Functional programming 函数式编程:映射是连续的吗?对关闭的影响

Functional programming 函数式编程:映射是连续的吗?对关闭的影响,functional-programming,closures,julia,higher-order-functions,Functional Programming,Closures,Julia,Higher Order Functions,我将用朱莉娅来说明: 假设我有一个函数counter(),它是一个闭包 function mycl()

我将用朱莉娅来说明:

假设我有一个函数counter(),它是一个闭包

function mycl()                                                                                                                                                                                                    
        state=0                                                                                                                                                                                                    
        function counter()                                                                                                                                                                                         
                state=state+1                                                                                                                                                                                      
        end                                                                                                                                                                                                        
end  
现在假设我创建函数mycoutner:

mycounter=mycl()
现在把这个函数映射到一个长度为10的数组上,所有元素都是1

map(x->x+mycounter(),ones(1:10))
结果如下:

julia> map(x->x+mycounter(),ones(1:10))
10-element Array{Int64,1}:
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
函数似乎按顺序应用于要映射的数组


最终,我试图避免for循环,但对于闭包变异状态的局部状态变量,我需要按顺序应用它。似乎是这样的,这是采用的标准吗?(尚未使用*apply测试等效的R版本)。这真的是“功能性”的吗?因为局部状态变量正在变异?

首先回答第二个问题,不,您的代码不是纯功能性的,因为它会变异状态

至于第一个问题,这取决于每种语言。在Scheme中,表示“[t]映射过程将
proc
元素应用于元素
,并按顺序返回结果列表”(第51页,我强调),其中“顺序”指的是列表的顺序还是列表元素的顺序(可能是前者),似乎有些模糊。在OCaml中,表示
List.map
“将函数
f
应用于
a1
,…,
an
,并使用
f
返回的结果构建列表
[fa1;…;fan]
。”这也是不明确的,但是它是使用
let
作为
a::l->let r=fa在r::map f l
中显式地顺序写入的
map
的当前Julia实现确实按顺序将其函数参数应用于其集合参数,尽管这不是一个明确记录的功能。将来,当多线程成为一种非实验性的语言特性时,计算顺序可能会改变,但如果没有警告,这种情况是不会发生的。它也可能不是通过改变
map
的行为来实现的,而是作为一种选择加入功能(例如通过
tmap
实现“线程映射”),或者在编译器知道被映射的函数是纯函数的情况下作为一种优化“累加映射”,它避免状态,而不是线程化累加参数。例如,请参见各种实现


这个函数在Julia中实现起来也相当简单,尽管可以说for循环更合适。在任何情况下,带有单个可变状态变量的for循环都比使用带有突变状态闭包的高阶函数要好得多,因为在前者中,突变是明显且包含的,而在后者在调用
map
函数时,突变不清楚。

map就是这种情况。如果您尝试使用pmap,您将看到您的输出类似于[2 2 2 3 3 4]等等,这取决于您定义的进程数。是的,如果您的函数具有状态,则它不起作用,并且在这种情况下,输出是完全不可预测的。您应该使用
reduce
/
fold
(Julia中的任何名称)对于需要按顺序完成的事情,而不是
map
map
的目的是创建一个新的容器,而不是执行副作用。有一个
pmap
函数就是这样做的,所以我认为这是一个合理的假设,map总是按顺序进行的。如果还没有,我会非常惊讶对纯函数的优化,因为检查非常简单。
pmap
函数用于分布式并行映射,而不是当前进程中的线程映射。(当然,可能两者都需要,但这是未来的API设计问题。)没有优化可以跨多个线程运行纯函数,因为在主线程以外的线程中运行Julia代码仍然是一项实验性功能(尽管它越来越稳定)未指定
proc
应用于
列表
s元素的动态顺序。”