首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >将Scheme调用/cc转换为Haskell callCC

将Scheme调用/cc转换为Haskell callCC
EN

Stack Overflow用户
提问于 2014-10-19 01:38:44
回答 2查看 214关注 0票数 6

让我们考虑打破一种否则不会终结的局面:

代码语言:javascript
复制
(call/cc (lambda (folded)
  (stream-fold
    (lambda (acc v)
      (if (< v 5)
        (cons v acc)
        (folded acc)))
    '()
    (in-naturals 0))))
; returns '(4 3 2 1 0)

上述代码的Haskell等价物应该是

代码语言:javascript
复制
callCC $ \folded -> foldl (\acc v -> if v < 5 then v:acc else folded acc) [] [0..]

此代码不编译,并抱怨无法在表达式折叠的acc中构造无限类型。我已经知道如何在Y组合器这样的情况下消除这种错误,但同样的方法在这里似乎行不通。在这种情况下,正确的做法是什么?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2014-10-19 05:21:19

是的;正如j·亚伯拉罕所说,

代码语言:javascript
复制
import Control.Monad.Trans.Cont
import Control.Monad

bar :: Cont r [Int]
bar = callCC $ \folded ->
    foldM (\acc v -> do
        when (v >= 5) $ folded acc
        return $ v : acc) [] [0..]

thing = runCont bar id

很管用。

票数 6
EN

Stack Overflow用户

发布于 2014-11-25 08:34:04

首先,page /cc和Haskell callCC是有些不同的东西,如页面未分隔的延续不是函数。中所解释的那样

主要问题是您可能根本不需要调用/抄送--即使在Scheme中也是如此。使用异常更好地实现了您的跳出循环的示例--从效率的角度来看更好(不需要捕获您无论如何都不会使用的延续),并且在概念上更好。如果任务是中止当前的延续,那么有一些工具正是用于此目的的。R7RS已经认识到这一点,并引入了例外。若要在Haskell中使用异常,请使用错误或单变量。例如,在您的代码中

代码语言:javascript
复制
baz :: Either [Int] [Int]
baz = foldM (\acc v -> do
        when (v >= 5) $ Left acc
        return $ v : acc) [] [0..]

thing1 = either id id baz

在对控制操作符缺乏经验的情况下,将操作员调用/cc引入到Scheme中。现在我们有了很多经验,call/cc的许多严重缺陷已经暴露出来了。如果您对更多细节感兴趣,下面的页面将详细介绍call/cc的问题。反对call/cc的论点

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/26446393

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档