Julia Language
Verschlüsse
Suche…
Syntax
- x -> [Körper]
- (x, y) -> [Körper]
- (xs ...) -> [Körper]
Bemerkungen
In älteren Versionen von Julia hatten Schließungen und anonyme Funktionen einen Performance-Nachteil für die Laufzeit. Diese Strafe wurde in 0.5 eliminiert.
Funktionszusammensetzung
Wir können eine Funktion definieren, um die Funktionszusammenstellung mit anonymer Funktionssyntax durchzuführen:
f ∘ g = x -> f(g(x))
Beachten Sie, dass diese Definition den folgenden Definitionen entspricht:
∘(f, g) = x -> f(g(x))
oder
function ∘(f, g)
x -> f(g(x))
end
unter Hinweis darauf, dass in Julia f ∘ g
nur Syntaxzucker für ∘(f, g)
.
Wir können sehen, dass diese Funktion richtig komponiert:
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
In Version v0.5 ist diese Definition sehr performant. Wir können den erzeugten LLVM-Code untersuchen:
julia> @code_llvm sextuple(1)
define i64 @"julia_#17_71238"(i64) #0 {
top:
%1 = mul i64 %0, 6
ret i64 %1
}
Es ist klar, dass die beiden Multiplikationen zu einer einzigen Multiplikation zusammengefasst wurden und dass diese Funktion so effizient wie möglich ist.
Wie funktioniert diese Funktion höherer Ordnung? Es erstellt einen sogenannten Abschluss , der nicht nur aus dem Code besteht, sondern auch bestimmte Variablen aus ihrem Gültigkeitsbereich heraus verfolgt. Alle Funktionen in Julia, die nicht im Top-Level-Bereich erstellt werden, sind Schließungen.
Man kann die verschlossenen Variablen durch die Felder der Schließung überprüfen. Zum Beispiel sehen wir das:
julia> (sin ∘ cos).f
sin (generic function with 10 methods)
julia> (sin ∘ cos).g
cos (generic function with 10 methods)
Currying implementieren
Eine Anwendung von Verschlüssen ist die teilweise Anwendung einer Funktion; Geben Sie jetzt einige Argumente an und erstellen Sie eine Funktion, die die restlichen Argumente übernimmt. Currying ist eine spezifische Form der Teilanwendung.
Beginnen wir mit der einfachen Funktion curry(f, x)
, die das erste Argument für eine Funktion bereitstellt, und erwartet später weitere Argumente. Die Definition ist ziemlich einfach:
curry(f, x) = (xs...) -> f(x, xs...)
Wieder verwenden wir eine anonyme Funktionssyntax , diesmal in Kombination mit einer variadischen Argumentsyntax.
Mit dieser curry
Funktion können wir einige grundlegende Funktionen implizit (oder punktfrei) implementieren.
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?
Funktionen erhalten den erwarteten Generismus aufrecht:
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
Einführung in die Verschlüsse
Funktionen sind ein wichtiger Bestandteil der Julia-Programmierung. Sie können direkt in Modulen definiert werden. In diesem Fall werden die Funktionen als Top-Level bezeichnet . Funktionen können aber auch in anderen Funktionen definiert werden. Solche Funktionen werden " Schließungen " genannt.
Verschlüsse erfassen die Variablen in ihrer äußeren Funktion. Eine Funktion der obersten Ebene kann nur globale Variablen aus ihren Modul-, Funktionsparametern oder lokalen Variablen verwenden:
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
Ein Abschluss dagegen kann alle zusätzlich zu den Variablen der äußeren Funktionen verwenden, die er erfasst:
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
Wenn wir c = toplevel(10)
, sehen wir das Ergebnis
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)
Beachten Sie, dass der Endausdruck dieser Funktion eine Funktion an sich ist. das ist eine Schließung. Wir können die Schließung c
wie jede andere Funktion nennen:
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)
Beachten Sie, dass c
immer noch Zugriff auf die Variablen y
und z
aus dem Aufruf der toplevel
toplevel
hat - obwohl toplevel
bereits zurückgekehrt ist! Jeder Abschluss, auch der von derselben Funktion zurückgegebene, schließt verschiedene Variablen. Wir können wieder toplevel
anrufen
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)
Beachten Sie, dass, obwohl d
und c
denselben Code haben und dieselben Argumente übergeben werden, deren Ausgabe unterschiedlich ist. Sie sind unterschiedliche Verschlüsse.