官术网_书友最值得收藏!

First-class functions and closures

In this section, we will demonstrate the power and flexibility of functions (example code can be found in Chapter 3\first_class.jl). Firstly, functions have their own type: Function. Functions can also be assigned to a variable by their name:

julia> m = mult  
julia> m(6, 6) #> 36

This is useful when working with anonymous functions, such as c = x -> x + 2, or as follows:

julia> plustwo = function (x) 
                     x + 2 
                 end 
(anonymous function) 
julia> plustwo(3) 
5 

Operators are just functions written with their arguments in an infix form; for example, x + y is equivalent to +(x, y). In fact, the first form is parsed to the second form when it is evaluated. We can confirm it in the REPL: +(3,4) returns 7 and typeof(+) returns Function.

A function can take a function (or multiple functions) as its argument, which calculates the numerical derivative of a function f; as defined in the following function:

function numerical_derivative(f, x, dx=0.01) 
    derivative = (f(x+dx) - f(x-dx))/(2*dx) 
    return derivative 
end 

The function can be called as numerical_derivative(f, 1, 0.001), passing an anonymous function f as an argument:

f = x -> 2x^2 + 30x + 9 
println(numerical_derivative(f, 1, 0.001)) #> 33.99999999999537  

A function can also return another function (or multiple functions) as its value. This is demonstrated in the following code, which calculates the derivative of a function (this is also a function):

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 

As we can see, both are excellent use cases for anonymous functions.

Here is an example of a counter function that returns (a tuple of) two anonymous functions:

function counter() 
    n = 0 
    () -> n += 1, () -> n = 0 
end 

We can assign the returned functions to variables:

  (addOne, reset) = counter() 

Notice that n is not defined outside the function:

julia> n 
ERROR: n not defined 

Then, when we call addOne repeatedly, we get the following output:

addOne() #=> 1 
addOne() #=> 2 
addOne() #=> 3 
reset()  #=> 0 

What we see is that, in the counter function, the variable n is captured in the anonymous functions. It can only be manipulated by the functions, addOne and reset. The two functions are said to be closed over the variable n and both have references to n. That's why they are called closures.

Currying (also called a partial application) is the technique of translating the evaluation of a function that takes multiple arguments (or a tuple of arguments) into evaluating a sequence of functions, each with a single argument. Here is an example of function currying:

function add(x) 
    return function f(y) 
        return x + y 
    end 
end 

The output returned is add (generic function with 1 method).

Calling this function with add(1)(2) returns 3. This example can be written more succinctly as add(x) = f(y) = x + y or, with an anonymous function, as add(x) = y -> x + y. Currying is especially useful when passing functions around, as we will see in the Map, filter, and list comprehensions section.

主站蜘蛛池模板: 平顶山市| 台州市| 方山县| 商都县| 长葛市| 卢湾区| 肇源县| 唐海县| 岳池县| 兴国县| 汤原县| 九龙坡区| 兴山县| 梅河口市| 甘泉县| 舞钢市| 襄汾县| 彝良县| 灯塔市| 桐柏县| 托里县| 潍坊市| 九龙坡区| 乌苏市| 天台县| 长岛县| 沧州市| 茂名市| 榆中县| 和林格尔县| 金阳县| 青海省| 无为县| 宜州市| 鹤庆县| 德昌县| 南雄市| 莱州市| 三门县| 斗六市| 乌恰县|