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":"[]"}