Functional programming 老练的阴谋家,letcc和诡计
这里有几个问题,关于经验丰富的Schemer中使用的Functional programming 老练的阴谋家,letcc和诡计,functional-programming,scheme,seasoned-schemer,Functional Programming,Scheme,Seasoned Schemer,这里有几个问题,关于经验丰富的Schemer中使用的letcc (define (intersect-all sets) (letcc hop (letrec ((A (lambda (sets) (cond ((null? (car sets)) (hop '()) ((null? (cdr sets)) (car sets)) (else
letcc
(define (intersect-all sets)
(letcc hop
(letrec
((A (lambda (sets)
(cond
((null? (car sets)) (hop '())
((null? (cdr sets)) (car sets))
(else
(intersect (car sets)
(A (cdr sets)))))))
; definition of intersect removed for brevity
(cond
((null? sets) '())
(else (A sets))))))
letcc
实现了什么,这基本上类似于ruby中的catch
和throw
(似乎是CL),这基本上意味着可以通过调用任何名为letcc
的函数来缩短整个代码块。这感觉像是我在这本短小的系列书中遇到的最不“实用”的东西,它让我觉得使用它有点犹豫,因为我想学习一种好的实用风格。我只是误解了letcc,还是它不是真正的函数式编程概念,只是为了提高性能而存在?我可以在一些例程中间突然想到代码中的另一个点的感觉有点不对…比如在Java中滥用try/catch来实现程序流letcc
在我安装在OS X中的guile(1.8.7)版本中似乎不存在。我应该在guile中查找它的其他名称吗letcc
,那么它在功能级别上究竟是如何工作的?它能不能用一种更长、更复杂的方式来表达,让我相信它毕竟是功能性的调用
,通常也使用更友好的名称call/cc
,而let/cc
是一个可以使用call/cc
构建的简单宏
我可以告诉你,在Racket中有一个内置的和一堆的,另外还有一系列不同的控制操作符(有大量的参考文献)let/cc
的简单用法实际上类似于捕获/抛出之类的东西——更具体地说,这种延续通常被称为“逃逸延续”(或者有时是“向上”)。这就是您在该代码中的用法,通常用于实现中止
或返回
但Scheme中的continuation是可以在任何地方使用的东西。对于显示此差异的非常简单的示例,请尝试以下方法:
(define (foo f) (f 100))
(let/cc k (+ (foo k) "junk") (more junk))
如果您有一个同时支持“正常”延续和转义延续的实现,那么使用后者通常比较便宜。您示例中的模式自然适合于转义延续。标准缩写是
let/ec
。仅供参考,它显示了如何使用一个简单的宏来定义letcc
,即call/cc
。@JonO,我以前读过并尝试过它,但guile只是说错误:无效语法()
中止:(杂项错误)
。检查我已经按照页面上说的方式做了,但仍然不起作用。当我开始学习宏时,我可能会弄明白为什么。谁知道这是在哪里记录的,但是在定义宏之前需要(使用语法(ice-9 syncase))
(至少是定义宏的方式):)哇,在读了Matthew Right的那篇文章之后,我的观点改变了。我认为,实际上理解了call/cc
的工作原理,使它看起来比我最初想象的要干净得多。非常感谢你的解释。原来我的guile版本有call/cc
和call与当前的continuation
,但没有letcc
。而且,在ruby中,call/cc
比catch/throw
有趣得多,因为它可以让你做更酷的事情。我想这位经验丰富的策划家会在后面的章节中对此进行更详细的探讨。如果你看完了他的课文,那么也可以看看我的课堂笔记:有几个例子扩展得更广,包括生成器和amb的完整开发,首先是对CPS的描述——在其他语言中实现其中一些的方式。顺便说一句,他的名字是Matthew May。(他可能是对的,但他的名字可能是。)let/cc
实际上是goto
s在服用类固醇。如果被滥用,他们将比转到更糟糕。当然,let/cc
也有合法的情况,同样的,goto
也有合法的(受限的)用途,例如switch
。