Howto: "letrec" в C# (вызов лямбда-выражения в его определении)

Рассмотрим функцию факториала, определенную в теле метода как лямбда-выражение и присвоенную переменной:

Func<int, int> factfail = n =>
{
    if (n == 0)
        return 1;
    else
        return n * factfail(n-1);
};

Это не удается, так как factfail еще не связан локальной переменной.

Есть ли способ добавить своего рода точку фиксации - путем абстрагирования самой функции?!

Func<Func<int, int>, int, int> fact_ = (fact, n) => 
{  
    if (n == 0) 
        return 1;
    else 
        return n * fact(n-1); 
};

fact_(??);

Длинная история: мне нужно написать рекурсивную функцию, у которой есть побочный эффект изменения некоторого внешнего состояния. Поэтому я пытаюсь написать этот метод как лямбда-выражение, которое фиксирует это внешнее состояние.

Я все еще экспериментирую с разными стилями, как написать это и - помимо этого одного словаря, который должен быть одинаковым для всех рекурсивных вызовов - я хочу быть настолько функциональным и ленивым, насколько это возможно.

Так что я играл с LINQ, так как это помогает мне сократить взаимные данные. Это также помогает понять, какие части кода могут быть выражены в функциональном стиле.

Чтобы быть кратким в операторе LINQ, полезно иметь возможность определять некоторые вспомогательные функции перед ними, и я сделал это, связав лямбда-выражения с переменными.

И с помощью выражения lamda я также могу захватить свой словарь без необходимости явно передавать его ссылку на метод, что довольно приятно.

не уверен, что я на правильном пути, хотя...

1 ответ

Решение

Вы можете найти больше информации о рекурсивных лямбда-выражениях в этом сообщении в блоге Mads Torgersen. Он показывает, как определить обычный комбинатор с фиксированной точкой. Он использует факториальную функцию в качестве примера, поэтому вы можете найти там точный пример:-).

Однако на практике вы можете просто определить местный Func<..> переменная, а затем изменить его. Если вы хотите дать имя делегату, то он работает просто отлично (он немного грязный, но простой):

Func<int, int> fact = null;
fact = (n) => (n == 0) ? 1 : n * fact(n-1);

Это работает, потому что замыкание захватывает ссылку на fact переменная, поэтому, когда вы на самом деле вызываете ее (во время рекурсивного вызова), значение не null больше, но ссылается на делегата.

Другие вопросы по тегам