25

由于副作用破坏了引用透明度,它们不违背函数式语言的观点吗?

4

4 回答 4

25

纯函数式编程语言使用两种技术来模拟副作用:

1) 表示外部状态的世界类型,其中该类型的每个值由类型系统保证仅使用一次。

在使用这种方法的语言中,函数可能分别具有 和print类型。read(string, world) -> worldworld -> (string, world)

它们可能会这样使用:

let main w =
  let w1 = print ("What's your name?", w) in
  let (name, w2) = read w1 in
  let w3 = print ("Your name is " ^ name, w2) in
  w3

但不是这样:

let main w =
  let w1 = print ("What's your name?", w) in
  let (name, w2) = read w in
  let w3 = print ("Your name is " ^ name, w2) in
  w3

(因为 w 被使用了两次)

所有具有副作用的内置函数都将获取并返回一个世界值。由于所有具有副作用的函数要么是内置函数,要么是调用具有副作用的其他函数,这意味着所有具有副作用的函数都需要获取和返回一个世界。

这样就不可能使用相同的参数两次调用具有副作用的函数,并且不会违反引用透明性。

2) 一个 IO monad,所有具有副作用的操作都必须在该 monad 内执行。

使用这种方法,所有具有副作用的操作都将具有 type io something。例如print,将是一个具有 type 的函数,string -> io unit并且read将具有 type io string

访问执行操作的值的唯一方法是使用“monadic bind”操作(例如在 haskell 中称为 >>=),将 IO 操作作为一个参数,将一个描述如何处理结果的函数作为另一个参数操作数。

上面的示例使用 monadic IO 如下所示:

let main =
  (print "What's your name?") >>=
  (lambda () -> read >>=
  (lambda name -> print ("Your name is " ^ name)))
于 2010-10-03T15:35:32.323 回答
13

有几个选项可用于以函数式语言处理 I/O。

  • 不要纯洁。许多函数式语言并不是纯粹的函数式。他们更多的是支持 函数式编程而不是强制执行它。这是迄今为止函数式编程中 I/O 问题最常见的解决方案。(例如:Lisp、Scheme、Standard ML、Erlang 等)
  • 流转换。早期的 Haskell I/O 就是这样完成的。如果您想了解更多信息,请查看下面的链接以获取详细信息。(提示:你可能不知道。)
  • 继续传递 I/O(其他答案中提到的“世界传递”)。在这个中,您通过 I/O 传递一个数据令牌,它充当必要的“不同值”以保持引用完整性。如果没有记错的话,这会被几种 ML 方言使用。
  • 上面的“延续”或“世界”事物可以包装在各种数据类型中,最著名的(最著名的)是在 Haskell 中使用 monads。请注意,这在理论上是相同的事情,但删除了跟踪“世界”/“延续”状态变量的单调乏味。

一篇研究论文详尽地分析了这些。

函数式 I/O 是一个正在进行的研究领域,还有其他语言以有趣和令人费解的方式解决这个问题。 霍尔逻辑被用于一些研究语言。其他人(如Mercury)使用uniqueness typing。还有一些(如 Clean)使用效果系统。其中我对水星的接触非常非常有限,所以我不能对细节发表评论。但是,如果您对这个方向感兴趣,有一篇论文详细介绍了 Clean 的 I/O 系统。

于 2010-10-03T16:15:13.570 回答
2

据我所知,如果你想在函数式语言中产生副作用,你必须明确地对它们进行编码。

于 2010-10-03T15:34:48.920 回答
0

由于副作用破坏了引用透明度,它们不违背函数式语言的观点吗?

这取决于功能语言:

  • 标准 ML允许像大多数过程语言(例如 Fortran、Algol、Pascal、C 等)一样自由使用副作用。

  • Haskell通过使用和等抽象数据类型来限制副作用IO,这有助于保持引用透明性。STSTM

  • Clean还限制了副作用,但它通过扩展类型系统做到了这一点。

  • Coq使用的函数式语言- Gallina -根本无法访问副作用


函数式语言如何模拟副作用?

一种不经常提及的方法依赖于伪数据:在可访问的结构化值(通常是树)中传达的单个一次性抽象值,只有在最初使用每个抽象值时才会出现副作用。有关更多信息,请参阅 F. Warren Burton 的Nondeterminism with Referential Transparency in Functional Programming Language。在 GHC 中也可以找到一个工作示例:它的Uniquename-suppy 类型。

于 2021-11-29T12:48:26.613 回答