haskell - Haskell 中的 Monad 和 Purity

标签 haskell io monads

我的问题是 Haskell 中的 monad 是否真正保持了 Haskell 的纯度,如果是的话,又是如何保持的。我经常读到副作用是如何不纯粹的,但有用的程序(例如 I/O)需要副作用。下一句指出 Haskell 对此的解决方案是 monad。然后对单子(monad)进行了某种程度的解释,但并没有真正解释它们如何解决副作用问题。

我见过thisthis ,我对答案的解释实际上是我在自己的阅读中想到的——IO monad 的“ Action ”不是 I/O 本身,而是在执行时执行 I/O 的对象。但我突然想到,可以对任何代码或任何已编译的可执行文件提出相同的论点。难道你不能说C++程序只有在执行编译后的代码时才会产生副作用吗?所有 C++ 都在 IO monad 内部,所以 C++ 是纯粹的?我怀疑这是真的,但老实说我不知道​​它在哪方面不是真的。事实上,Moggi(sp?)最初不是使用 monad 来建模命令式程序的指称语义吗?

一些背景:我是 Haskell 和函数式编程的粉丝,我希望随着我的学习的继续,了解更多关于这两方面的知识。例如,我了解引用透明度的好处。提出这个问题的动机是,我是一名研究生,我将在编程语言类(class)上进行 2 个 1 小时的演示,其中一个主要涵盖 Haskell,另一个涵盖一般的函数式编程。我怀疑类的大多数人都不熟悉函数式编程,也许看过一些方案。我希望能够(合理地)清楚地解释单子(monad)如何解决纯度问题,而不需要深入范畴论和单子(monad)的理论基础,我没有时间讨论这些,而且无论如何我也没有完全理解自己——当然不够好,无法呈现。

我想知道这种情况下的“纯度”是否没有真正明确的定义?

最佳答案

很难在任何一个方向上做出结论性的争论,因为“纯粹”并没有特别明确的定义。当然,某些使得 Haskell 与其他语言有根本的不同,并且它与管理副作用和 IO 类型 1 密切相关,但确切尚不清楚> 那东西是什么。给出一个具体的定义来引用,我们可以检查它是否适用,但这并不容易:这样的定义往往要么不符合每个人的期望,要么过于宽泛而无用。

那么,Haskell 有何特别之处呢?在我看来,这是评估执行之间的分离。

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

如果我们只是坚持这种基本语言而不添加任何IO设施,我认为称其为“纯粹”是相当没有争议的。也许作为 Mathematica 的替代品,它仍然很有用。您可以将程序编写为表达式,然后在 REPL 中获取表达式的计算结果。只不过是一个奇特的计算器,没有人指责您在计算器中使用的表达语言不纯粹!

但是,当然,这太有限了。我们希望使用我们的语言来读取文件、提供网页、绘制图片、控制机器人以及与用户交互。因此,问题是如何保留我们喜欢的有关评估表达式的所有内容,同时扩展我们的语言以执行我们想要的所有操作。

我们得出的答案是什么? IO。我们的类似计算器的语言可以评估的一种特殊类型的表达式,它对应于执行一些有效的操作。至关重要的是,即使对于 IO 中的事物,评估仍然像以前一样工作。效果按照结果 IO 值指定的顺序执行,而不是基于它的评估方式。 IO 是我们用来将效果引入到我们的纯粹表达语言中并对其进行管理的工具。

我认为这足以使 Haskell 描述为“纯粹”有意义。

脚注

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

² 这就是为什么 unsafePerformIO 如此不安全:它破坏了语言的核心抽象。这与在 C 中使用特定寄存器相同:它既会导致奇怪的行为,也会阻止代码的可移植性,因为它低于 C 的抽象级别。

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

关于haskell - Haskell 中的 Monad 和 Purity,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28637146/

相关文章:

haskell - 为什么 Haskell 中没有 `Cofunctor` 类型类?

haskell - 这个 Haskell 表达式中的 redexes 是什么?

java - Swing Java GUI 使用扫描仪读取文本文件

c++ - 在吃 EOF 后重用 std::cin

performance - StateT over Reader 和 ReaderT over State 之间有什么显着区别吗?

jquery - jQuery 是一个 monad

function - 当非 curry 形式已知时,在haskell中进行柯里化(Currying)

haskell - Haskell中的*>和>>有什么区别?

haskell - 我如何理解 Haskell 中的 ":t ((==) <*>)"?

java - 编写仅读写一列的文本