【问题标题】:How does the "monad-based IO" design of Haskell contrasts with one based on tagging pure/impure code?Haskell 的“基于 monad 的 IO”设计与基于标记纯/不纯代码的设计有何不同?
【发布时间】:2015-12-10 18:04:13
【问题描述】:

众所周知,IO Monad 在 Haskell 中将纯代码与不纯代码分开,因此像 f :: ... -> IO ? 这样的签名表示具有副作用的操作,否则它是纯函数。

此外,在 Haskell 中,monad 被用作对动作进行排序的纯函数机制,否则可能会被设计为仅处理纯函数的编译器意外地重新排序。

围绕 monad 进行设计的问题在于它们似乎对很多人来说很难理解,也许包括我自己,所以我想知道它们是否是在软件开发中区分纯代码和不纯代码的最佳方法。

我想如果我们有一种语言,其中所有原语都被标记为纯和不纯,编译器可以很容易地直接或间接地使用原语推断任何函数的纯度,这将是一个更简单的设计。这样的编译器然后会知道代码的哪些部分可以重新排序,因为它们是纯的,或者由于存在副作用而需要一些顺序。

所以,我的问题是:

与上面描述的基于语言中标记纯/不纯原语的设计相比,“基于 monad 的 IO”设计有哪些优点/缺点?

【问题讨论】:

  • 单子的力量远远超出了知道什么是纯和不纯的。继续努力,你会得到的。
  • 一个明显的优势是,使用 monad 为您提供了一个清晰的抽象,可以在许多不同的 monad 中使用相同的函数。看看Control.Monad 和其他地方的所有函数,有几十个组合子可以与Monad m => ... 一起工作,不管它是哪个monad。这让您可以在很多情况下重复使用强大的工具。
  • 您的问题似乎假设将纯事物与不纯事物分开的唯一要点是使编译器能够进行更多的优化。然而,跟踪副作用不仅对编译器有用,对人类编写和阅读代码也有用。使用类型跟踪副作用为我们提供了关于它们存在或不存在的可靠且易于访问的信息,这些信息在构建程序时非常有用。
  • 我一直发现查看 monad 的构成更有用(基于类型签名和法律)。诸如“它有点像容器”和“它用于排序操作”之类的可爱类比在某些特定情况下效果很好,但通常对理解实际发生的事情没有用处。
  • @Cubic 我认为 monads 是一种将a >> ... >> z 中的函数序列处理为我们需要的任何内容的方法,最后将return ... 处理为此类处理的结果。我没有得到的是这样的东西怎么能像人们所说的那样强大。

标签: haskell


【解决方案1】:

Haskell 对 IO 类型做了类似的事情。然而,Haskell 类型系统更通用。您可以将 monad 视为潜在副作用范围的声明,因此您可以拥有一个更复杂的系统,而不是使用二进制纯/不纯标志。

当然,Haskell monad 是关于“杂质”的神话。当然,IO 是一个特例,但是所有其他的 monad 都是用 Haskell 编写的,并且完全实现了“bind”。 (好吧,也许 ST 和 STM 需要一些来自运行时系统的魔法来提高效率,但它们可以用 Haskell 编写)。

【讨论】:

  • “Haskell monad 是关于杂质的神话”是一个非常重要的评论。 Monad 是一个非常笼统和抽象的(这使得一开始有点难以掌握)但最终非常简单的界面。 IO 恰好是其众多用例之一。
猜你喜欢
  • 1970-01-01
  • 2023-04-07
  • 1970-01-01
  • 2011-03-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-08-16
  • 2013-11-19
相关资源
最近更新 更多