高阶函数及闭包
【本文来源:(https://juliabook.josephjctang.com/content/ch3/first_class_function.html)】
在本节中,我们将展示Julia 函数的奇妙与灵活。首先,函数有自己的类型在REPL键入typeof(mult)
返回Function
。函数也可以被赋值给一个变量:
julia> m = mult
julia> m(6, 6) #> 36
这在匿名函数的使用过程中非常有用,如c = x -> x + 2
, 或:
julia> plustwo = function (x)
x + 2
end
(anonymous function)
julia> plustwo(3)
5
操作符也是一个函数,只是它写在两个参数中间而已,形如x + y
等价于 +(x, y)
。实际上,执行时第一种形式会被解析成第二种形式。我们可以在REPL确认 +(3, 4)
返回7 和 而typeof(+)
返回Function
。
一个函数的参数可以是另外一个函数 ( 或多个函数), 如后定义的一个函数计算另一个函数f
的梯度 :
function numerical_derivative(f, x, dx=0.01)
derivative = (f(x+dx) - f(x-dx))/(2*dx)
return derivative
end
上面这个函数就可以把匿名函数f
当作一个参数做如后调用numerical_derivative(f, 1, 0.001)
:
f = x -> 2x^2 + 30x + 9
println(numerical_derivative(f, 1, 0.001)) #> 33.99999999999537
函数的返回值也可以是另一个函数(或多个函数) 。如后代码中的函数返回值就是一个计算梯度的函数。
function derivative(f)
return function(x)
# pick a small value for h
h = x == 0 ? sqrt(eps(Float64)) : sqrt(eps(Float64)) * x
xph = x + h
dx = xph - x
f1 = f(xph) # evaluate f at x + h
f0 = f(x) # evaluate f at x
return (f1 - f0) / dx # divide by h
end
end
如我们所见,上面都是比较好的匿名函数的实例。而如后则是返回返回两个匿名函数的例子:
function counter()
n = 0
() -> n += 1, () -> n = 0
end
我们可以将返回的函数赋值给另外的变量:(addOne, reset) = counter()
;也注意到上例中n
是一个局部变量:
julia> n
ERROR: n not defined
当我们反复调用 addOne 时可见到如后结果:
addOne() #=> 1
addOne() #=> 2
addOne() #=> 3
reset() #=> 0
如我们所见,在counter
函数里 , 变量 n 只在匿名函数中使用,亦即只可在addOne
和reset
中操作。这两个函数都是封闭式的使用 n,这就是为什么叫这闭包 。
柯里化(Currying, 也称偏函数应用PF)是指:将一个多参数函数调用,变成一系列的单参数函数调用。下面是函数柯里化的例子:
function add(x)
return function f(y)
return x + y
end
end
上例输出将是add (generic function with 1 method)
。调用add(1)(2)
得3。上例可更简洁地写作add(x) = f(y) = x + y
。或者加入一个匿名函数 则为add(x) = y -> x + y
。传递函数时柯里化是非常有用的,后面讲解 Map, filters, list comprehensions 的章节也将用到。
PF. Partial Function ↩
网友评论