2010-05-15 82 views
9

有什麼辦法如何從另一個lambda遞歸返回lambda?Lambda返回另一個lambda

所有我想要做的是有限狀態機,實現爲lambda,它返回實現另一個狀態(或null)的lambda。

嵌套功能<>將無法正常工作。

C#,.NET 3.5

實施例:

機,3個狀態,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(); 
    } 
} 

我知道,我可以解決此使用枚舉+開關,例如,但我我只是好奇,如果我能做到這一點。

+0

我被這個問題的「遞歸」屬性所困惑;你能舉出這種行爲的例子嗎? lambda實際上是否應該返回*本身*? – Aaronaught 2010-05-15 14:24:58

+0

目前尚不清楚您希望如何工作。你可以給一個僞代碼的例子,或一個詳細的解釋? – Joren 2010-05-15 14:27:10

+0

我很困惑的更新。這段代碼中沒有任何lambda表達式。 「lambda」是什麼意思?我的意思是*一個lambda表達式*。 – 2010-05-15 15:03:10

回答

13

我相信你可以聲明委託類型:public delegate Lambda Lambda()返回了自己的類型的委託。無論如何它都會編譯。

+0

據我所見,這工作正常。 – Joren 2010-05-15 14:36:56

+0

我的問題可能有點混亂,但這完全解決了我的問題,謝謝。 :-) – nothrow 2010-05-15 14:38:11

23

當然,你可以從另一個lambda返回拉姆達:

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

這裏我們返回一個返回lambda的lambda。你爲什麼認爲這是不可能的?

更新:

啊哈,我明白了。你相信「lambda」這個詞的意思是「委託」。它不是。 lambda是一種可轉換爲委託的表達式。

如果你想要一個委託返回一個委託,那麼就聲明這一點。這是完全合法的。例如,這裏有一個被稱爲「組合子」委託 - 一個組合子是一個委託這需要本身並返回自己:

delegate D D(D d); 

這是一個代表名爲d,這需要d和返回D.

您可以製作一個拉姆達表達式,它與此委託類型兼容。例如:

D I = x=>x; 

是身份組合子。或

D M = x=>x(x); 

是Raymond Smullyan對組合子的異想天開表徵中的模仿鳥組合。

正如您正確指出的那樣,沒有辦法使這種類型的combinator是一個通用的Func。我在2006年寫了一篇關於這個事實回來:

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

+0

不錯,但你不能返回lambda返回的lambda ...( - >看我的編輯) – nothrow 2010-05-15 14:32:30

+1

我發現很多人混淆了「lambda」和「delegate」。當我們實際返回/傳遞由lambda表達式構造的委託時,通常會使用這個常見用法:「所以我們返回這個lambda ...」或「傳遞這樣的lambda」。 – 2010-05-15 15:18:34

2

您的問題已經得到解答,但是讀者可能會注意到您可以使用這種技術將Lambda微積分嵌入到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