Juliaの<br>多重ディスパッチ === > [name=phigasui] > [time=Sat, Nov 18, 2017] --- 自己紹介 ---- @phigasui a.k.a ガーシー phigasui.com ---- Julia, Python あたりが好き ---- 仕事ではPHP:shit: --- みなさん Juliaしてますか? ---- Julia - 数値計算向けに作られた高レベル、高パフォーマンスな動的プログラミング言語 - すばらしいコンパイラ、並列処理、高速な数値計算、学術計算のライブライ ---- なかでも**多重ディスパッチ**によってJuliaはささえられる --- 多重ディスパッチとは ---- 複数の引数の組み合わせで多重定義された関数のなかから 適したものをディスパッチ ---- 単一のディスパッチ ---- :snake: ```python >>> int(3).__add__(4) 7 >>> 3.5.__add__(4.5) 8.0 >>> 3.5.__add__(4) 7.5 ``` ---- ```julia // example julia> @which +(3, 4) +(x::T, y::T) where T<:Union{Int128, Int16, Int32, Int64, Int8, UInt128, UInt16, UInt32, UInt64, UInt8} in Base at int.jl:32 julia> @which +(3.5, 4.5) +(x::Float64, y::Float64) in Base at float.jl:375 julia> @which +(3.5, 4) +(x::Number, y::Number) in Base at promotion.jl:249 ``` ---- ```julia julia> methods(+) # 180 methods for generic function "+": +(x::Bool, z::Complex{Bool}) in Base at complex.jl:232 +(x::Bool, y::Bool) in Base at bool.jl:89 +(x::Bool) in Base at bool.jl:86 +(x::Bool, y::T) where T<:AbstractFloat in Base at bool.jl:96 +(x::Bool, z::Complex) in Base at complex.jl:239 +(a::Float16, b::Float16) in Base at float.jl:372 +(x::Float32, y::Float32) in Base at float.jl:374 +(x::Float64, y::Float64) in Base at float.jl:375 +(z::Complex{Bool}, x::Bool) in Base at complex.jl:233 +(z::Complex{Bool}, x::Real) in Base at complex.jl:247 #= 以下略 =# ``` --- 多重ディスパッチを支える技術 ---- Juliaの抽象型 ---- ```julia julia> typeof(1) # instance Int64 julia> supertype(Int64) # struct Signed julia> supertype(Signed) # abstruct type Integer julia> supertype(Integer) # abstruct type Real julia> supertype(Real) # abstruct type Number julia> supertype(Number) # abstruct type Any julia> supertype(Any) # abstruct type Any ``` ---- ![](http://hua-zhou.github.io/teaching/biostatm280-2017spring/slides/02-juliaintro/tree.png) --- たのしいJuliaの多重ディスパッチ ---- ```julia abstract type Shape end struct Rock <: Shape end struct Paper <: Shape end struct Scissors <: Shape end play(::Type{Paper}, ::Type{Rock}) = "Paper wins" play(::Type{Paper}, ::Type{Scissors}) = "Scissors wins" play(::Type{Rock}, ::Type{Scissors}) = "Rock wins" play(::Type{T}, ::Type{T}) where {T<: Shape} = "Tie, try again" play(a::Type{<:Shape}, b::Type{<:Shape}) = play(b, a) ``` [元記事: Rock–paper–scissors game in less than 10 lines of code](https://giordano.github.io/blog/2017-11-03-rock-paper-scissors/) ---- ```julia julia> play(Paper, Rock) "Paper wins" julia> play(Paper, Paper) "Tie, try again" julia> play(Rock, Paper) "Paper wins" ``` :ok_woman: ---- どれをディスパッチしておるか ```julia julia> @which play(Paper, Rock) play(::Type{Paper}, ::Type{Rock}) in Main at REPL[5]:1 # play(::Type{Paper}, ::Type{Rock}) = "Paper wins" julia> @which play(Paper, Paper) play(::Type{T}, ::Type{T}) where T<:Shape in Main at REPL[8]:1 # play(::Type{T}, ::Type{T}) where {T<: Shape} = "Tie, try again" julia> @which play(Rock, Paper) play(a::Type{#s1} where #s1<:Shape, b::Type{#s2} where #s2<:Shape) in Main at REPL[9]:1 # play(a::Type{<:Shape}, b::Type{<:Shape}) = play(b, a) ``` --- 順に追う ---- ```julia abstract type Shape end ``` :punch::v::hand: それぞれの抽象型の定義だけでも実現化であるが 親となる型を作っておくと後々楽 ---- ```julia struct Rock <: Shape end struct Paper <: Shape end struct Scissors <: Shape end ``` 親を継承して:punch::v::hand:それぞれの型をつくる ---- :ok_woman: ```julia struct Rock <: Shape end ↓ abstract type Rock <: Shape end ``` インスタンスで利用しないので抽象型で定義してもいける ---- じゃんけんの組み合わせは $$ {}_n C _r = \frac{n!}{(n-r)!r!} \\ {}_3C_2 = \frac{3!}{(3-2)!2!} = 3 $$ なので3つ関数を定義 ```julia play(::Type{Paper}, ::Type{Rock}) = "Paper wins" play(::Type{Paper}, ::Type{Scissors}) = "Scissors wins" play(::Type{Rock}, ::Type{Scissors}) = "Rock wins" ``` ---- :no_good: ```julia play(::Type{Paper}, ::Type{Rock}) = "Paper wins" ↓ play(::Paper, ::Rock) = "Paper wins" julia> play(Paper, Rock) ERROR: MethodError: no method matching play(::Type{Paper}, ::Type{Rock}) julia> play(Paper(), Rock()) "Paper wins" ``` DataTypeオブジェクトを引数に取る形にしておかねば インスタンスでないとディスパッチできぬ ---- おなじ型が来たらあいこ ```julia play(::Type{T}, ::Type{T}) where {T<: Shape} = "Tie, try again" ``` ---- 順序入れ替え ```julia play(a::Type{<:Shape}, b::Type{<:Shape}) = play(b, a) ``` ---- Juliaの多重ディスパッチでは引数の組み合わせで 一番近い型にディスパッチする ```julia play(Paper, Rock) ``` のときは ```julia play(::Type{Paper}, ::Type{Rock}) = "Paper wins" ``` がドンピシャ ---- ```julia play(Paper, Paper) ``` のときは ```julia play(::Type{T}, ::Type{T}) where {T<: Shape} = "Tie, try again" ``` がドンピシャ ---- ```julia play(Rock, Paper) ``` のときは そのままの型でははまらないので ```julia julia> subtypes(Shape) 3-element Array{Union{DataType, UnionAll},1}: Paper Rock Scissors ``` で当てはまる ```julia play(a::Type{<:Shape}, b::Type{<:Shape}) = play(b, a) ``` ---- ```julia play(Rock, Paper) = play(Paper, Rock) ``` になるため ```julia play(::Type{Paper}, ::Type{Rock}) = "Paper wins" ``` にドンピシャる --- 良いJuliaライフを
{"metaMigratedAt":"2023-06-14T14:57:55.988Z","metaMigratedFrom":"YAML","title":"Juliaの<br>多重ディスパッチ","breaks":true,"slideOptions":"{\"transition\":\"slide\",\"theme\":\"black\"}","contributors":"[]"}
    1053 views