Clojure的延续

unj*_*nj2 28 scheme continuations functional-programming clojure

我读到富有的hickey说的地方:

"我认为在理论上延续可能是整洁的,但在实践中并非如此"

我不熟悉clojure.
1. clojure有继续吗?
如果不是,你不需要继续吗?我见过很多很好的例子,尤其是这个人.有什么选择?
3.如果是,是否有文件?

Dar*_*rio 27

在谈论延续时,你必须区分它们的两种不同:

  • 一流的延续 - 持续支持,深度集成在语言中(Scheme或Ruby).Clojure不支持一流的延续.

  • 延续传递式(CPS) - CPS只是一种编码风格,任何支持匿名功能的语言都将允许这种风格(也适用于Clojure).

例子:

-- Standard function
double :: Int -> Int
double x = 2 * x

-- CPS-function – We pass the continuation explicitly
doubleCPS :: Int -> (Int -> res) -> res
doubleCPS x cont = cont (2 * x)
Run Code Online (Sandbox Code Playgroud)
; Call
print (double 2)

; Call CPS: Continue execution with specified anonymous function
double 2 (\res -> print res)
Run Code Online (Sandbox Code Playgroud)

阅读维基百科上的续篇.

我不认为延续对于良好的语言是必要的,但尤其是像Haskell这样的函数式语言中的第一类延续和CPS可能非常有用(智能回溯示例).

  • 关于你的两点中的第二点,在一般情况下,是否需要尾调用才能使CPS可用?考虑一个标准函数,将其包装在"while(!aborted)"块中,使其重复直到中止.CPS式函数的等效使用是不是将其自身作为延续发送?因此,您将获得无限递归,并且需要进行尾调用优化.我只是在这里大声思考,所以请告诉我这是否有意义:-) (9认同)

dno*_*len 22

我写了一个cl-cont的Clojure端口,它为Common Lisp添加了延续.

https://github.com/swannodette/delimc


Dra*_*mon 13

延续是语言中的必要特征吗?

没有.很多语言都没有延续.

如果不是,你不需要继续吗?我见过很多很好的例子,尤其是这个人.有什么选择?

一个调用堆栈


Nat*_*vis 10

摘要继续

Continuations是一个抽象概念,用于描述控制流语义.在这个意义上,它们既存在又不存在(记住,它们是抽象的)任何提供控制操作符的语言(如任何图灵完整语言必须的那样),就像数字都存在一样(作为抽象实体)和不存在(作为有形实体).

Continuations描述控制效果,例如函数调用/返回,异常处理,甚至是gotos.除其他外,一个完善的语言将设计有基于延续(例如,例外)的抽象.(也就是说,一个有根据的语言将由设计时考虑到延续的控制运算符组成.当然,将语言作为唯一的控件抽象公开,允许用户构建自己的语言是完全合理的.抽象在上面.)

头等舱继续

如果延续的概念被物化为一种语言一流的对象,然后我们有一个工具,在其各种控制效果可建.例如,如果一种语言具有一等继承而非异常,我们可以在continuation之上构造异常.

一流继续存在的问题

虽然在许多情况下,一流的延续是一个强大而有用的工具,但是用一种语言暴露它们也有一些缺点:

  • 在连续之上构建的不同抽象可能在编写时导致意外/不直观的行为.例如,finally如果我使用continuation中止计算,则可能会跳过一个块.
  • 如果可以在任何时间请求当前继续,则必须构造语言运行时,以便可以随时生成当前延续的一些数据结构表示.这对于一个功能的运行时间造成了一定程度的负担,无论好坏,通常被认为是"异国情调".如果托管语言(例如Clojure托管在JVM上),则该表示必须能够适合托管平台提供的框架.还可能存在语言想要维护的其他特征(例如,C interop),其限制解空间.诸如此类的问题增加了"阻碍不匹配"的可能性,并且可能使性能解决方案的开发严重复杂化.

为语言添加一流的连续性

通过元编程,可以为语言添加对一流延续的支持.通常,这种方法涉及将代码转换为连续传递样式(CPS),其中当前延续作为每个函数的显式参数传递.

例如,David Nolen的delimc库通过一系列宏变换实现了Clojure程序部分的分隔连续.与此类似,我创作了pulley.cps,它是一个将代码转换为CPS的宏编译器,以及一个运行时库,支持更多核心Clojure特性(如异常处理)以及与本机Clojure代码互操作.

这种方法的一个问题是如何处理本机(Clojure)代码和转换(CPS)代码之间的边界.具体来说,由于您无法捕获本机代码的延续,您需要禁止(或以某种方式限制)与基本语言的互操作,或者给用户带来负担,确保上下文允许他们希望实际捕获的任何延续被捕获.

尽管已经进行了一些尝试以允许用户管理它,但是滑轮cps倾向于后者.例如,可以禁止CPS代码调用本机代码.此外,提供了一种机制来提供现有本机功能的CPS版本.

在具有足够强类型系统的语言(例如Haskell)中,可以使用类型系统来封装可能使用来自功能纯代码的控制操作(即,延续)的计算.

摘要

我们现在拥有直接回答您的三个问题所需的信息:

  1. 由于实际考虑,Clojure不支持一流的延续.
  2. 所有语言都建立在理论意义上的延续之上,但很少有语言将连续性视为第一类对象.但是,可以通过例如转换为CPS来向任何语言添加延续.
  3. 查看delimc和/或pulley.cps的文档.


Vij*_*hew 7

延迟的一个常见用途是实现控制结构:从函数返回,从循环中断,异常处理等.大多数语言(如Java,C++等)都将这些特性作为核心语言的一部分提供.有些语言没有(例如:Scheme).相反,这些语言将连续性暴露为第一类对象,并让程序员定义新的控制结构.因此,Scheme应该被视为一种编程语言工具包,而不是一种完整的语言本身.

在Clojure中,我们几乎不需要直接使用continuation,因为几乎所有的控制结构都是由语言/ VM组合提供的.仍然,一流的延续可以成为有能力的程序员手中的有力工具.特别是在Scheme中,continuation比其他语言中的等价对应物更好(比如C中的setjmp/longjmp对).文章对此有更多的细节.

顺便说一句,了解Rich Hickey如何证明他对延续的看法将会很有趣.任何链接?

  • 好的Lispers通过增加语言来编写程序.换句话说,您将Lisp转换为最适合解决手头问题的语言.这是Lisps和其他语言之间的一个很大的区别.Paul Graham在他的"On Lisp"一书中详细解释了这一点.我不知道你是谁或你做了什么,但我想你还没有在Lisp中写过任何重要的软件.否则我不必解释这个.我维护自己的Scheme并每天使用它来解决现实问题. (8认同)
  • "几乎所有的控制结构都是由语言/ VM组合提供的",你忘了补充说没人会需要超过640kb的RAM. (8认同)
  • 顺便说一下,我不认为在称之为"无聊的漫无边际"之后要求某人解释他的观点是个好主意. (3认同)
  • 它应该是"完整的"而不是"完整的".当我说"完整"时,我并不是说图灵完整.我的意思是人们通常对"现代"语言的期望.例如,使用try-catch进行异常处理.Scheme没有提供,但使用第一类continuation,您可以实现自己的异常处理机制. (2认同)

pmf*_*pmf 6

Clojure(或者更确切地说clojure.contrib.monads)有一个延续monad; 这是一篇描述其用法和动机的文章.