cen*_*980 4 haskell functional-programming side-effects
我正在学习函数式编程中的副作用(在 Haskell 中),我知道外部效果是在函数外部可观察到的效果,而内部效果从外部是不可见的。
为数据结构分配内存是一种纯粹的操作吗?副作用必须修改某些状态或与调用函数或外部世界进行可观察的交互。在分配数据结构的情况下,您必须调用一些函数(例如 malloc)为其分配内存。但是如果在一个函数内调用这些函数,这对于外部世界来说是不可见的。即使外部世界被修改(因为为数据结构分配了内存),我也不认为分配数据结构是一种副作用,因为它是不可观察的。
但是,我不确定我的推理是否正确。任何见解表示赞赏。
为数据结构分配内存是一种纯粹的操作吗?
在 Haskell 中,内存几乎从不由程序员直接分配。从这个意义上说,这个问题是没有实际意义的:分配内存既不是纯操作也不是不纯操作,因为分配内存不是一个操作,而是一个实现细节。换句话说,Haskell中的内存分配对于外部代码(或任何代码)是不可观察的,但这不是因为纯度,而是因为语言本身抽象了内存分配的概念。就 Haskell 代码本身而言,没有内存或内存分配之类的东西。
这很重要的原因是因为它允许编译器在不改变代码含义的情况下进行各种优化。例如,在 Haskell 中,当您对大型数据结构进行小的更改时,您实际上是在制作该结构的副本,而不是修改原始结构,这是非常低效的。但是,编译器通常可以判断是否需要结构的旧副本,如果不需要,它将编写机器代码来简单地修改原始结构。作为另一个例子,小的本地值可能被移动到 CPU 寄存器或系统堆栈,完全绕过这些值的分配。只要它不改变代码的作用,优化器就可以并且会以任何必要的方式打破纯度规则。区别在那个级别根本不重要。
在分配数据结构的情况下,您必须调用一些函数(例如 malloc)为其分配内存。但是如果这些函数在一个函数内被调用,这将不会被外界观察到。即使外部世界被修改(因为为数据结构分配了内存),我也不认为分配数据结构是一种副作用,因为它是不可观察的。
在某些情况下,内存分配操作可能会暴露给 Haskell 代码。例如,分配内存的 C 函数malloc可能会被 Haskell 绑定通过FFI调用。在这些情况下,绑定的作者需要决定函数是“纯”(类型应该返回一个纯值)还是“不纯”(类型应该返回一个IO动作)。这是我能想到的主要情况,这个问题的答案具有实用价值。
在这种情况下,需要关注的重要事项是:
如果两个答案都是“是”,则为纯函数,否则为不纯函数。这与 C 代码中发生了多少杂质无关,只要该杂质在函数外部不可见就可以了。
所以要真正回答你的问题:这取决于。
saymalloc被调用,然后在函数退出前释放内存。在函数运行过程中,已分配零净内存。所以函数是纯的。
Saymalloc被调用,并返回指向已分配内存的指针。这不是纯粹的,因为 Haskell 只知道指针,而不知道分配的内存本身。如果我们运行这个函数来分配一个 4 字节的块,然后我们再次运行它来分配另一个 4 字节的块,而 Haskell 认为该函数是纯函数,它可能会将第二次调用替换为第一个的结果(指针)调用,导致两个调用都返回指向同一个 4 字节块的指针(这不是你想要的)。因此,该函数必须键入为不纯的IO操作。
| 归档时间: |
|
| 查看次数: |
391 次 |
| 最近记录: |