Julia Language
閉鎖
サーチ…
構文
- x - > [body]
- (x、y) - > [body]
- (xs ...) - > [body]
備考
古いバージョンの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)
は∘(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
バージョンv0.5では、この定義は非常に優れています。生成されたLLVMコードを調べることができます。
julia> @code_llvm sextuple(1)
define i64 @"julia_#17_71238"(i64) #0 {
top:
%1 = mul i64 %0, 6
ret i64 %1
}
2つの乗算が単一の乗算に折り畳まれ、この関数は可能な限り効率的であることは明らかである。
この高次関数はどのように機能しますか?これは、コードだけでなく、その範囲から特定の変数を追跡する、いわゆるクロージャを作成します。 Juliaのトップレベルのスコープで作成されていないすべての関数はクロージャです。
クロージャのフィールドを通して閉じられた変数を検査することができます。たとえば、次のようになります。
julia> (sin ∘ cos).f
sin (generic function with 10 methods)
julia> (sin ∘ cos).g
cos (generic function with 10 methods)
カレー化の実装
クロージャの1つのアプリケーションは、関数を部分的に適用することです。つまり、いくつかの引数を提供し、残りの引数をとる関数を作成します。 カレー化は、部分的な適用の特定の形態である。
最初の引数を関数に提供する単純な関数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
クロージャーの紹介
機能はジュリアプログラミングの重要な部分です。モジュール内で直接定義することができます。この場合、関数はトップレベルと呼ばれます 。しかし、関数は他の関数内で定義することもできます。そのような機能は「 クロージャ 」と呼ばれます。
クロージャは、外部関数内の変数を取得します。トップレベル関数は、モジュール、関数パラメータ、またはローカル変数からのグローバル変数のみを使用できます。
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)
toplevel
がすでに返っていたとしても、 c
まだtoplevel
コールからの変数y
とz
アクセスできることに注意してください!各クロージャは、同じ関数によって返されたクロージャであっても、異なる変数で終了します。もう一度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
が同じコードを持ち、同じ引数が渡されているにもかかわらず、それらの出力は異なっていることに注意してください。彼らは明確なクロージャーです。