使用 Lambda 表达式编写递归二:推断 FIX、g 的类型
2013-04-09 20:41
453 查看
![](http://images.cnblogs.com/cnblogs_com/ldp615/469308/o_Stars.gif)
《Stars》 作者:埃舍尔 本系列文章目录:
一:前言及基础
二:推断 FIX、g 的类型
三:实现 Y 组合子
四:实现 Θ 组合子
五:推导装配脑袋的 Fix
上一篇文章介绍的 λ 演算是无类型的,对于 FIX、g 我们只知道:它们都是有独个参数的函数,它们的参数本身也是一个只有单一参数的函数;同时,它们值是又一个只有单一参数的函数。
基于这种描述,是无法将 FIX、g 转化为 c# 代码的,我们需要推断出 FIX、g 类型。
我们先做一些假定,基于假定进行推导,得出结论再抽象为通用类型。
递归参数及返回值类型假定
对于常见的递归函数,如:阶乘、斐波那契数列求值,我们先作如下假定:参数为 int 类型(Int32);
返回值为 long 类型(Int64)。
基于假推断各类型
FIX g 类型
根据上篇文章中的描述:1 2 | FIX g = λn. (ISZERO n) 1 (MULT n ((FIX g) (PRED n))) FIX g 5 = 5 * (4 * (3 * (2 * (1 * 1))) = 120 |
接收一个 int 参数(上面假定第 1 条)值为 5
返回一个 long 型数值(上面假定第 2 条)120。
因此,确定出 FIX g 的类型可表示为 Func<int, long>。
同时也能看出 n 是递归函数的参数,n 类型为 int。
g 类型
阶乘单步函数如下:1 | g = λf. λn. (ISZERO n) 1 (MULT n (f (PRED n))) |
先来推断 f 的类型:
f 的参数:f 接收 n – 1 作为参数,因此,f 参数的类型和 n – 1 类型相同,即 n 的类型:int;
[align=left]f 的返回值:为 0 时返回 1,否则返回 n * f(n-1),f 的返回值类型也就是整个递归函数的返回值类型,即 long。[/align]
可确定 f 类型为 Func<int, long>。
n => n == 0 ? 1 : n * f(n – 1) 是传入一个 int 返回一个 long,其类型 Func<int, long>。
先来变换下 g 的表示形式:
1 2 3 4 5 | var g = (Func<int, long> f) => { Func<int, long> t = n => n == 0 ? 1 : n * f(n - 1); return t; }; // 示意代码 |
g 的类型为 Func<Func<int, long>, Func<int, long>>
FIX 类型
FIX g 可写作 FIX(g),可以看出: FIX g 的类型 == FIX(g) 的类型 == FIX 返回值的类型。前面得知 FIX g 类型为 Func<int, long>,也就可推出 FIX 返回值类型为 Func<int, long>。FIX 接受 g 作为参数,FIX 的参数类型也就是 g 的类型,可知 FIX 参数类型为 Func<Func<int, long>, Func<int, long>>。
由此得出 FIX 的类型为:Func<Func<Func<int, long>, Func<int, long>>, Func<int, long>>。
(估计这是多数开发人员见过的最复杂的泛型了。后面还在更复杂的吆!)
小结
名称 | λ 演算表达式 | 数据类型 |
输入参数 | n | int |
迭归返回值 | FIX g n | long |
迭归函数 | FIX g | Func<int, long> |
单步函数 | g | Func<Func<int, long>, Func<int, long>> |
不动点组合子 | FIX | Func<Func<Func<int, long>, Func<int, long>>, Func<int, long>> |
通用类型
基于以上部分的推演和小结,我们可以归纳出通用类型:名称 | λ 演算表达式 | 数据类型 |
输入参数 | n | TInput |
迭归返回值 | FIX g n | TResult |
迭归函数 | FIX g | Func<TInput, TResult> |
单步函数 | g | Func<Func<TInput, TResult>, Func<TInput, TResult>> |
不动点组合子 | FIX | Func<Func<Func<TInput, TResult>, Func<TInput, TResult>>, Func<TInput, TResult>> |
基于本文推断出的类型,不动点组合子转换为 c# 代码了不容易多了。下一篇文章 将以 Y 组合子为例进行说明。
相关文章推荐
- 使用 Lambda 表达式编写递归五:推导装配脑袋的 Fix
- 使用 Lambda 表达式编写递归四:实现 Θ 组合子
- 使用 Lambda 表达式编写递归一:前言及基础
- 使用 Lambda 表达式编写递归三:实现 Y 组合子
- Lambda表达式类型推断
- 编写高质量代码改善C#程序的157个建议——建议37:使用Lambda表达式代替方法和匿名方法
- Lambda 表达式编写递归
- Lambda表达式--使用方法语法的复杂查询: join (在单个 LINQ to Entities 查询中的两个结构上不兼容的初始化过程中出现类型)
- C# 函数式编程 —— 使用 Lambda 表达式编写递归函数
- 不使用任何变量编写是strlen函数(递归)
- lambda表达式的使用
- Java中Lambda表达式的使用
- 编写高质量代码改善C#程序的157个建议[为泛型指定初始值、使用委托声明、使用Lambda替代方法和匿名方法]
- Python中Lambda表达式使用
- python之lambda表达式 : 对于python中max函数的key参数的理解与使用
- Lambda 表达式的深化及使用
- 如何在AS中使用lambda表达式
- 泛型、函数式接口基础复习以及Lambda表达式、Optional的使用
- 编写高质量代码改善C#程序的157个建议——建议26:使用匿名类型存储LINQ查询结果
- 使用Spring Boot构建任务计划与cron表达式编写