julia における関数の機微について調べてみた
versioninfo()
Julia Version 0.6.2 Commit d386e40 (2017-12-13 18:08 UTC) Platform Info: OS: Linux (x86_64-linux-gnu) CPU: Intel(R) Core(TM) i7-6600U CPU @ 2.60GHz WORD_SIZE: 64 BLAS: libopenblas (USE64BITINT DYNAMIC_ARCH NO_AFFINITY Haswell) LAPACK: libopenblas64_ LIBM: libopenlibm LLVM: libLLVM-3.9.1 (ORCJIT, skylake)
function func1(x)
sin(x) # return が無くても最後の式が返値になる
end
func1 (generic function with 1 method)
func1(x) = sin(x) # 同じシグネチャで再定義すると上書き可能
func1 (generic function with 1 method)
次の書き方でも func2 を定義できるけれど以下の相違がある
func2 = x -> sin(x)
(::#1) (generic function with 1 method)
func2 = func1
func1 (generic function with 1 method)
func2 = 1
1
関数名は const 扱いで上書きできない
func1 = x -> sin(x)
invalid redefinition of constant func1 Stacktrace: [1] include_string(::String, ::String) at ./loading.jl:522
const にすれば代入は不可能になるけど、関数自体は無名のまま
const func3 = x -> sin(x)
(::#5) (generic function with 1 method)
func2 = func3
(::#5) (generic function with 1 method)
無名関数は内部的に #数字 という名前(?)で管理されている?
知ってないと表示を見ても何のことだか分からない
println(x->x)
#7
x->x
(::#9) (generic function with 1 method)
引数やキーワード引数に ... を付けると、Tuple として受け取れる
function test(a, other... ; opt1=0, options...)
println("a=", a, ", other=", other)
println("opt1=", opt1, ", options=", options)
end
test (generic function with 1 method)
test(1, 2, 3, 4; opt1=1, opt2=2, opt3=3)
a=1, other=(2, 3, 4) opt1=1, options=Any[(:opt2, 2), (:opt3, 3)]
逆に、Tupleや配列に ... を付けて渡すと、展開して渡せる
test((1,2,3)...)
a=1, other=(2, 3) opt1=0, options=Any[]
test([1,2,3]...)
a=1, other=(2, 3) opt1=0, options=Any[]
test([1,2]...)
a=1, other=(2,) opt1=0, options=Any[]
あれ?これは正しいのか?
length((1,))
1
ああ、(1) だけだと数字の 1 と区別が付かないから、1要素の Tuple は後ろに , を付けてるのか。
test(1;[(:opt1, 1), (:opt2, 2)]...)
a=1, other=() opt1=1, options=Any[(:opt2, 2)]
ポリモーフィズム的な
test2(a::Int) = println("Int")
test2 (generic function with 1 method)
test2(s::String) = println("String")
test2 (generic function with 2 methods)
test2(1)
Int
test2("a")
String
test2(a::Number) = println("Number")
test2 (generic function with 3 methods)
test2(1.0)
Number
1 は Number でもあるが Int が採用される
test2(1)
Int
test2(a) = println("Any type")
test2 (generic function with 4 methods)
test2(true)
Number
ありゃ、Bool は Number なのか。。。
test2([])
Any type
test2(1.0)
Number
test2(1)
Int
可変引数関数ではない方が優先される
test2(a...) = println("Variable args of any type")
test2 (generic function with 5 methods)
test2(1)
Int
test2([])
Any type
可変引数でも型指定があればそちらが優先
test2(a::Array...) = print("Variable args of Array")
test2 (generic function with 6 methods)
test2([])
Variable args of Array
test2(:symbol)
Any type
test2(a, b=false) = println("With omittable b")
test2 (generic function with 7 methods)
test2(1)
Int
test2(:symbol)
With omittable b
どうしてそっちが呼ばれるの? → 答えは下の方に
test3(a) = println("Any type")
test3 (generic function with 1 method)
test3(a; option=false) = println("Any type with option")
test3 (generic function with 1 method)
2 methods にならない事に注意
test3(1)
Any type with option
これは、キーワード引数付きが優先されたのではなく後から書いたもので上書きされただけ
test3(a) = println("Any type")
test3 (generic function with 1 method)
test3(1)
Any type
test3(1, option=true)
Any type with option
ではなかった。
優先順位が変わっただけでキーワード引数付きも呼べている。
1 method と書かれている意味は何なのか???
test3(a; option2=false) = println("Any type with option2")
test3 (generic function with 1 method)
test3(1, option=true)
MethodError: no method matching test3(::Int64; option=true) Closest candidates are: test3(::Any; option2) at In[46]:1 got unsupported keyword argument "option" Stacktrace: [1] (::#kw##test3)(::Array{Any,1}, ::#test3, ::Int64) at ./<missing>:0 [2] include_string(::String, ::String) at ./loading.jl:522
test3(1, option2=true)
Any type with option2
キーワード引数無しとキーワード引数付きは別シグネチャだけど、異なる名前のキーワード付き同士は同一シグネチャなので、後から定義したもので上書きされてしまうということか。
test3(a; options...) = println("Any type with options")
test3 (generic function with 1 method)
test3(1, option2=true)
Any type with options
可変キーワード引数付きの優先度が高い?
test3(a; option2=false) = println("Any type with option2")
test3 (generic function with 1 method)
test3(1, option2=true)
Any type with option2
じゃなくて、後から定義されたものが優先されているだけ?
test3(1, option1=true)
MethodError: no method matching test3(::Int64; option1=true) Closest candidates are: test3(::Any; option2) at In[51]:1 got unsupported keyword argument "option1" Stacktrace: [1] (::#kw##test3)(::Array{Any,1}, ::#test3, ::Int64) at ./<missing>:0 [2] include_string(::String, ::String) at ./loading.jl:522
いやいや、上書きされてるや
指定キーワード付きと、可変キーワード付きは同一シグネチャとして、互いに上書き対象になってる
test4(a) = "only a"
test4(a, b=false) = "with omittable b"
test4 (generic function with 2 methods)
test4("which should be called?")
"with omittable b"
優先順位が同位なので、後から定義されたものが採用されてるわけだ
だからもう一度「後から」定義してやればそちらが優先される
test4(a) = "only a"
test4 (generic function with 2 methods)
test4("which should be called?")
"only a"
省略可能引数持ちとそうでないものとを両方定義するときは順番が重要と覚えよう
ちゃんとこっちも呼べる
test4(1, 2)
"with omittable b"