《哈斯克尔与普里蒂》中的单曲

人气:443 发布:2022-10-16 标签: io monads haskell

问题描述

我的问题是,Haskell中的单体是否真的保持了Haskell的纯净,如果是的话,又是如何保持的。我经常读到关于副作用是如何不纯的,但有用的程序(例如I/O)需要副作用。在接下来的一句话中,哈斯克尔对此的解决方案是单体。然后,人们在某种程度上解释了单药,但并没有真正说明它们如何解决副作用问题。

我见过this和this,我对答案的解释实际上是我自己读到的--IO单元格的操作和操作不是I/O本身,而是在执行时执行I/O的对象。但是我想到,对于任何代码或任何编译后的可执行文件,都可以得出同样的结论。难道你不能说C++程序在执行编译后的代码时只产生副作用吗?所有的C++都在IO Monad中,所以C++是纯的?我怀疑这是真的,但我真的不知道它在哪方面不是真的。事实上,莫吉不是(sp?)最初使用单数对命令式程序的指称语义进行建模?

一些背景:我是Haskell和函数式编程的粉丝,我希望随着学习的继续,对两者都有更多的了解。例如,我理解引用透明度的好处。这个问题的动机是因为我是一名研究生,我将在一门编程语言课上做两个1小时的演讲,一个特别介绍Haskell,另一个一般地介绍函数式编程。我怀疑班上的大多数人不熟悉函数式编程,可能看过一些方案。我希望能够(合理地)清楚地解释单子是如何解决纯度问题的,而不是深入到范畴理论和单子的理论基础,因为我没有时间讨论这些问题,而且反正我也不完全理解自己--当然不够好地展示。

我想知道这个上下文中的纯度是不是定义得不是很清楚?

推荐答案

很难在这两个方向上得出结论,因为"纯"一词的定义不是特别明确。当然,某些使Haskell从根本上不同于其他语言,并且它与管理副作用和IO类型?密切相关,但不清楚确切地那个是什么。给出一个具体的定义以供参考,我们可以只检查它是否适用,但这并不容易:这样的定义要么不符合每个人的期望,要么过于宽泛而没有用。

那么,哈斯克尔的特别之处在哪里呢?在我看来,这是评估和执行之间的分离。

与λ密切相关的基本语言-Caluclus-完全是关于前者的。您可以使用计算结果为1 + 12的表达式。这里没有副作用,不是因为它们被抑制或移除,而只是因为它们从一开始就没有意义。就像回溯搜索是Java模型的一部分(与Prolog相反)一样,它们也不是模型的一部分。

如果我们只是坚持使用这种基本语言,而不为IO添加任何功能,我认为将其称为"纯"是相当没有争议的。它仍将是有用的,也许,作为数学的替代品。您可以将您的程序编写为一个表达式,然后在REPL处获得计算该表达式的结果。只不过是一个花哨的计算器,没有人会指责你在计算器中使用的表达语言不纯正!

但是,当然,这太有限了。我们想要使用我们的语言来阅读文件和提供网页,绘制图片和控制机器人,并与用户互动。因此,问题是如何保留我们在计算表达式时喜欢的一切,同时扩展我们的语言来做我们想做的任何事情。

我们得出的答案?IO。一种特殊类型的表达,我们类似计算器的语言可以计算它,它对应于做一些有效的行动。重要的是,求值仍然像以前一样工作,甚至对IO中的内容也是如此。效果按照结果IO值指定的顺序执行,而不是基于它的求值方式。IO是我们用来在原本纯粹的表达式语言中引入和管理效果的工具。

我认为这足以使将Haskell描述为"纯粹的"有意义。

脚注

?请注意我是如何说IO而不是一般的Monad的:Monad的概念对于许多与输入和输出无关的事情都非常有用,并且IO类型必须多于仅仅Monad才是有用的。我觉得这两者在共同的话语中联系得太紧密了。

这就是unsafePerformIO如此不安全的原因:它破坏了语言的核心抽象。比方说,这与在C中使用特定寄存器是一样的:这既会导致奇怪的行为,又会阻止代码的可移植,因为它低于C的抽象级别。

³大多数情况下,只要我们忽略生成随机数之类的事情。

635