Haskell 让IO成为MonadContent的实例有意义吗?
显然,Haskell 让IO成为MonadContent的实例有意义吗?,haskell,monads,continuation,Haskell,Monads,Continuation,显然,MonadConts比普通的Monads更受限制,并且由于其callCC功能更强大。这意味着更少的实例,你可以用它做更多的事情 当查看MonadCont的已定义实例时,这里列出的所有内容都需要Cont或ContT或已经存在的MonadCont实例。这意味着我们必须从一些Cont或ContT开始,特别是不能将IO变成MonadCont 但是,我认为在IO上下文中使用callCC是有意义的,因此我们可以简化以下内容(根据callCC示例进行调整): whatsYourName::IO() 你的
MonadCont
s比普通的Monad
s更受限制,并且由于其callCC
功能更强大。这意味着更少的实例,你可以用它做更多的事情
当查看MonadCont
的已定义实例时,这里列出的所有内容都需要Cont
或ContT
或已经存在的MonadCont
实例。这意味着我们必须从一些Cont
或ContT
开始,特别是不能将IO
变成MonadCont
但是,我认为在IO
上下文中使用callCC
是有意义的,因此我们可以简化以下内容(根据callCC
示例进行调整):
whatsYourName::IO()
你的名字是什么
名副其实
当(空名称)(退出“你忘了告诉我你的名字!”)
return$“Welcome,”++name++“!”
打印响应
进入
whatsYourName':IO()
你叫什么名字
名称文件上说:
许多需要在其他语言中延续的算法不需要
由于Haskell的惰性语义,在Haskell中需要它们。滥用
延续单子可以产生无法理解的代码
维护
我想这可能是主要原因。我认为这是个坏主意。首先,MonadCont
在MTL中。GHC对此一无所知,这意味着编译器依赖于第三方库ick
其次,callCC
即使在一些非常知名的策划人中也不受欢迎,这主要是因为它使关于代码的推理成为一种痛苦!就像很难推理的goto
一样。特别是在Haskell的时候我们要去哪里
它是例外安全的吗?(这已经很难了)
它安全吗
最后,我们甚至不需要它。如果您想使用continuations和IO,请使用ContT IO
,它同样强大。然而,我几乎可以保证它可以被一些功能不那么强大的东西取代,比如monad提示符
。Continuations是一把大锤,10次中有9次,callCC
太强大了,可以用更高阶函数和惰性的组合来表达
例如,callCC
的一个典型用法是实现类似异常的东西,但在Haskell中,我们可以只使用monad:)(它依赖于高阶函数和惰性)
从本质上说,你的提议增加了复杂性,意味着将MTL合并到base中,以及为了避免liftIO
而产生的一系列其他不愉快
重新编辑
当然可以这样做,但它不是MonadCont的实例(当然:)
这有点不同,unsafePerformIO
的目的是为了让其他人看不到副作用,因为您无法保证如何或何时执行
如果callCCIO
是这种情况,那么您可以使用Cont
连续传球风格很有用,我们有它,有了contr IO
!对我来说,这是棺材上最大的钉子,我看不出这一想法比仅仅使用现有库而不是困难且可能不安全的编译器破解有任何好处
通过使用ContT
monad实现简单的中止功能,您可以有效地用火箭筒击中苍蝇。:-)如果您的目标只是在出错时放弃错误消息,那么您可能需要考虑使用<代码> ErrorT <代码>单元格(由其提供)。或者,如果您在错误发生时不使用一个单独的类型,那么您可能需要考虑使用<代码> Apvutt< /Cord>Munad(由其提供)。< /P> < P>答案是否定的,因为Laul/CC是任何语言的坏特性。尽管call/cc在Scheme中已经存在了很长时间,但这并不意味着call/cc是一种很好的语言特性。call/cc-in方案的经验表明,它是一种糟糕的语言特性:使用call/cc经常泄漏内存,没有动态风的call/cc不适合任何严肃的程序或任何库;另一方面,在动态风中,标准的call/cc习惯用法变得缓慢。所有这些缺点,连同支持代码和其他证据,在
我同意延续传球方式有很多好处。事实上,当我们以一元风格编写Haskell代码时,我们使用的正是CPS。实际上,考虑一个简单的嵌套函数调用<代码> PTCHAR(GETCHAR)(< /代码>)。我们用CPS写它如下
getCharK :: () -> (Char -> w) -> w
putCharK :: Char -> (() -> w) -> w
gp :: (() -> w) -> w
gp = \k -> getCharK () (\c -> putCharK c k)
这里我们如何为一元getM和putM编写相同的嵌套调用(对于某些一元getM):
现在,如果bind定义为
bind m f = \k -> m (\x -> (f x) k)
然后,一元嵌套函数应用程序与CPS版本的代码相同。
如果将M替换为ContT w IO
和newtype,则一元示例在Haskell中有效
在bind的定义中包装ContT/runContT(在ContT w IO monad中变成(>>=)
)。因此,Haskell已经允许我们用CPS编写代码;do nonation使它非常方便。您好,谢谢您的回答,请查看我的编辑,它回答了您的论点。
getCharK :: () -> (Char -> w) -> w
putCharK :: Char -> (() -> w) -> w
gp :: (() -> w) -> w
gp = \k -> getCharK () (\c -> putCharK c k)
getM :: () -> M Char
putM :: Char -> M ()
gpM :: M ()
gpM = getM () `bind` (\c -> putM c)
bind m f = \k -> m (\x -> (f x) k)