将Scheme call/cc转换为Haskell callCC 让我们考虑一下另一个非终止折叠: (呼叫/抄送(lambda(折叠) (溪流褶皱) (lambda(附件五) (如果(
上述代码的Haskell等价物是将Scheme call/cc转换为Haskell callCC 让我们考虑一下另一个非终止折叠: (呼叫/抄送(lambda(折叠) (溪流褶皱) (lambda(附件五) (如果(,haskell,scheme,continuations,Haskell,Scheme,Continuations,上述代码的Haskell等价物是 callCC$\folded->foldl(\acc v->如果v
callCC$\folded->foldl(\acc v->如果v<5那么v:acc else folded acc)[0..]
这段代码没有编译,并且抱怨无法在表达式中构造无限类型。我已经知道如何在Y combinator这样的情况下消除这种错误,但是相同的方法在这里似乎不起作用。对于这种情况,什么是正确的方法?是的;作为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
工作。首先,正如前面所解释的,Scheme call/cc和Haskell callCC有些不同 在页面上 主要问题是您可能根本不需要call/cc——即使在Scheme中也是如此。您的打破循环的示例使用异常实现得更好——从效率的角度来看更好(不需要捕获您无论如何都不会使用的延续),并且在概念上更好。如果任务是中止当前的延续,那么有一些工具正是用于此目的的。R7RS已经认识到这一点,并引入了例外情况。要在Haskell中使用异常,请使用Error或monad。例如,在您的代码中
baz :: Either [Int] [Int]
baz = foldM (\acc v -> do
when (v >= 5) $ Left acc
return $ v : acc) [] [0..]
thing1 = either id id baz
操作员呼叫/cc是在缺乏控制操作员经验的情况下引入该方案的。现在我们有了很多经验,call/cc的许多严重缺点已经暴露出来。如果您对更多细节感兴趣,下面的页面将详细介绍call/cc的问题。
使用
foldM
而不是foldl
。这里有一个v:acc
和折叠的acc
不返回相同的类型。谢谢你的回答。它在这种情况下有效,但似乎相当专业化。是否有一个通用的方法来翻译方案代码与呼叫/ CC到Haskell或我应该总是考虑每个案件通过查看类型签名?