在从SICP学习了一点Scheme之后,我开始阅读The Little Schemer(我发现它非常有趣)并且大约完成了四分之一。我注意到我可以在不使用lambda的情况下编写许多(大多数?全部?)解决方案,而Little Schemer 总是使用它们。例如,第一个定义是
(define atom?
(lambda (x)
(and (not (pair? x)) (not (null? x)))))
除非我弄错了,否则可以更简单地写成
(define (atom? x)
(and (not (pair? x)) (not (null? x))))
如果我写一些没有lambda的解决方案,我是否遗漏了一些基本的东西?
答案 0 :(得分:22)
我非常喜欢lambda
- 重教学风格,因为它使函数创作更加明确,正如杰伊所说。
在学习时,您在atom?
开始的简单功能在顶层是define
d。这意味着使用您提到的defun
- 样式define
来创建函数是可能的,甚至更紧凑。
然而,当你开始使用函数作为第一类值时,例如,作为map
的参数,你将第一次看到lambda
,它看起来更奇怪,更多比实际上更神奇。
相反,如果你一直用lambda
定义你的函数,那么看起来函数就像任何其他值一样,这不是一个飞跃。它们碰巧经常位于define
的右侧,但与数字或引用的常数没有区别:
(define x 1)
(define l '(2 3 4 5))
(define s (cons x ls))
(define f (lambda (n) (+ n 2)))
当然,该语言支持这两种形式,因此最终归结为风格。对我来说,当使用define
创建所有函数时,lambda
的使用具有吸引人的一致性:第一个参数始终是符号,第二个参数只是任何旧表达式。事实上lambda
就像任何旧表达式一样,是任何函数式程序员学习的最重要的事情之一。
答案 1 :(得分:14)
最初,define
只有一个语法,可以将变量设置为一个值。这就是这些古老(和永恒)书籍中使用的风格。稍后,define
会使用不同的语法作为您正在使用的快捷方式。
只是为了好玩,搜索您的Scheme库,您可能会发现一个宏将非lambda表单扩展为旧的lambda表单。
答案 2 :(得分:8)
您可以看到您的Scheme将这些快捷方式(宏)扩展为使用expand
(如果支持):
mzscheme 4.2.4(与DrScheme合作):
> (expand '(define (add1 x) (+ 1 x)))
#<syntax (define-values (add1) (lambda...>
(define-values
(add1)
(lambda (x) (apply + '1 x)))
Chez Scheme 8.0:
> (expand '(define (add1 x) (+ 1 x)))
(begin
(set! add1
(lambda (x)
(+ 1 x)))
(void))
lambda
显示为白天。
答案 3 :(得分:4)
我依旧记得一位教授在讨论这样的事情。
我认为使用lambda解决方案有两个原因:
第一个纯粹是一个历史性的东西。在某个时间点,这是唯一可行的方式。所以有些人仍然使用这种方法。
第二,有些人只是想更明确地创建一个函数,所以他们喜欢看到lambda这个词。
所以我相信这个选择取决于你个人最喜欢的。
答案 4 :(得分:2)
我正在阅读有关lambda演算的一些内容(阅读Simon Peyton Jones的“函数式编程语言的实现”;在线使用免费的pdf),因为我使用的是TLS。所以这只是猜测,但我相信TLS的作者希望你在思考中真的很重要。他们没有出来说出来,但有一些提示(查看TLS第107页),这只是应用lambda calc的练习。所以也许他们不说,“你正在做lambda抽象,我的朋友!”
答案 5 :(得分:1)
Little Schemer使用伪代码方案(为了教育目的而进行简化并且与实现无关)。今天的标准Scheme有一个define的定义,你在其中隐式调用lambda(参见http://www.cs.cmu.edu/Groups/AI/html/r4rs/r4rs_7.html)。 Little Schemer方案非常简单,不包括这种替代形式。