对调用者看起来纯粹但在内部使用突变的函数 [英] Functions that look pure to callers but internally use mutation

查看:119
本文介绍了对调用者看起来纯粹但在内部使用突变的函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述


例如,在必要时,您可以

开始时分配的私有数据
结构使用副作用算法,然后在返回$之前丢弃这些
数据结构b $ b结果;那么总体结果是
有效地是一个无副作用的
函数。从F#库中分离
的一个例子是库的
实现List.map,它在内部使用
突变;写入在
内部结构中发生
,没有其他代码可以
访问。



<现在,这种方法的优势显然是性能。我只是好奇,是否有任何缺点 - 在这里可以带来哪些副作用?换句话说,如果把性能放在一边,那么实现 List.map 以纯粹的方式?



(显然这与F#特别有关,但我也对一般的哲学感兴趣)



(我能想到的唯一不利因素是,当人类看到这样的局部变化时,他们必须推断它是否可以逃脱。在F#中,局部变量(关闭不能捕获可变数据),所以唯一潜在的精神税来自推理可变引用类型。)



总结:使用效果很好,只要说服自己说这种影响只发生在非逃避的当地人身上很简单。 (也可以在其他情况下使用效果,但我忽略了其他情况,因为在这个问题上 - 线程我们是开明的函数式程序员,只要合理就试图避开效果。))



(如果你想深入,本地特效,如实现F#的List.map中的特效,不仅是并行性的障碍,而且实际上也是一个好处,从认为更高效的实施分配更少,因此对GC共享资源的压力更小。)


I just got my copy of Expert F# 2.0 and came across this statement, which somewhat surprised me:

For example, when necessary, you can use side effects on private data structures allocated at the start of an algorithm and then discard these data structures before returning a result; the overall result is then effectively a side-effect-free function. One example of separation from the F# library is the library's implementation of List.map, which uses mutation internally; the writes occur on an internal, separated data structure that no other code can access.

Now, obviously the advantage to this approach is performance. I'm just curious if there are any disadvantages--do any of the pitfalls that can come with side-effects apply here? Is parallelisibility affected?

In other words, if performance were set aside, would it be preferable to implement List.map in a pure way?

(Obviously this deals with F# in particular, but I'm also curious about general philosophy)

解决方案

I think nearly every disadvantage of side-effects is tied to "interaction with other portions of the program". Side-effects themselves aren't bad (as @Gabe says, even a pure functional program is constantly mutating RAM), it's the common-side-consequences of effects (non-local interactions) which cause problems (with debugging/performance/understandability/etc.). So effects on purely local state (e.g. on a local variable that does not escape) are fine.

(The only detriment I can think of is that, when a human sees such a local mutable, they have to reason about whether it can escape. In F#, local mutables can never escape (closures cannot capture mutables), so the only potential "mental tax" comes from reasoning about mutable reference types.)

Summary: it's fine to use effects, so long as it's simple to convince one's self that the effects only happen on non-escaping locals. (It's also ok to use effects in other cases, but I'm ignoring those other cases, since on this question-thread we are the enlightened functional programmers trying to eschew effects whenever it's reasonable. :) )

(If you want to go very deep, local effects, like those in the implementation of F#'s List.map, are not only a non-hindrance to parallelizability, but actually a benefit, from the point of view that the more-efficient implementation allocates less, and thus is less of a strain on the shared resource of the GC.)

这篇关于对调用者看起来纯粹但在内部使用突变的函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆