给定:
λ: let f = putStrLn "foo" in 42
42f的类型是什么?为什么在显示42结果之前不打印"foo"
最后,为什么下面的方法不起作用?
λ: :t f
<interactive>:1:1: Not in scope: ‘f’发布于 2016-05-27 17:09:26
这里发生了两件事。
首先,考虑一下
let x = sum [1..1000000] in 42哈斯克尔很懒。因为我们实际上没有对x做任何事情,所以它永远不会被计算出来。(这也很好,因为它会稍微慢一点。)事实上,如果你编译它,编译器会发现x从未被使用过,并删除它(也就是说,不会为它生成任何编译代码)。
其次,调用putStrLn实际上不会打印任何内容。相反,它返回IO (),您可以将其视为一种"I/O命令对象“。仅仅拥有一个命令对象与执行它是不同的。按照设计,“执行”I/O命令对象的唯一方法是从main返回它。至少,它是在一个完整的程序中实现的;如果您输入一个返回I/O命令对象的表达式,GHCi将为您执行它,这对GHCi很有帮助。
您的表达式返回42;同样,没有使用f,因此它不做任何事情。
正如chi正确指出的那样,这有点像声明了一个本地(零参数)函数,但从未调用过它。您不会期望看到任何输出。
你也可以做类似这样的事情
actions = [print 5, print 6, print 7, print 8]这将创建I/O命令对象的列表。但是,同样,它不会执行它们中的任何一个。
通常,当您编写执行I/O的函数时,它是一个do-block,它将所有内容链接到一个巨大的I/O命令对象中,并将其返回给调用者。在这种情况下,您实际上不需要理解或了解定义命令对象和执行命令对象之间的区别。但两者之间的区别仍然存在。
使用具有显式run-function的monad可能更容易看到这一点。例如,runST获取一个ST命令对象,运行它,并返回给您答案。但是(比方说) newSTVar本身除了构造一个ST命令什么也不做;你必须在任何事情真正“发生”之前对其进行runST。
https://stackoverflow.com/questions/37474405
复制相似问题