2010-05-15 22 views
9

¿Hay alguna forma de cómo devolver lambda de otra lambda recursivamente?Lambda que devuelve otra lambda

Todo lo que quiero hacer es una máquina de estados finitos, implementada como lambda, que devuelve lambda implementando otro estado (o nulo).

nesting Func <> no funcionará como yo quiera.

C#, .NET 3.5

Ejemplo:

máquina, 3 estados, 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(); 
    } 
} 

sé, que puedo solucionar este usando enum + interruptor, por ejemplo, pero Solo tengo curiosidad si puedo hacer esto.

+0

I Estoy confundido por el atributo "recursivo" de esta pregunta; ¿Puedes dar un ejemplo de este comportamiento? ¿Se supone que la lambda debe regresar * en sí misma? – Aaronaught

+0

No está muy claro cómo exactamente le gustaría que esto funcione. ¿Puedes dar un ejemplo de pseudocódigo o una explicación detallada? – Joren

+0

Estoy confundido por la actualización. No hay expresiones lambda en ningún lado en este código. ¿Qué quieres decir exactamente con la palabra "lambda"? Quiero decir * una expresión lambda *. –

Respuesta

13

Creo que se puede declarar un tipo de delegado: public delegate Lambda Lambda() que devuelve un delegado de su propio tipo. Sí compila, de todos modos.

+0

Por lo que puedo ver, esto funciona bien. – Joren

+0

Mi pregunta fue tal vez poco confusa, pero esto resuelve exactamente mi problema, gracias. :-) – nothrow

23

Sin duda, puede devolver un lambda de otro lambda:

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

¿Qué aspecto de la sintaxis que está teniendo problemas con? Estoy interesado en saber cómo la gente hace este tipo de cosas mal porque eso nos ayuda a diseñar mejor el lenguaje y la documentación la próxima vez.

ACTUALIZACIÓN:

bien, pero no se puede volver lambda lambda regresar

Claro que puedes.

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

Aquí están volviendo un lambda que devuelve un lambda. ¿Por qué crees que esto es imposible?

ACTUALIZACIÓN:

Aha, entiendo. Usted cree que la palabra "lambda" significa "delegado". No es asi. Un lambda es un tipo de expresión que se puede convertir en un delegado.

Si desea un delegado que devuelve un delegado, solo tiene que declararlo. Eso es perfectamente legal. Por ejemplo, aquí hay un delegado pidió un "combinador" - un combinador es un delegado que tiene en sí y en sí retornos:

delegate D D(D d); 

Eso es un D nombrado delegado que tiene un D y devuelve una D.

Puede hacer una expresión lambda que sea compatible con este delegado tipo. Por ejemplo:

D I = x=>x; 

es el combinador de identidad.O

D M = x=>x(x); 

es el combinador Mockingbird en la caracterización caprichosa de Raymond Smullyan de combinadores.

Como nota correctamente, no hay forma de hacer un Func genérico que sea este tipo de combinador. Escribí un artículo sobre este hecho en 2006:

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

+0

bien, pero no se puede devolver lambda devolviendo lambda ... (-> ver mi edición) – nothrow

+1

Me parece que mucha gente confunde "lambda" y "delegar". Esto se ve agravado por el uso común: "así que devolvemos este lambda ..." o "pasamos un lambda como este" cuando en realidad estamos regresando/pasando un delegado construido a partir de una expresión lambda. –

2

Su pregunta ya ha sido respondida, pero aquellos que lean esto pueden estar interesados ​​en saber que puede utilizar esta técnica para incrustar el cálculo Lambda en C#.

primer lugar a partir de:

public delegate Lambda Lambda(Lambda x); 

Utilizando diversas definiciones de funciones que se encuentran en http://en.wikipedia.org/wiki/Lambda_calculus he definido varias primitivas como sigue:

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

Por diversas pruebas y todo el código, véase: http://code.google.com/p/jigsaw-library/source/browse/trunk/Theory/EmbeddedLambdaCalculus.cs