2013-08-17 42 views
4

我在Visual Studio中擺弄周圍,我發現是否有用於委託類型返回與它自己相同類型的委託?

delegate RecursiveDelegate RecursiveDelegate(); 

是一個有效的委託定義。

我沒有很多函數式編程經驗,但我想知道這個模式在函數式編程中是否真正有用,或者它只是對語義的好奇。我想以兩種方式提出這個問題:

  1. 在有副作用的情況下。我可以看到這實際上是一種中等程度的方式來模擬功能性語言中的迭代學習算法,其中算法的實際任務是作爲副作用執行的,新版本的函數是返回值。這是否完成?
  2. 在沒有副作用的情況下。我認爲這在原則上是無用的,但如果我錯了,我會非常好奇。如果我們假設RecursiveDelegate()的實現沒有副作用,這可能會有用嗎?
+0

在CLR中,委託是具有'Invoke'方法(帶有一些額外的元數據,但是它的核心)的對象。如果你這麼想的話,它的工作原理並不奇怪。它並不比在方法中返回自身的對象更爲怪異。 – zneak

+2

@zneak - 我不認爲這個問題是關於它爲什麼起作用的(有些合理,因爲函數可以返回它想要的任何類型),而是如何/如果它對於函數式編程有用。 –

+1

當然。這就是爲什麼我沒有發佈答案。我正在解決表達的最初驚喜。 – zneak

回答

1

我有一些類似的代碼,不完全是一個遞歸委託的例子,但它接近。一個「Y-Combinator」接近了 - 坦率地說,我不知道它在實踐中是如何工作的,但它被用來定義遞歸函數。

這裏有您需要定義時髦代碼:

public delegate T S<T>(S<T> s); 

public static T U<T>(S<T> s) 
{ 
    return s(s); 
} 

public static Func<A, Z> Y<A, Z>(Func<Func<A, Z>, Func<A, Z>> f) 
{ 
    return U<Func<A, Z>>(r => a => f(U(r))(a)); 
} 

現在你可以在一行定義遞歸函數。

階乘:

var fact = Y<int, int>(_ => x => x == 0 ? 1 : x * _(x - 1)); 
var fact5 = fact(5); // == 120 
var fact6 = fact(6); // == 720 
var fact7 = fact(7); // == 5040 

斐波那契數:

var fibo = Y<int, int>(_ => x => x <= 1 ? 1 : _(x - 1) + _(x - 2)); 
var fibo5 = fibo(5); // == 8 
var fibo6 = fibo(6); // == 13 
var fibo7 = fibo(7); // == 21 

我的代碼最喜歡的行是調用s(s)。說真的,如果任何人都能夠理清頭腦,他們就是天才!更不用說整個U<Func<A, Z>>(r => a => f(U(r))(a))