LoginSignup
7
3

More than 3 years have passed since last update.

Julia で多重ディスパッチするためのタイプシグネチャ

Last updated at Posted at 2020-02-22

この記事について

引数の型指定について、応用的なことをまとめる。

このあたりのことは、ドキュメントで散発的にしか出てこなかったり、直接的には書かれていなかったりするので、挙動やコードから推測しているところもある。

引数の型パラメータを指定する

Int64 <: Integer                              # true
Vector{Int64} <: Vector{Integer}              # false
Vector{Int64} <: Vector{T} where T<:Integer   # true

Vector{<:Integer} == Vector{T} where T<:Integer

f1(x::Vector{T}) where T<:Integer = x
f2(x::Vector{<:Integer}) = x
f1([1, 2]) # [1, 2]
f2([1, 2]) # [1, 2]

https://docs.julialang.org/en/v1/manual/methods/#Parametric-Methods-1
https://docs.julialang.org/en/v1/manual/types/#Parametric-Composite-Types-1

複合体の型パラメータのスーパータイプを指定する

関数の引数ではないけれど、私がよく混乱するところなので書き留めておく。

struct MyType{T<:Number}
    a :: T
end

MyType(3) # MyType{Int64}(3)

前節の書き方と混同してこのように間違えがちなのである。

Bad_example
struct MyType{T} where T<:Number
    a :: T
end
# ERROR: syntax: invalid type signature

型パラメータを省略する

# Array{T,N}
Array{Int} == Array{Int,N} where N
Array{Int,2} <: Array{Int} <: Array

型を作るときには、ここを考慮した上で型パラメータの順番を決めるとよいだろう。指定したい型パラメータを先に配置し、省略しそうな型パラメータを後にするのが便利である。

例外:タプルの型

タプルは関数引数の抽象化なので、ここまでの説明とは挙動が全く異なる。

# パラメータの包含関係が連鎖する (covariant)
Tuple{Int64} <: Tuple{Integer}     # true

# パラメータは省略できない(2引数と1引数は異なるメソッド)
Tuple{Int,String} <: Tuple{Int}   # false

可変長引数の型を指定する

Function parameters can also be used to constrain the number of arguments that may be supplied to a "varargs" function.

https://docs.julialang.org/en/v1/manual/functions/#Varargs-Functions-1
https://docs.julialang.org/en/v1/manual/types/#Vararg-Tuple-Types-1
https://docs.julialang.org/en/v1/manual/methods/#Parametrically-constrained-Varargs-methods-1

AbstractArray インターフェースで getindex を実装するときなど、引数の個数が N 個のとき、 Vararg{T,N} で指定できる。
https://docs.julialang.org/en/v1/manual/interfaces/#man-interface-array-1

# 等価な表現
f1(args::Int...) = args
f2(args::Vararg{Int}) = args

f1(1, 2) # (1, 2)
f2(1, 2) # (1, 2)
配列を複合体でラップする例
struct MyArray{T,N,A<:AbstractArray{T,N}} <: AbstractArray{T,N}
    arr :: A
end

Base.size(A::MyArray) = size(A.arr)
Base.getindex(A::MyArray, I::Vararg{Int}) = A.arr[I...]

MyArray(rand(10, 10))[3, 4]

追記: NTuple{N,T} と関係がある

Tuple{Vararg{Int,3}} == NTuple{3,Int}

型を引数にとる

T の型は Type{T} で指定できる。

typeof(Int64) # DataType
Int64 isa Type{Int64}

f1(typ::Type{Int64}) = typ
f1(Int64) # Int64

f2(typ::Type{T}) where T<:Integer = typ
f2(Int32) # Int32

UnionAllタイプを指定する
isa(AbstractVector, Type{AbstractArray{<:Any,N}} where N)
!isa(AbstractVector, Type{AbstractArray{T,<:Any}} where T)

Stylishな書き方
Type{>:Missing} == Type{Union{T,Missing}} where T

JuliaCon 2019 | What's Bad About Julia | Jeff Bezanson
https://www.youtube.com/watch?v=TPuJsgyu87U
14:00 ぐらい

7
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
3