首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >了解`let`表达式中IO ()的类型

了解`let`表达式中IO ()的类型
EN

Stack Overflow用户
提问于 2016-05-27 11:33:21
回答 4查看 547关注 0票数 15

给定:

代码语言:javascript
复制
λ: let f = putStrLn "foo" in 42
42

f的类型是什么?为什么在显示42结果之前不打印"foo"

最后,为什么下面的方法不起作用?

代码语言:javascript
复制
λ: :t f

<interactive>:1:1: Not in scope: ‘f’
EN

Stack Overflow用户

发布于 2016-05-27 17:09:26

这里发生了两件事。

首先,考虑一下

代码语言:javascript
复制
let x = sum [1..1000000] in 42

哈斯克尔很懒。因为我们实际上没有对x做任何事情,所以它永远不会被计算出来。(这也很好,因为它会稍微慢一点。)事实上,如果你编译它,编译器会发现x从未被使用过,并删除它(也就是说,不会为它生成任何编译代码)。

其次,调用putStrLn实际上不会打印任何内容。相反,它返回IO (),您可以将其视为一种"I/O命令对象“。仅仅拥有一个命令对象与执行它是不同的。按照设计,“执行”I/O命令对象的唯一方法是从main返回它。至少,它是在一个完整的程序中实现的;如果您输入一个返回I/O命令对象的表达式,GHCi将为您执行它,这对GHCi很有帮助。

您的表达式返回42;同样,没有使用f,因此它不做任何事情。

正如chi正确指出的那样,这有点像声明了一个本地(零参数)函数,但从未调用过它。您不会期望看到任何输出。

你也可以做类似这样的事情

代码语言:javascript
复制
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

票数 4
EN
查看全部 4 条回答
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/37474405

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档