Szukaj…


Składnia

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

Uwagi

0.4.0

W starszych wersjach Julii zamknięcia i anonimowe funkcje powodowały spadek wydajności w czasie wykonywania. Kara została wyeliminowana w 0,5.

Skład funkcji

Możemy zdefiniować funkcję do wykonania kompozycji funkcji przy użyciu anonimowej składni funkcji :

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

Należy pamiętać, że ta definicja jest równoważna każdej z następujących definicji:

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

lub

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

przypominając, że u Julii f ∘ g to po prostu cukier składniowy dla ∘(f, g) .

Widzimy, że ta funkcja składa się poprawnie:

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

W wersji v0.5 ta definicja jest bardzo wydajna. Możemy przyjrzeć się wygenerowanemu kodowi LLVM:

julia> @code_llvm sextuple(1)

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

Oczywiste jest, że dwa mnożenia zostały złożone w jedno zwielokrotnienie i że ta funkcja jest tak wydajna, jak to możliwe.

Jak działa ta funkcja wyższego rzędu? Tworzy tak zwane zamknięcie , które składa się nie tylko z jego kodu, ale także śledzi niektóre zmienne z jego zakresu. Wszystkie funkcje w Julii, które nie są tworzone w zakresie najwyższego poziomu, są zamknięciami.

0,5.0

Można sprawdzić zmienne zamknięte przez pola zamknięcia. Na przykład widzimy, że:

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

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

Wdrażanie curry

Jednym z zastosowań zamknięć jest częściowe zastosowanie funkcji; to znaczy, podaj teraz kilka argumentów i utwórz funkcję, która pobierze pozostałe argumenty. Curry to szczególna forma częściowego zastosowania.

Zacznijmy od prostej funkcji curry(f, x) , która dostarczy pierwszy argument funkcji, i oczekujemy dodatkowych argumentów później. Definicja jest dość prosta:

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

Ponownie używamy anonimowej składni funkcji , tym razem w połączeniu ze składnią argumentów variadic.

Za pomocą tej funkcji curry możemy zaimplementować niektóre podstawowe funkcje w stylu cichym (lub bez punktów).

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?

Funkcje utrzymują oczekiwany generalizm:

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

Wprowadzenie do zamknięć

Funkcje są ważną częścią programowania Julii. Można je zdefiniować bezpośrednio w modułach, w którym to przypadku funkcje są określane jako najwyższego poziomu . Ale funkcje można również zdefiniować w ramach innych funkcji. Takie funkcje nazywane są „ zamknięciami ”.

Zamknięcia przechwytują zmienne w ich funkcji zewnętrznej. Funkcja najwyższego poziomu może używać tylko zmiennych globalnych z ich modułu, parametrów funkcji lub zmiennych lokalnych:

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

Z drugiej strony zamknięcie może wykorzystywać wszystkie oprócz zmiennych z funkcji zewnętrznych, które przechwytuje:

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

Jeśli uruchomimy c = toplevel(10) , zobaczymy, że wynik to

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)

Zauważ, że wyrażenie ogonowe tej funkcji jest funkcją samą w sobie; to jest zamknięcie. Możemy wywołać zamknięcie c tak, jakby to była każda inna funkcja:

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)

Zauważ, że c nadal ma dostęp do zmiennych y i z z toplevel rozmowy - mimo toplevel już wrócił! Każde zamknięcie, nawet te zwrócone przez tę samą funkcję, zamyka się przy różnych zmiennych. Możemy ponownie nazwać 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)

Zauważ, że pomimo tego, że d i c mają ten sam kod i przekazano te same argumenty, ich wynik jest inny. Są odrębnymi zamknięciami.



Modified text is an extract of the original Stack Overflow Documentation
Licencjonowany na podstawie CC BY-SA 3.0
Nie związany z Stack Overflow