如何将SICP中基于函数的Scheme(Lisp) cons/car转换为C#
用C#实现SICP中的函数式cons和car
在《计算机程序的构造和解释》(SICP)中,作者用纯函数封装的方式重写了构造整数对的cons和提取首元素的car,对应的Lisp代码如下:
(define (cons x y) (lambda (m) (m x y))) (define (car z) (z (lambda (p q) p)))
这段代码的核心逻辑是:cons返回一个等待接收双参处理函数的函数,它会把内部封装的两个值传给这个处理函数,最终返回处理结果;而car则是给这个返回的函数传入一个"只返回第一个参数"的处理函数,从而拿到整数对的首元素。
作为C#开发者,要实现这个逻辑,关键是搞对Cons方法的返回类型:它不是Func<int, int, int>(这是处理函数的类型),而是接收一个双参处理函数、返回该函数执行结果的函数,也就是Func<Func<int, int, int>, int>。
针对整数的实现
直接对应SICP逻辑的C#代码如下:
// 构造函数:返回一个接收处理函数的函数 static Func<Func<int, int, int>, int> Cons(int x, int y) { return processFunc => processFunc(x, y); } // 提取首元素:传入"取第一个参数"的处理函数 static int Car(Func<Func<int, int, int>, int> pair) { return pair((first, second) => first); } // 调用示例 var myPair = Cons(10, 20); Console.WriteLine(Car(myPair)); // 输出 10
泛型通用版
如果想摆脱整数的限制,实现更通用的版本,可以用C#泛型:
// 通用构造函数,支持任意类型的参数和返回值 static Func<Func<T1, T2, R>, R> Cons<T1, T2, R>(T1 x, T2 y) { return processFunc => processFunc(x, y); } // 通用首元素提取函数 static T1 Car<T1, T2>(Func<Func<T1, T2, T1>, T1> pair) { return pair((first, second) => first); } // 调用示例 var stringPair = Cons("Hello", "World"); Console.WriteLine(Car(stringPair)); // 输出 Hello
关键说明
你之前的困惑在于混淆了"处理函数的类型"和"cons返回的函数类型":
cons内部的m是处理函数,类型是Func<int, int, int>(输入两个int,输出int)- 而
cons本身返回的是接收这个处理函数并执行它的函数,所以类型是Func<Func<int, int, int>, int>
只要理清这层嵌套关系,就能写出可编译的代码了。
内容的提问来源于stack exchange,提问作者Avrohom Yisroel
相关产品推荐
相关产品推荐

