使用Lambda表达式编写递归二

开发 后端
对于常见的递归函数,如:阶乘、斐波那契数列求值,我们先作如下假定:参数为 int 类型(Int32);返回值为 long 类型(Int64)。

上一篇文章介绍的 λ 演算是无类型的,对于 FIX、g 我们只知道:它们都是有独个参数的函数,它们的参数本身也是一个只有单一参数的函数;同时,它们值是又一个只有单一参数的函数。

基于这种描述,是无法将 FIX、g 转化为 c# 代码的,我们需要推断出 FIX、g 类型。

我们先做一些假定,基于假定进行推导,得出结论再抽象为通用类型。

递归参数及返回值类型假定

对于常见的递归函数,如:阶乘、斐波那契数列求值,我们先作如下假定:

1.参数为 int 类型(Int32);

2.返回值为 long 类型(Int64)。

基于假推断各类型

FIX g 类型

根据上篇文章中的描述:

  1. FIX g = λn. (ISZERO n) 1 (MULT n ((FIX g) (PRED n)))
  2. FIX g 55 = 5 * (4 * (3 * (2 * (1 * 1))) = 120 

FIX g 返回的是我们需要的递归函数,这个递归函数

·接收一个 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))) 

c# 中可表达为:g => f => n => n == 0 ? 1 : n * f(n – 1)

先来推断 f 的类型:

·f 的参数:f 接收 n – 1 作为参数,因此,f 参数的类型和 n – 1 类型相同,即 n 的类型:int;

·f 的返回值:为 0 时返回 1,否则返回 n * f(n-1),f 的返回值类型也就是整个递归函数的返回值类型,即 long。

可确定 f 类型为 Func<int, long>。

n => n == 0 ? 1 : n * f(n – 1) 是传入一个 int 返回一个 long,其类型 Func<int, long>。

先来变换下 g 的表示形式:

  1. var g = (Func<int, long> f) => {  
  2.     Func<int, long> t =   
  3.         n => n == 0 ? 1 : n * f(n - 1);  
  4.     return t;  
  5. };  // 示意代码 

从上面这段代码可以清楚到看出 g 接收一个 Func<int, long> 类型的参数 f,返回一个类型为 Func<int, long> 的委托,可得出:

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 组合子为例进行说明。

原文链接:http://www.cnblogs.com/ldp615/archive/2013/04/09/recursive-lambda-expressions-2.html

责任编辑:张伟 来源: 博客园
相关推荐

2009-08-31 17:11:37

Lambda表达式

2013-04-10 10:46:06

LambdaC#

2009-10-12 10:11:08

Lambda表达式编写

2009-08-10 09:41:07

.NET Lambda

2009-09-15 15:18:00

Linq Lambda

2009-09-09 13:01:33

LINQ Lambda

2022-12-05 09:31:51

接口lambda表达式

2009-09-11 09:48:27

Linq Lambda

2023-11-02 08:25:58

C++Lambda

2009-09-17 10:40:22

Linq Lambda

2009-09-15 17:30:00

Linq Lambda

2009-09-17 09:44:54

Linq Lambda

2009-08-27 09:44:59

C# Lambda表达

2012-06-26 10:03:58

JavaJava 8lambda

2009-04-29 09:05:59

Lambda抽象代表.NET

2023-09-25 13:28:14

C++Lambda

2024-03-25 13:46:12

C#Lambda编程

2009-09-09 17:14:17

Linq lambda

2013-04-07 15:44:26

Java8Lambda

2009-09-17 09:09:50

Lambda表达式Linq查询
点赞
收藏

51CTO技术栈公众号