Ixm*_*tus 43 lisp scheme continuations the-little-schemer racket
我和The Little Schemer一起工作,学习Scheme并在我的环境中使用PLT-Scheme.
Little Schemer对递归给了我很大的帮助(现在对我来说很简单)但是我仍然坚持介绍"收藏家"这本书的一部分,并将整个函数称为一个延续.
这是他们使用的示例代码.我理解递归元素但是我被卡住了,特别是在lambda函数上 - 我的思想不能遵循路径以及如何设置lambda函数的参数(因为他们唯一的调用是在递归中再次调用它们,有功能体内没有具体用途).
如果有人能够或多或少地通过将函数递归到lambda收集器来分解计算路径,那可能对我有所帮助.
;; Build a nested list of even numbers by removing the odd ones from its
;; argument and simultaneously multiply the even numbers and sum the odd
;; numbers that occur in its argument.
(define (even-only-collector l col)
(cond
((null? l)
(col (quote ()) 1 0))
((atom? (car l))
(cond
((even? (car l))
(even-only-collector (cdr l)
(lambda (newl p s)
(col (cons (car l) newl)
(* (car l) p) s))))
(else
(even-only-collector (cdr l)
(lambda (newl p s)
(col newl
p (+ (car l) s)))))))
(else
(even-only-collector (car l)
(lambda (al ap as)
(even-only-collector (cdr l)
(lambda (dl dp ds)
(col (cons al dl)
(* ap dp)
(+ as ds)))))))))
;; The collector function
(define (collector newl product sum)
(cons sum
(cons product newl)))
Run Code Online (Sandbox Code Playgroud)
先感谢您!!
Eli*_*lay 43
尝试更简单的东西,看看它是如何工作的.例如,这是一个list-sum接收延续参数(通常称为k)的函数版本:
(define (list-sum l k)
(if (null? l)
???
(list-sum (cdr l) ???)))
Run Code Online (Sandbox Code Playgroud)
基本模式就在那里,缺失的部分是有趣的事情发生的地方.continuation参数是一个期望接收结果的函数 - 所以如果列表为null,很明显我们应该发送它0,因为这是总和:
(define (list-sum l k)
(if (null? l)
(k 0)
(list-sum (cdr l) ???)))
Run Code Online (Sandbox Code Playgroud)
现在,当列表不为null时,我们用列表的尾部递归调用函数(换句话说,这是一个迭代),但问题是延续应该是什么.这样做:
(define (list-sum l k)
(if (null? l)
(k 0)
(list-sum (cdr l) k)))
Run Code Online (Sandbox Code Playgroud)
显然是错误的 - 这意味着k最终会获得总和,(cdr l)而不是全部l.相反,在那里使用一个新函数,它将总结第一个元素l以及它接收的值:
(define (list-sum l k)
(if (null? l)
(k 0)
(list-sum (cdr l) (lambda (sum) (+ (car l) sum)))))
Run Code Online (Sandbox Code Playgroud)
这越来越近,但仍然是错误的.但是考虑一下事情是如何工作的 - 这是一个很好的观点 - 我们正在调用list-sum一个本身会收到总和的延续,并将我们现在看到的第一个项目添加到它.缺少的部分很明显,我们忽略了这一点k.我们需要的是组合 k使用此功能-所以我们做同样的总和操作,那么结果发送到k:
(define (list-sum l k)
(if (null? l)
(k 0)
(list-sum (cdr l) (compose k (lambda (s) (+ s (car l)))))))
Run Code Online (Sandbox Code Playgroud)
这终于奏效了.(顺便说一下,请记住,这些lambda功能中的每一个都有自己的"副本" l.)您可以尝试以下方法:
(list-sum '(1 2 3 4) (lambda (x) x))
Run Code Online (Sandbox Code Playgroud)
最后请注意,这与:
(define (list-sum l k)
(if (null? l)
(k 0)
(list-sum (cdr l) (lambda (s) (k (+ s (car l)))))))
Run Code Online (Sandbox Code Playgroud)
如果你明确表达了作品.
(您也可以在中间+ lambda学生语言中使用此代码,然后单击步进按钮以查看评估是如何进行的 - 这将需要一段时间才能完成,但您将看到延续函数如何嵌套,每个用它自己的列表视图.)