Лямбда, возвращающая другую лямбду - PullRequest
9 голосов
/ 15 мая 2010

есть ли способ как рекурсивно вернуть лямбду из другой лямбды?

Все, что я хочу сделать, - это конечный автомат, реализованный как лямбда, который возвращает лямбду, реализующую другое состояние (или ноль).

Вложение Func <> не будет работать так, как я хочу.

C #, .NET 3.5

Пример:

автомат, 3 состояния, псевдоязык

private Lambda State1()
{  
    if (SomeConditionIsMet)
        return State2;
    else
        return State1;
}

private Lambda State2()
{  
    while (SomeConditionIsMet)
        return State2;
    else
        return State3;
}

private Lambda State3()
{  
    LogEnd();
    return NULL;
}

public void FSM()
{
    Lambda _currentState = State1;

    while(_currentState != NULL)
    {
        _currentState = _currentState();
    }
}

Я знаю, что я могу обойти это, используя, например, enum + switch, но мне просто любопытно, могу ли я это сделать.

Ответы [ 4 ]

23 голосов
/ 15 мая 2010

Конечно, вы можете вернуть лямбду из другой лямбды:

Func<int, Func<int, int>> makeAdder = x => y => x + y;
Func<int, int> addTen = makeAdder(10);
Console.WriteLine(addTen(20)); // 30

С каким аспектом синтаксиса у вас возникают проблемы? Мне интересно знать, как люди неправильно понимают подобные вещи, потому что в следующий раз это поможет нам лучше разработать язык и документацию.

UPDATE:

хорошо, но вы не можете вернуть лямбду, возвращая лямбду

Конечно, вы можете.

Func<int, Func<int, int>> GetAdderMaker()
{
    return x => y => x + y;
}

Здесь мы возвращаем лямбду, которая возвращает лямбду. Почему вы считаете, что это невозможно?

UPDATE:

Ага, я понимаю. Вы верите, что слово «лямбда» означает «делегат». Это не. Лямбда - это своего рода выражение, которое можно преобразовать в делегат.

Если вам нужен делегат, который возвращает делегата, просто объявите это. Это совершенно законно. Например, вот делегат под названием «комбинатор» - комбинатор - это делегат, который берет себя и возвращает себя:

delegate D D(D d);

Это делегат по имени D, который принимает D и возвращает D.

Вы можете создать лямбда-выражение , совместимое с этим типом делегата . Например:

D I = x=>x;

- комбинатор идентификации. Или

D M = x=>x(x);

- комбинатор пересмешника в причудливой характеристике комбинаторов Раймонда Смулляна.

Как вы правильно заметили, нет никакого способа создать универсальный Func, который является этим типом комбинатора. Я написал статью об этом факте еще в 2006 году:

http://blogs.msdn.com/ericlippert/archive/2006/06/23/standard-generic-delegate-types-part-two.aspx

13 голосов
/ 15 мая 2010

Я полагаю, что вы можете объявить тип делегата: public delegate Lambda Lambda(), который возвращает делегата своего собственного типа.Это все равно компилируется.

2 голосов
/ 19 сентября 2011

На ваш вопрос уже дан ответ, но тем, кто его читает, может быть интересно отметить, что вы можете использовать эту технику для встраивания лямбда-исчисления в C #.

Первый начинается с:

    public delegate Lambda Lambda(Lambda x);

Используя различные определения функций, найденные в http://en.wikipedia.org/wiki/Lambda_calculus Я определил различные примитивы следующим образом:

    public static Lambda Id         = x => x;
    public static Lambda Zero       = f => x => x;
    public static Lambda True       = x => y => x;
    public static Lambda False      = x => y => y;
    public static Lambda One        = f => x => f(x);
    public static Lambda Two        = f => x => f(f(x));
    public static Lambda Succ       = n => f => x => f(n(f)(x));
    public static Lambda Three      = Succ(Two);
    public static Lambda Pred       = n => f => x => n(g => h => h(g(f)))(u => x)(Id);
    public static Lambda Plus       = m => n => f => x => m(f)(n(f)(x));
    public static Lambda Sub        = m => n => n (Pred) (m);
    public static Lambda And        = p => q => p(q)(p);
    public static Lambda Or         = p => q => p(p)(q);
    public static Lambda Not        = p => a => b => p(b)(a);
    public static Lambda IfThenElse = p => a => b => p(a)(b);
    public static Lambda IsZero     = n => n(x => False)(True);
    public static Lambda IsLtEqOne  = n => IsZero(Pred(n));
    public static Lambda Pair       = x => y => f => f(x)(y);
    public static Lambda First      = pair => pair(True);
    public static Lambda Second     = pair => pair(False);
    public static Lambda Nil        = x => True;
    public static Lambda Null       = p => p(x => y => False);
    public static Lambda LtEq       = x => y => IsZero(Sub(x)(y));
    public static Lambda Gt         = x => y => LtEq(y)(x);
    public static Lambda Eq         = x => y => And(LtEq(x)(y))(LtEq(y)(x));
    public static Lambda M          = x => x(x);

Для различных тестов и всего кода см .: http://code.google.com/p/jigsaw-library/source/browse/trunk/Theory/EmbeddedLambdaCalculus.cs

1 голос
/ 15 мая 2010

У вас может быть метод, который создает и возвращает дерево выражений :

public Expression GetExpression()
{

}

Также значительно улучшено построение деревьев выражений в .NET 4.0 .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...