我正在学习函数式编程中的副作用(在Haskell中),并且我知道外部效果是在函数外部可以观察到的效果,而内部效果从外部看不到。
为数据结构分配内存是纯操作吗?副作用必须修改某些状态或与调用函数或外界发生可观察的交互。在分配数据结构的情况下,您将必须调用某些函数(例如malloc)来为其分配内存。但是,如果在一个函数中调用这些函数,那么外部世界将无法观察到。即使外部世界被修改了(因为为数据结构分配了内存),我也不认为分配数据结构是副作用,因为它是不可观察的。
但是,我不确定我的推理是否正确。任何见解都会受到赞赏。
答案 0 :(得分:3)
为数据结构分配内存是纯操作吗?
在Haskell中,程序员几乎从不直接分配内存。从这个意义上讲,这个问题是没有意义的:分配内存既不是纯操作也不是不纯正的操作,因为分配内存不是不是操作,而是一个实现细节。换句话说,Haskell 中的内存分配对于外部代码(或任何代码)来说是不可观察的,但这不是 的原因,因为它是纯净的,这是因为语言本身是抽象的在内存分配的概念上。就Haskell代码本身而言,没有诸如内存或内存分配之类的东西。
之所以如此重要,是因为它允许编译器在不改变代码含义的情况下进行各种优化。例如,在Haskell中,当对大型数据结构进行小的更改时,实际上是在复制结构而不是修改原始数据,这效率非常低。但是,编译器通常可以告诉您是否需要该结构的旧副本,如果不需要,它将编写仅修改原始结构的机器代码。作为另一个示例,较小的局部值可以移动到CPU寄存器或系统堆栈中,从而完全绕过这些值的分配。只要不改变代码的作用,优化器就可以并且会以任何必要的方式破坏纯度规则。在那个级别上,区别根本不重要。
在分配数据结构的情况下,您必须调用某些函数(例如malloc)为其分配内存。但是,如果在一个函数中调用这些函数,那么外部世界将无法观察到。即使外部世界被修改了(因为为数据结构分配了内存),我也不认为分配数据结构是副作用,因为它是不可观察的。
在某些情况下,内存分配操作可能会暴露于Haskell代码。例如,Haskell绑定可以通过FFI调用使用malloc
分配内存的C函数。在这些情况下,绑定的作者需要确定函数是“纯”(类型应返回纯值)还是“不纯”(类型应返回IO
操作)。这是我可以想到的主要情况,该问题的答案在实用上很有价值。
在这种情况下,要注意的重要事项是:
如果两个答案都为“是”,则这是一个纯函数,否则不纯。不管C代码中发生了多少杂质,只要该杂质在函数外部不可见就可以了。
所以要真正回答您的问题:这取决于。
说malloc
,然后在函数退出之前释放内存。在此功能过程中,已分配了零个净内存。因此该函数是纯函数。
说malloc
,并返回指向已分配内存的指针。 不是纯粹的,因为Haskell只知道指针,而不知道分配的内存本身。如果我们运行此函数以分配一个4字节的块,然后再次运行它以分配另一个4字节的块,并且Haskell认为该函数是纯函数,则可以用第一个调用的结果(指针)替换第二个调用调用,导致两个调用都返回指向相同4字节块的指针(这不是您想要的)。因此,必须将函数键入为不纯的IO
操作。
答案 1 :(得分:2)
将绑定设为s被认为是纯值,但是生成的机器代码将覆盖内存来这样做。因此,问题是您是在显式分配还是在设置一个值,让编译器执行分配。
答案 2 :(得分:-1)
通过分配,您可以修改外界的状态,从而产生副作用