Lambda returning another lambda
Asked Answered
B

4

11

is there any way how to return lambda from another lambda recursively?

All I want to do is finite state machine, implemented as lambda, which returns lambda implementing another state (or null).

nesting Func<> won't work as I want.

C#, .NET 3.5

Example:

machine, 3 states, pseudolanguage

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();
    }
}

I know, that I can workaround this using enum+switch, for example, but I'm just curious if I can do this.

Brainbrainard answered 15/5, 2010 at 14:21 Comment(5)
I'm confused by the "recursively" attribute of this question; can you give an example of this behaviour? Is the lambda actually supposed to return itself?Combat
It's not really clear how exactly you would like this to work. Can you give a pseudocode example, or a detailed explanation?Aramen
I am confused by the update. There are no lambda expressions anywhere in this code. What exactly do you mean by the word "lambda"? I mean a lambda expression.Forint
I figured it out. You mean "delegate" when you say "lambda". I've updated my answer.Forint
This is a good idea, but you're way better using a functional language for this.Alaric
H
13

I believe you can declare a delegate type: public delegate Lambda Lambda() which returns a delegate of its own type. It does compile, anyway.

Homs answered 15/5, 2010 at 14:31 Comment(1)
My question was maybe little confusing, but this exactly solves my problem, thanks. :-)Brainbrainard
F
26

Sure, you can return a lambda from another lambda:

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

What aspect of the syntax are you having trouble with? I am interested to know how people get this sort of thing wrong because that helps us design the language and documentation better next time.

UPDATE:

well, but you cannot return lambda returning lambda

Sure you can.

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

Here we are returning a lambda that returns a lambda. Why do you believe this is impossible?

UPDATE:

Aha, I understand. You believe that the word "lambda" means "delegate". It does not. A lambda is a kind of expression that is convertible to a delegate.

If you want a delegate that returns a delegate then just declare that. That's perfectly legal. For example, here's a delegate called a "combinator" -- a combinator is a delegate which takes itself and returns itself:

delegate D D(D d);

That's a delegate named D which takes a D and returns a D.

You can make a lambda expression that is compatible with this delegate type. For example:

D I = x=>x;

is the Identity combinator. Or

D M = x=>x(x);

is the Mockingbird combinator in Raymond Smullyan's whimsical characterization of combinators.

As you correctly note, there's no way to make a generic Func that is this kind of combinator. I wrote an article about this fact back in 2006:

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

Forint answered 15/5, 2010 at 14:30 Comment(2)
well, but you cannot return lambda returning lambda ... (-> see my edit)Brainbrainard
I find that a lot of people confuse "lambda" and "delegate". This is compounded by common usage: "so we return this lambda..." or "pass a lambda like this" when we're actually returning/passing a delegate constructed from a lambda expression.Homs
H
13

I believe you can declare a delegate type: public delegate Lambda Lambda() which returns a delegate of its own type. It does compile, anyway.

Homs answered 15/5, 2010 at 14:31 Comment(1)
My question was maybe little confusing, but this exactly solves my problem, thanks. :-)Brainbrainard
K
3

Your question is already answered, but those reading this may be interested to note that you can use this technique to embed the Lambda calculus in C#.

First starting with:

    public delegate Lambda Lambda(Lambda x);

Using various function definitions found at http://en.wikipedia.org/wiki/Lambda_calculus I defined various primitives as follows:

    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);

For various tests and the whole code see: http://code.google.com/p/jigsaw-library/source/browse/trunk/Theory/EmbeddedLambdaCalculus.cs

Kidd answered 19/9, 2011 at 1:45 Comment(0)
M
1

You can have a method which builds and returns an expression tree:

public Expression GetExpression()
{

}

Also building expression trees in .NET 4.0 has been greatly enhanced.

Metritis answered 15/5, 2010 at 14:24 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.