为什么不能通过严格的评估来欺骗Haskell执行IO操作?

Jua*_*uan 16 monads haskell io-monad

我只是在学习Haskell和IO monads.我想知道为什么这不会强制程序输出"hi"以及"bye":

second a b = b
main = print ((second $! ((print "hi") >>= (\r -> return ()))) "bye")
Run Code Online (Sandbox Code Playgroud)

据我所知,$!运算符会强制要求第一个参数second进行求值,并且>>=运算符需要运行print "hi"以便从中获取值并将其传递\r -> return ()给屏幕,这将打印"hi"到屏幕.

我的推理有什么问题?

而且,有没有办法证明Haskell不能被欺骗(除了使用不安全的函数)在"安全"代码中运行IO操作?

Joa*_*ner 33

你强迫的表达式((print "hi") >>= (\r -> return ()))是类型IO ().因此,它代表IO动作.但是评估这样的事情与运行它是完全不同的!

评估一个值意味着执行足够的步骤将其转换为所谓的弱头正常形式.因为IO是抽象的,在这种情况下看到这意味着什么有点棘手,但是人们可以认为IO aRealWorld -> (a, RealWorld),然后弱头正常形式是一个等待给予的函数RealWorld.

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

所有这些都不是非常具体的IO; 你的困惑和概念同样适用于a -> b.如果你理解$!当第二个参数是一个函数时会发生什么,你就会明白当它是一个IO动作时会发生什么.


dfe*_*uer 21

你对评估执行感到困惑.当您强制使用表达式时print "hi",不会打印任何内容.它只生成一个值(在这种情况下,类型的值IO()),表示打印出来的操作.您可以将print "hi"作为打印"hi"的配方的价值想象出来.