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

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.

主站蜘蛛池模板: 宜黄县| 高平市| 监利县| 博野县| 萝北县| 巩义市| 即墨市| 古丈县| 通山县| 定陶县| 益阳市| 项城市| 揭西县| 遵义县| 丹棱县| 镇康县| 盈江县| 观塘区| 亚东县| 崇左市| 济源市| 东安县| 杨浦区| 北安市| 高陵县| 韶关市| 玛多县| 花垣县| 武川县| 峨眉山市| 赣州市| 清涧县| 潜山县| 六枝特区| 海宁市| 丰顺县| 诸城市| 武功县| 绥棱县| 镇远县| 旬阳县|