
本系列文章目錄:
上一篇文章 我們實現 Y 組合子,這篇文章討論 Θ 組合子的實現。(Θ 讀 Theta,希臘語第八個字母,小寫為 θ。)
繼續使用前文中的類型假定,假定遞歸函數:
- 參數為 int;
- 返回值為 long。
Θ 組合子
Θ 組合子也是一個常見不動點組合子,由 阿蘭·圖靈 發現,也稱為圖靈不動點組合子:
1 |
Θ = (λx.λy.(y(x x y))) (λx.λy.(y(x x y))) |
傳值調用形式為((x x y) η-展開為 λz. x x y z):
1 |
Θv = (λx.λy.(y(λz. x x y z))) (λx.λy.(y(λz. x x y z))) |
不過我還是喜歡把 y (x x y) η-展開為: λn.(y (x x y) n),得出:
1 |
Θ = (λx.λy.λn.(y(x x y) n)) (λx.λy.λn.(y(x x y) n)) |
定義一個中間變量 h,令:
1 |
h = λx.λy.λn.(y(x x y)n) |
則:
1 |
Θ = h h Θ = h(h) |
實現 h
確定 h 的類型
根據前文的推斷,Θ 的類型為 Func<Func<Func<int, long>, Func<int, long>>, Func<int, long>> , 這也是 h 返回值的類型。
h 可調用自身 h(h),需要用到 上一篇文章 用的 SelfApplicable<TResult>委托:
1 |
delgate TResult SelfApplicable<TResult>(SelfApplicable<TResult> self); |
h 的類型為:SelfApplicable<Func<Func<Func<int, long>, Func<int, long>>, Func<int, long>>>。
實現 h
對 h 作一步簡單變換:
1 2 |
h = λx.λy.λn.(y(x x y)n) h = λx.λy.λn.(y(x(x)(y))(n) |
使用本系列第一篇文章總結出的規律,可寫出:
1 |
SelfApplicable<Func<Func<Func<int, long>, Func<int, long>>, Func<int, long>>> h = x => y => n => y(x(x)(y))(n); |
實現 Θ
根據 Θ 的簡單式:
1 |
Θ = h(h) |
可寫出:
1 |
Func<Func<Func<int, long>, Func<int, long>>, Func<int, long>> Θ = h(h); |
與 h 的代碼放在一塊:
1 2 |
SelfApplicable<Func<Func<Func<int, long>, Func<int, long>>, Func<int, long>>> h = x => y => n => y(x(x)(y))(n); Func<Func<Func<int, long>, Func<int, long>>, Func<int, long>> Θ = h(h); |
還記得 上一篇文章 最后給出的代嗎?(出處:http://blogs.msdn.com/b/madst/archive/2007/05/11/recursive-lambda-expressions.aspx)
比較下,看看是不是一回事的。
調用下試試:
1 2 |
var factorial = Θ(f => x => x == 0 ? 1 : x * f(x - 1)); var result = factorial(5); // 120 |
封裝 Θ
1 2 3 4 5 6 7 8 9 10 |
public class ThetaCombinator { public static Func<TInput, TResult> Fix<TInput, TResult>(Func<Func<TInput, TResult>, Func<TInput, TResult>> f) { return Theta<TInput, TResult>.Fix(f); } static class Theta<TInput, TResult> { delegate T SelfApplicable<T>(SelfApplicable<T> self); static readonly SelfApplicable<Func<Func<Func<TInput, TResult>, Func<TInput, TResult>>, Func<TInput, TResult>>> h = x => y => n => y(x(x)(y))(n); public static readonly Func<Func<Func<TInput, TResult>, Func<TInput, TResult>>, Func<TInput, TResult>> Fix = h(h); } } |
調用示例代碼:
1 2 3 4 5 |
var factorial = ThetaCombinator.Fix<int, int>(f => n => n == 0 ? 1 : n * f(n - 1)); var result1 = factorial(5); // 120 var fibonacci = ThetaCombinator.Fix<int, int>(f => n => n < 2 ? n : f(n - 1) + f(n - 2)); var result2 = fibonacci(5); // 5 |
后記
http://blogs.msdn.com/b/madst/archive/2007/05/11/recursive-lambda-expressions.aspx 文中也給出了下面一種簡單到極致的寫法:
1 2 3 |
Func<T, T> Fix<T>(Func<Func<T,T>, Func<T,T>> F) {
return t => F(Fix(F))(t);
} |
增加一個泛型參數並修改下參數的名稱,得出:
1 |
Func<T, TResult> Fix<T, TResult>(Func<Func<T,TResult>, Func<T,TResult>> f) {
return t => f(Fix(f))(t);
} |