![](http://images.cnblogs.com/cnblogs_com/ldp615/469308/o_Fish%20and%20Scales.gif)
《Fish and Scales》 作者:埃舍尔
本系列文章目录:一:前言及基础二:推断 FIX、g 的类型三:实现 Y 组合子四:实现 Θ 组合子五:推导装配脑袋的 Fix 上一篇文章 我们实现 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)
|
则:
实现 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
| 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);
}
|
便是
装配脑袋 给出的写法。
下一篇文章 中将说明这个是如何编导出的。