Метапрограммирование в немерле на высоте, но пока только в компайл тайме. Это конечно более эффективно, но и требует большего скачка для перехода. Предлагаю сделать удобным метапрограммирование в рантайме, для тех, кто хочет его использовать, но не хочет вникать в сложности компилятора.
Сначала код:
Main()
{
F(1, x => x + 1); // компиляция выражений конструктор дерева вместо кода
F(1, x => x * 10);
}
F(val : int, expr : Expr[int -> int]) : int
{
match (expr)
{
| <[ (x) => x + $y ]> => WriteLine($"x + $y expression") // PM по дереву выражений
| x => WriteLine("other expression $x");
}
def lambda = expr.Compile(); // компиляция выражения в код
lambda(val);
}
Дополнительно можно сделать макрос, который умеет создавать перегруженную функцию для того, чтобы такие методы можно было использовать из C#:
F(val : int, expression : System.Linq.Expressions.Expression[int -> int]) : int
{
def expr = expression.ToExpr(); // преобразование Expression из фреймворка в наш аст для квазицитирования и PM
F(val, expr)
}
Что требуется от компилятора для реализации этой фичи (все это уже есть, но в несколько других сценаоиях):
0. Умение создавать AST вместо кода в зависимости от типа аргумента. (реализовано в linq)
1. типизированный expression AST (реализовано, но я не знаю насколько подойдет)
2. квазицитирование и PM по нему (не реализовано, тут будут основные сложности)
3. компиляция expresison в рантайме (не реализовано, но требуется всего лишь поднять компилятор и пропустить фазу парсера и типизации, дав уже типизированный код)
Дополнительные юзкейсы:
def expr = fun(x) { x + 1 } : Expr; // вывод типов позволяет не указывать тип дженерика
def expr = try {
any(valid(expression))
} finally {
allowed(here)
} : Expr; // используются любые выражения, не только лямбды это будет Expr[void -> _]
def otherExpr = <[
repeat (10)
$expr
]> : Expr; // можно конструировать их по месту
Главный поинт: Это сильно проще и привычнее. Для использования метапрограммирования (пусть и в рантайме), не требуется весь проект переводить на nemerle, достаточно на нем написать именно задачу требующую МП. Мне все чаще приходится метапрограммировать через expression tree, это АДЪ. Такая прослойка могла бы мне помочь с легким сердцем использовать nemerle для создания одной сборки внутри проекта. Я бы мог писать простой и понятный код анализа и обработки и конструирования C# expressions на nemerle, но это все оставалось бы внутри одной сборки и снаружи использовалось бы точно так же как тот код, который пишу сейчас я.
Основная проблема сложных макросов (типизация и раличные фазы) тут не стоит, все работает уже с типизированным AST.
К сожалению, "снаружи" сделать это не получится. Требуется поддержка именно компилятора.