为什么可以';Haskell会被欺骗,通过使用严格的评估来执行IO操作吗?

为什么可以';Haskell会被欺骗,通过使用严格的评估来执行IO操作吗?,haskell,monads,io-monad,Haskell,Monads,Io Monad,我只是在学习Haskell和IO monads。我想知道为什么这不会迫使程序输出“hi”和“bye”: 据我所知,$操作符将强制计算second的第一个参数,而>=操作符需要运行打印“hi”,以便从中获取一个值,并将其传递给\r->return(),从而将“hi”打印到屏幕上 我的推理有什么问题 还有,是否有任何方法可以证明Haskell不会被欺骗(除了使用不安全的函数)在“安全”代码中运行IO操作?您强制使用的表达式是((打印“hi”)>=(\r->return()),类型为IO()。因此,它

我只是在学习Haskell和IO monads。我想知道为什么这不会迫使程序输出“hi”和“bye”:

据我所知,<代码>$操作符将强制计算
second
的第一个参数,而
>=
操作符需要运行
打印“hi”
,以便从中获取一个值,并将其传递给
\r->return()
,从而将“hi”打印到屏幕上

我的推理有什么问题


还有,是否有任何方法可以证明Haskell不会被欺骗(除了使用不安全的函数)在“安全”代码中运行IO操作?

您强制使用的表达式是
((打印“hi”)>=(\r->return())
,类型为
IO()
。因此,它表示IO操作。但是评估这样的事情和运行它是完全不同的

评估一个值意味着执行足够的步骤将其转换为所谓的值。因为
IO
是抽象的,所以在这种情况下要理解这意味着什么有点困难,但是人们可以把
ioa
想象成
RealWorld->(a,RealWorld)
,然后弱头范式就是一个等待被赋予
RealWorld
的函数

运行意味着求值,但也将
RealWorld
作为参数传递,从而导致
IO
效果发生


所有这些都不是特定于
IO
;你的困惑和概念同样适用于
a->b
。如果你明白什么是
$您将计算与执行混淆。当您强制执行类似于
打印“hi”
的表达式时,它不会打印任何内容。它只生成一个值(在本例中,是类型为
IO()
)的值),表示打印某个内容的操作。你可以把打印“hi”
的价值看作是打印“hi”的秘诀。

顺便说一句,你的代码可以简化为
main=print(打印“hi”`seq`“bye”)
回答:因为你不能欺骗Haskell。正如Joachim所说,
($!
利用
seq
,这已经吸引了许多开发人员,例如,请参阅另一个有问题的使用
seq
,这是由;它提供了更多关于为什么您的代码示例在Haskell 2010中不起作用的详细信息。
second a b = b
main = print ((second $! ((print "hi") >>= (\r -> return ()))) "bye")