Поиск…


Синтаксис

  • x -> [body]
  • (x, y) -> [body]
  • (xs ...) -> [body]

замечания

0.4.0

В более старых версиях Julia закрытие и анонимные функции имели ограничение производительности во время выполнения. Это наказание было отменено в 0,5.

Состав функции

Мы можем определить функцию для выполнения композиции функции с использованием анонимного синтаксиса функции :

f ∘ g = x -> f(g(x))

Обратите внимание, что это определение эквивалентно каждому из следующих определений:

∘(f, g) = x -> f(g(x))

или же

function ∘(f, g)
    x -> f(g(x))
end

напомнив, что в Julia f ∘ g является просто синтаксическим сахаром для ∘(f, g) .

Мы видим, что эта функция правильно составлена:

julia> double(x) = 2x
double (generic function with 1 method)

julia> triple(x) = 3x
triple (generic function with 1 method)

julia> const sextuple = double ∘ triple
(::#17) (generic function with 1 method)

julia> sextuple(1.5)
9.0
0.5.0

В версии v0.5 это определение очень показательно. Мы можем просмотреть созданный код LLVM:

julia> @code_llvm sextuple(1)

define i64 @"julia_#17_71238"(i64) #0 {
top:
  %1 = mul i64 %0, 6
  ret i64 %1
}

Ясно, что эти два умножения были сведены в одно умножение и что эта функция настолько эффективна, насколько это возможно.

Как работает эта функция более высокого порядка? Он создает так называемое замыкание , которое состоит не только из его кода, но и отслеживает определенные переменные из его области. Все функции в Julia, которые не созданы на уровне верхнего уровня, являются закрытием.

0.5.0

Можно проверить переменные, закрытые через поля замыкания. Например, мы видим, что:

julia> (sin ∘ cos).f
sin (generic function with 10 methods)

julia> (sin ∘ cos).g
cos (generic function with 10 methods)

Реализация каррирования

Одно применение закрытий - частично применить функцию; то есть предоставить некоторые аргументы и создать функцию, которая принимает остальные аргументы. Каррирование - это конкретная форма частичного применения.

Начнем с простой функции curry(f, x) , которая предоставит первый аргумент функции и ожидает дополнительных аргументов позже. Определение довольно просто:

curry(f, x) = (xs...) -> f(x, xs...)

Еще раз, мы используем синтаксис анонимных функций , на этот раз в сочетании с синтаксисом вариационных аргументов.

Мы можем реализовать некоторые базовые функции в молчаливом (или без точек) стиле, используя эту функцию curry .

julia> const double = curry(*, 2)
(::#19) (generic function with 1 method)

julia> double(10)
20

julia> const simon_says = curry(println, "Simon: ")
(::#19) (generic function with 1 method)

julia> simon_says("How are you?")
Simon: How are you?

Функции поддерживают ожидаемый генералитет:

julia> simon_says("I have ", 3, " arguments.")
Simon: I have 3 arguments.

julia> double([1, 2, 3])
3-element Array{Int64,1}:
 2
 4
 6

Введение в закрытие

Функции являются важной частью программирования Julia. Они могут быть определены непосредственно внутри модулей, и в этом случае функции называются верхним уровнем . Но функции также могут быть определены в рамках других функций. Такие функции называются « замыканиями ».

Замыкания фиксируют переменные в их внешней функции. Функция верхнего уровня может использовать только глобальные переменные из своего модуля, параметров функции или локальных переменных:

x = 0  # global
function toplevel(y)
    println("x = ", x, " is a global variable")
    println("y = ", y, " is a parameter")
    z = 2
    println("z = ", z, " is a local variable")
end

С другой стороны, закрытие может использовать все это в дополнение к переменным от внешних функций, которые он захватывает:

x = 0  # global
function toplevel(y)
    println("x = ", x, " is a global variable")
    println("y = ", y, " is a parameter")
    z = 2
    println("z = ", z, " is a local variable")

    function closure(v)
        println("v = ", v, " is a parameter")
        w = 3
        println("w = ", w, " is a local variable")
        println("x = ", x, " is a global variable")
        println("y = ", y, " is a closed variable (a parameter of the outer function)")
        println("z = ", z, " is a closed variable (a local of the outer function)")
    end
end

Если мы запустим c = toplevel(10) , мы увидим, что результат

julia> c = toplevel(10)
x = 0 is a global variable
y = 10 is a parameter
z = 2 is a local variable
(::closure) (generic function with 1 method)

Обратите внимание, что хвостовое выражение этой функции является самой функцией; то есть замыкание. Мы можем назвать замыкание c как и любую другую функцию:

julia> c(11)
v = 11 is a parameter
w = 3 is a local variable
x = 0 is a global variable
y = 10 is a closed variable (a parameter of the outer function)
z = 2 is a closed variable (a local of the outer function)

Обратите внимание, что c все еще имеет доступ к переменным y и z из вызова toplevel - даже если toplevel уже вернулся! Каждое закрытие, даже те, которые возвращаются одной и той же функцией, закрываются по разным переменным. Мы снова можем вызвать toplevel

julia> d = toplevel(20)
x = 0 is a global variable
y = 20 is a parameter
z = 2 is a local variable
(::closure) (generic function with 1 method)

julia> d(22)
v = 22 is a parameter
w = 3 is a local variable
x = 0 is a global variable
y = 20 is a closed variable (a parameter of the outer function)
z = 2 is a closed variable (a local of the outer function)

julia> c(22)
v = 22 is a parameter
w = 3 is a local variable
x = 0 is a global variable
y = 10 is a closed variable (a parameter of the outer function)
z = 2 is a closed variable (a local of the outer function)

Обратите внимание, что, несмотря на то, что d и c имеют одинаковый код и передаются одни и те же аргументы, их вывод отличается. Они являются отличными закрытиями.



Modified text is an extract of the original Stack Overflow Documentation
Лицензировано согласно CC BY-SA 3.0
Не связан с Stack Overflow