【问题标题】:What counts as a side-effect? Why isn't memory allocation a side-effect?什么算作副作用?为什么内存分配不是副作用?
【发布时间】:2017-04-15 03:19:08
【问题描述】:

我了解 Haskell 等纯函数式语言的吸引力,您可以在其中使用 monad 跟踪磁盘 I/O 等副作用。

为什么不是所有的系统调用都被视为副作用?例如,不会跟踪 Haskell 中的堆内存分配(这是自动的)。堆栈分配可能是一个副作用,尽管我不确定它是否有用。这两者都会改变系统的整体状态。

那么,什么是副作用,什么不是?仅仅是最“有用”的东西吗?还是有更理论的基础?

【问题讨论】:

  • 我认为最简单的答案是,如果分配是一种副作用,那么很少有东西是“纯粹的”,这会降低这个概念的实用性。纯度没有一个普遍的严格定义。我可以想象一种语言确实将分配视为一种副作用并通过类型系统对其进行管理,这在具有少量内存的系统(即嵌入式系统)上可能非常有用,但我不'目前不知道任何这样的语言。
  • 内存分配是一个副作用,如果你想控制它何时发生。请参阅 IORef/STRef/FunPtr 包装器。只是如果它是自动发生的,那么您可以相信您的编译器对此很聪明,因此 Haskell 不会强迫您担心它。
  • @AlexisKing 作为一个偶尔需要为嵌入式系统编写代码的人,这将是一种非常有趣的语言。我想它可以在 Haskell 中编写为 DSL,但作为一种编译效率很高的独立语言会很酷。
  • 您无法检测到的不存在。你调用一个函数,你如何检测它是否分配了内存?
  • 你会想看看this discussion - 答案是“因为我们不在乎”。是的,将两个不同内存位置中的相同值视为彼此不同是没有用的。

标签: haskell functional-programming monads side-effects


【解决方案1】:

在对这些事情进行推理时,必须在理论层面和语言规范层面进行推理,而不是在硬件上实际进行推理。

编程语言并不是真正的实际实现,因此除非您考虑将内存分配和系统调用作为语言的一部分的 C og C++,否则由系统原语处理的高级语言不是它的一部分语言。如果它不是语言的一部分,它就不会是副作用。

现在实际实现的机器代码永远不会是纯粹的,因为传递参数和接收返回值的方式是通过突变存储在寄存器或堆栈中。我们在所有现代编程中使用的大多数概念都被转化为算术、标志、跳转和内存访问。除了 NOP 之外,每条 CPU 指令都会改变机器。只包含 NOP 的程序不是很有用。

【讨论】:

  • 所有好的答案,我想我将 Haskell 的规范与其实现混淆了。谢谢。现在我想知道是否有任何低级汇编/C 类语言为分配等内容指定副作用语义。
  • CPU 指令评估也有硬件实现,因此可以说 NOP(同样无益)改变指令指针寄存器。
  • @thatotherguy 是的,但是除了 NOP 之外的每条指令也会改变程序计数器以外的东西。
  • 你可能想看看 Rust,它有一个静态检查的分配内存“所有权”模型。
【解决方案2】:

堆栈分配和堆分配都不是您可以在 Haskell 中“做”或观察的事情。因此,它不能算作副作用。从某种意义上说,CPU 升温也是如此,这无疑是运行纯 Haskel 代码的一种可识别的物理效应。

碰巧在现代硬件和操作系统上的某些 Haskell 实现会在运行您的代码的过程中分配堆栈/堆,但从您的代码中无法观察到。

【讨论】:

  • “碰巧在现代硬件和操作系统上的某些 Haskell 实现将在运行代码的过程中分配堆栈/堆” - 以及如何分配!
猜你喜欢
  • 2010-11-07
  • 1970-01-01
  • 1970-01-01
  • 2011-07-21
  • 2021-04-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多