显然 MonadCont
s 比普通的 Monad
s 受到更多限制,并且提供更多功能,这要归功于它的 callCC
。这意味着它的实例更少,你可以用它做更多的事情。
当查看 MonadCont
的定义实例时,看起来那里列出的所有内容都需要 Cont
或 ContT
或一个已经存在的 MonadCont
实例。这意味着我们必须从一些 Cont
或 ContT
开始,特别是不能将 IO
变成 MonadCont
。
但是,我认为在 callCC
上下文中使用 IO
是有意义的,因此我们可以简化以下内容(根据 official Hackage page callCC
示例调整):
whatsYourName :: IO ()
whatsYourName = do
name <- getLine
let response = flip runCont id $ do
callCC $ \exit -> do
when (null name) (exit "You forgot to tell me your name!")
return $ "Welcome, " ++ name ++ "!"
print response
进入
whatsYourName' :: IO ()
whatsYourName' = do
name <- getLine
response <- callCC $ \exit -> do
when (null name) (exit "You forgot to tell me your name!")
return $ "Welcome, " ++ name ++ "!"
print response
以更简洁的方式在 do 块中使用
callCC
。当然,为了使
IO
成为 MonadCont
的实例,我们必须有一些魔法,因为 callCC
的 IO
意味着“调用给定的函数, future 的计算指定了现实世界中接下来发生的事情”,所以实际上只有解释器或编译器才能知道这是什么意思。另一方面,我没有看到任何理论上的理由表明这是可导入的,因为 Scheme 已经拥有它很长时间了,并且制作这样的实例根本不需要语言更改。可能的问题
我能想到的一个因素是
callCC
的语义与适当的清理保证冲突。许多语言提供了“try...finally”控制以进行适当的清理,C++ 的析构函数也保证了这一点。我不确定它在 Haskell 中是什么,但是如果 callCC
可用于 IO
,则可以使用它来摆脱任何需要清理的 IO
相关上下文,因此提供 sush 保证将变得不可能,正如您所看到的 what happens in Ruby 。意见讨论
@jozefg 的回答非常好。我只想在这里写下我的看法。
MonadCont
确实来自 mtl。但这并不意味着 GHC 或其他编译器不能定义 unsafeCallCC
并定义实例,如果具有正确定义的 MonadCont
在编译模块和 -XIOMonadCont
被设置的范围内。 unsafePerformIO
,在我看来,它基本上比 unsafeCallCC
更不安全。 callCC
在大多数情况下过于强大,应尽可能避免使用。然而,在我看来,延续传递风格可以用来使惰性求值显式化,这有助于更好地理解程序,从而更容易找到可能的优化。因为 CPS 不是 MonadCont
,但它是使用它并将深层嵌套的内部函数转换为 do 符号的自然步骤。 最佳答案
我会说这是一个坏主意。首先,MonadCont
在 MTL 中。 GHC 对此一无所知,这意味着使编译器依赖于 3rd 方库,ick。
其次,callCC
即使在一些非常高调的 Schemers 中也不受欢迎,主要是因为它使对代码的推理变得痛苦!与 goto
难以推理的方式大致相同。特别是在 Haskell 中,我们必须担心的地方
callCC
安全吗? 最后,我们甚至不需要它。如果您想使用延续和 IO,请使用
ContT IO
,它同样强大。但是,我几乎可以保证它可以用功能较弱的东西替换,例如 monad-prompt
。延续是一把大锤,10 次中有 9 次,callCC
太强大了,可以使用高阶函数和惰性的组合来更愉快地表达。例如,
callCC
的典型用途之一是实现诸如异常之类的东西,但在 Haskell 中,我们可以只使用 monads :)(它依赖于高阶函数和惰性)。从本质上讲,您的提议增加了复杂性,意味着将 MTL 合并到 base 中,以及避免使用
liftIO
的一大堆其他不愉快。RE 编辑
MonadCont
的实例 :) unsafePerformIO
旨在用于其他人看不到副作用,因为您无法保证事情如何或何时执行。如果
callCCIO
就是这种情况,那么您可以只使用 Cont
! ConT r IO
!这对我来说是棺材上最大的钉子,我认为 没有任何 的好处,而不是仅仅使用现有的库来克服困难且可能不安全的编译器黑客攻击。 关于haskell - 让 IO 成为 MonadCont 的实例有意义吗?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/19851915/