让我们考虑打破一种否则不会终结的局面:
(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等价物应该是
callCC $ \folded -> foldl (\acc v -> if v < 5 then v:acc else folded acc) [] [0..]此代码不编译,并抱怨无法在表达式折叠的acc中构造无限类型。我已经知道如何在Y组合器这样的情况下消除这种错误,但同样的方法在这里似乎行不通。在这种情况下,正确的做法是什么?
发布于 2014-10-19 05:21:19
是的;正如j·亚伯拉罕所说,
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很管用。
发布于 2014-11-25 08:34:04
首先,page /cc和Haskell callCC是有些不同的东西,如页面未分隔的延续不是函数。中所解释的那样
主要问题是您可能根本不需要调用/抄送--即使在Scheme中也是如此。使用异常更好地实现了您的跳出循环的示例--从效率的角度来看更好(不需要捕获您无论如何都不会使用的延续),并且在概念上更好。如果任务是中止当前的延续,那么有一些工具正是用于此目的的。R7RS已经认识到这一点,并引入了例外。若要在Haskell中使用异常,请使用错误或单变量。例如,在您的代码中
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的论点
https://stackoverflow.com/questions/26446393
复制相似问题