为什么原位突变用“IO”表示?

Why is in-place mutation represented with `IO`?

提问人:joel 提问时间:11/17/2023 最后编辑:K. A. Buhrjoel 更新时间:11/17/2023 访问量:127

问:

为什么在函数式语言中使用可变数据结构和其他可变性来表示?例如,我正在查看 Haskell 的 IORef 或 Idris 的 IOArrayIO

我不认为这是一个历史或设计问题。我不太明白为什么适合突变——或者更确切地说,为什么突变在封装时变得纯粹。IOIO

Haskell 函数式编程 语言不可知突变 就地

评论

0赞 Alexei Levenkov 11/17/2023
这很可能更适合 langdev.stackexchange.comsoftwareengineering.stackexchange.com......历史/设计问题通常被认为对 SO 来说过于宽泛。
0赞 joel 11/17/2023
@AlexeiLevenkov谢谢。我不认为我的意思是历史或设计问题。我不太明白为什么适合突变——或者更确切地说,为什么突变在封装时变得纯粹。历史/设计表明,在这件事上也有一个选择,我不知道IOIO
0赞 that other guy 11/17/2023
从用户的角度来看,没有突变。如果你有 a 和 a,那么你无疑可以创建一个接受和输出的函数。这是否意味着有副作用?不。这是否意味着每次都返回不同的值?不。但是,如果你创建了一个列表,你仍然可以以某种方式进行某种程序,就好像你有可变状态一样。单子基本上是创建(可能是无限的)此类步骤序列的奇特方法。data Op = Assign Int | Outputprogram = [Assign 1, Assign 2, Output, Assign 42, Output]program[2,42]Assign 2Output
0赞 K. A. Buhr 11/17/2023
@joel,我认为您的后续评论是理解您在这里提出的问题的关键,因此我将其复制到您的问题中。

答:

4赞 leftaroundabout 11/17/2023 #1

您不需要用 .可以在 ST 中执行它们。但是你显然可以用 来表示它们,在那里可以实现任何肮脏的副作用。因此,如果你无论如何都在工作,最简单的方法是在那里进行突变,这样你就不需要担心将不同的单子焊接在一起。如果您还没有在 中工作,则应使用 但是。IOIOIOIOST

评论

0赞 joel 11/17/2023
我熟悉假装用状态单子改变变量,但从文档来看,这主要是一个“突变”单子。它与编译为就地突变的状态单子有什么不同吗?ST
0赞 K. A. Buhr 11/17/2023
是的,这是不同的。monad 支持改变内存位置的编译器原语(参见 代码 )。据我所知,monad 永远不会被编译为在内存中改变状态的代码,至少在 GHC 中不会。最好将其视为“真正的”突变,使用 = + I/O 操作。STSTRefStateSTIOST
0赞 Daniel Wagner 11/17/2023
@joel 尝试实现 using 而不是 (即 ),你会发现它们确实有很大不同。newSTRefStateSTnewStateRef :: YourChoiceOfContextIDon'tMind s => State s (StateRef a)
0赞 Ben 11/17/2023
@joel 特别是,即使某些计算有时被优化为通过突变来执行,这几乎是偶然的。API 只处理值,事实上,早期的状态值在“更改”后仍然有引用是相当有效的,所以它显然不能总是作为突变实现。 有一个显式处理对可变存储的引用的 API;你指定突变,它们不是优化的偶然结果。StateStateST
0赞 joel 11/18/2023
知道这一点非常有用。我一直以为人们在谈论状态时提到,给定吃。我实际上可以在我的工作中做到这一点STSTST
1赞 HTNW 11/18/2023
@joel 实施细节。你不能(或不应该)实际执行 IO。 应该是一个纯函数。STrunST