Julia Language
sluitingen
Zoeken…
Syntaxis
- x -> [body]
- (x, y) -> [body]
- (xs ...) -> [body]
Opmerkingen
In oudere versies van Julia hadden sluitingen en anonieme functies een uitvoeringsduurstraf. Deze boete is geëlimineerd in 0,5.
Functie samenstelling
We kunnen definiëren van een functie uit te voeren functie samenstelling met behulp van anonieme syntaxis van de functie :
f ∘ g = x -> f(g(x))
Merk op dat deze definitie equivalent is aan elk van de volgende definities:
∘(f, g) = x -> f(g(x))
of
function ∘(f, g)
x -> f(g(x))
end
herinnerend aan het feit dat f ∘ g
in Julia gewoon syntaxisuiker is voor ∘(f, g)
.
We kunnen zien dat deze functie correct is samengesteld:
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 versie v0.5 is deze definitie zeer performant. We kunnen de gegenereerde LLVM-code bekijken:
julia> @code_llvm sextuple(1)
define i64 @"julia_#17_71238"(i64) #0 {
top:
%1 = mul i64 %0, 6
ret i64 %1
}
Het is duidelijk dat de twee vermenigvuldigingen zijn samengevouwen tot een enkele vermenigvuldiging en dat deze functie zo efficiënt mogelijk is.
Hoe werkt deze hogere orde functie? Het creëert een zogenaamde afsluiting , die niet alleen uit de code bestaat, maar ook bepaalde variabelen uit het bereik houdt. Alle functies in Julia die niet op het hoogste niveau zijn gemaakt, zijn sluitingen.
Men kan de gesloten variabelen door de velden van de sluiting inspecteren. We zien bijvoorbeeld dat:
julia> (sin ∘ cos).f
sin (generic function with 10 methods)
julia> (sin ∘ cos).g
cos (generic function with 10 methods)
Curry implementeren
Een toepassing van sluitingen is om een functie gedeeltelijk toe te passen; dat wil zeggen, geef nu enkele argumenten en maak een functie die de resterende argumenten overneemt. Currying is een specifieke vorm van gedeeltelijke toepassing.
Laten we beginnen met de eenvoudige functie curry(f, x)
die het eerste argument voor een functie levert en later aanvullende argumenten verwachten. De definitie is vrij eenvoudig:
curry(f, x) = (xs...) -> f(x, xs...)
We gebruiken opnieuw de syntaxis van de anonieme functie , dit keer in combinatie met de syntaxis van variadische argumenten.
We kunnen enkele basisfuncties in stilzwijgende (of puntloze) stijl implementeren met behulp van deze 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?
Functies handhaven het verwachte generisme:
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
Inleiding tot sluitingen
Functies zijn een belangrijk onderdeel van de programmering van Julia. Ze kunnen direct binnen modules worden gedefinieerd, in welk geval de functies topniveau worden genoemd . Maar functies kunnen ook worden gedefinieerd binnen andere functies. Dergelijke functies worden " sluitingen " genoemd.
Bij sluitingen worden de variabelen in hun uiterlijke functie vastgelegd. Een functie op het hoogste niveau kan alleen globale variabelen uit hun module, functieparameters of lokale variabelen gebruiken:
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
Een sluiting, aan de andere kant, kan al deze gebruiken naast variabelen van externe functies die het vastlegt:
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
Als we c = toplevel(10)
, zien we dat het resultaat is
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)
Merk op dat de staartuitdrukking van deze functie een functie op zichzelf is; dat wil zeggen een sluiting. We kunnen de sluiting c
noemen alsof het een andere functie was:
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)
Merk op dat c
nog steeds toegang heeft tot de variabelen y
en z
vanuit de toplevel
aanroep - ook al is toplevel
al terug! Elke sluiting, zelfs die teruggegeven door dezelfde functie, sluit over verschillende variabelen. We kunnen weer toplevel
bellen
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)
Merk op dat, ondanks dat d
en c
dezelfde code hebben en dezelfde argumenten krijgen, hun uitvoer anders is. Het zijn verschillende sluitingen.