abstract type Name end
typeof(Name)
DataType
司馬 博文
9/09/2020
A Blog Entry on Bayesian Computation by an Applied Mathematician
$$
$$
<:
, >:
は arity 2 の論理演算子にもなる.
関数宣言の際の型注釈にて,冠頭演算子としても使う.型変数に対するslicingである.従って,木構造の上でのslicingとなる(第 1.5.2 節).
複数の名前付き field をまとめて扱うことができる.
Julia で複合型を立てる時は,まるで構造付きの空間を作るようである.Euclid空間のように.
従って,データと method を統合する(=関数が複合型に所属する)OOP とは少し違い,複合型と,その上の関数を別々に作る.従って,Julia の関数は常 にfirst-class object として扱われる.1
imutable な複合型の変数はstruct
-end
ブロックで宣言する.
複合型を宣言すると,暗黙のうちに constructor が生成される.これも OOP と同じ.
mutable な複合型はmutable struct
-end
ブロックで宣言する.
直和型を表す,代数的データ型の簡単な場合.他の言語では Nullable, Option 型と呼ばれる.
Union{Int,String}
というように,タグUnion
をつけて表す.
function process(x::Union{Int, String})
if x isa Int
println("The integer is $x")
elseif x isa String
println("The string is $x")
end
end
process(3)
The integer is 3
Union{Int, Nothing}
とすると,部分関数の値域として使える.
他の言語では generics や template と呼ばれるものである.2
そもそもタグ付という表示方法自体が,タグを関数名と見れば,点を表しているように見える.その調子で,タグを固定し,型変数を導入すればいい.
Parametric 型は,{}
オブジェクトで定義する.試しに,Point
というパラメトリック型を定義する:
インスタンス化する際は,型変数 T
, U
にも代入をする.
Point{Int64, Float64}(3, 4.5)
パラメトリック型のデータに対して関数を定義する際は,型変数を使用した後に,where
を使って型変数を指定する.3
Point{T}
型に対して,型変数T
に代入を行って得る型Point{Int}
は concrete 型になり,Point{T}
という抽象型を親型に持つ.
従って,多重ディスパッチにおいてはPoint{Int}
はPoint{T}
にも match する.4
型変数を{}
演算子により持たせた Parametric 型は,持たせていない型の下流にある.
「持たせていない型」はUnionAll
という型になる.5
Julia では,型変数の間に包含関係があっても,一度 parametric になると包含関係は消える【不変】.これは主に実行効率性の理由による.
UnionAll
型はスライシングができる.
Number
は抽象型であり,Point{Number}
という表現はできない.
Point{<:Number}
には,Point{Int}
もマッチする:
SingletonType
:たった一つの型を含む自明な Parametric Typeキーワード Type
によって,Type{T}
の形で定義される.元の型 T
のインスタンスとなる.
更なる構造付きのものはDataStructure.jl
にある.
各直積型に,tagをつけてその性質を明示する.
Any直下の型 0. (a,b,…)::Tuple{T1,T2,…} 0. immutableである 0. Array型に対するsize関数の返り値はTuple型. 0. 可変長引数もTuple型のobjectとして受けられる. 0. 上記から観察されるように,入れ物であって,代数的構造を持たせることを意図していない.その場合はArrayを使う. 0. named tuple:Typeの直積. 0. 元々NamedTuple.jlという独立したpackageだったが,0.7から統合. 0. 要素に数字以外のaliasでタグ付できる.immutable. 0. (a=1, b=2)::NamedTuple{(:a, :b), Tuple(Int, Int)}などの記法で定義される. 0. つまり,値のTupleと,Symbol型のオブジェクトのTupleとの組で表される. ⁃ この時の射影が,keys関数,values関数として実装されている. 0. keyは.演算子でアクセスできる. • t.a 0. Symbolをindexの代わりに使える. • t[:a] 0. 一時的に使うのが普通で,本格的にはstruct, mutable structとして第一級の居住権を与えるのが良い. 0. List:Array{T,1}としての実装.Vector{T}というエイリアスもある. 0. 追加や削除などの順序的構造が重視されるCollection型. 0. スタック,キュー,両端キューはDataStructure.jlへ. ⁃ push!(List, object) -> List’ ⁃ 要素の末尾追加 ⁃ pushfirst!(List, object) -> List’ ⁃ 要素の先頭追加 ⁃ pop!(List) -> object ⁃ 要素の末尾摘出 ⁃ popfirst!(List) ⁃ insert!(List, n, object) -> List’ ⁃ n番目の位置に追加 ⁃ deleteat!(List, n) -> List’ ⁃ n番目の要素を削除. 0. 辞書:Dict{K, V}という直積型 0. constructorは • d = Dict{String, Int}() • d[“a”] = 1 • d = Dict(key => value, key => value, …) 0. constructorの{}内の要素を1つ,または全て省略するとAnyとしたのと等価. ⁃ haskey(Dict, key) -> Bool ⁃ Dict型objectに,所定のkeyが含まれているかを判定する. 0. built-inにIdDict型とWeakKeyDict型がある. 0. 集合:Set{T} 0. constructorは • s = Set([1,2]) 0. 即ち,1次元Arrayから生成される.というより,1次元Arrayにタグをつけたものである. 0. 実装は「keyのみを保持する辞書」というべきもので,辞書と同様,値の重複を無視する. ⁃ push!(set, object) ⁃ 値の追加. ⁃ union(set, List) ⁃ intersect(set, List) ⁃ issubset(List, List) -> ::Bool ⁃ List ⊂ List -> ::Bool ⁃ Set型のinstanceを生成することなく集合演算ができる. 0. 多次元配列:Array{T,n}.Matrix{T}はArray{T,2}のエイリアスである. 0. MATLABを踏襲している.NumPyとは所々違う. 0. NumPyは0からindexingし,row-major orderである.これは,行列のindexingにとって,辞書式順序になる. 0. しかしJuliaは1からindexingし,column-major orderである.後者は行列のindexingに沿って,第一要素のストライドが1になる. 0. 従って,Juliaは同じ行の要素の列挙が得意.線型代数のものの見方である. 0. 内部実装は結局一次元配列(List)であることを意識すると良い.
⁃ [] (constructor)
⁃ [ a b c; d e f; h i j ]
⁃ または改行を入れてもいい.
• []
• 要素へアクセスする作用素.
⁃ isempty(collection) -> Bool
⁃ empty!(collection) -> collection
⁃ 空にする
⁃ length(collection) -> Int
⁃ eltype(collection) -> Type
• 関数名の最後に!
• 引数の一部を変更・破棄する関数
• !のつかない関数は,引数に対する破壊的変更はないので安心して使用できる,という慣習.
• 例:push!,insert!
• sortは新たなobjectを返すが,sort!は引数そのものを変更してしまう.
• for文に使う構文はPythonと同じ使用感.
• しかし,直積型を意識.
• for (key, value) in d::Dict
• 実装は,iterable型オブジェクトを介して行われる.つまり,Juliaは次のように変換して処理される.速度の問題?
• next = iterate(collection)while next !== nothing (x,state) = next #suite next = iterate(collection, state)end
• Juliaはiterable型は無く,Tuple{Int, Int}である.
• 第一要素は,「次の要素」で,第二要素は「その次の要素」のindex(やそれに値するもの)を表す整数またはnothing.
• 従って,自作のcollection型にもfor文iterationを実現させるためには,iterate関数をディスパッチすれば良い.
作成 0. constructor 0. Array{T}(undef, dims…) 0. 値が初期化されていないことに注意. 0. collect(reshape(1:9, 3, 3)) 0. collectionから,要素を奪って配列に仕立て直す. 0. zeros([T,] dims…) 0. ones([T,] dims…) 0. fill(x, dims…) 0. 行列xI 0. fill!(A,x) 0. 配列AをxIにする. 0. rand([T,] dims…) 0. 一様分布でランダムに初期化した配列 0. 型を指定しないとFloat64で. 0. randn([T,] dims…) 0. 正規分布でランダムに初期化した配列 0. similar(A,[T,dims…]) 0. 配列Aと類似した配列を返す. 0. reshape(A, dims…) -> AbstractArray 0. 切り取る,または形を変える. 0. 並びはcolumn-major orderのままである. 0. AにはUnitRange型も許容されるのがすごい. 0. copy(A) 0. deepcopy(A) 0. Aの要素も再帰的にコピーする.
0. [A B]
0. 数学的記法の感覚で使える行列の接続.
0. view(A, n, m) -> view(::Array{T,n}, m, i)
0. n, mはindexingまたはslicing.
0. Aから部分配列を抜き出す.
0. 返るobjectはAへの参照とindexの情報を持っているので,Aを変更するとその部分配列も変わる.
0. この実装は,Aが巨大すぎる場合への配慮を感じる.
0. 「ただし,現在の計算機による配列のコピー操作は,一般に非常に高速であるため,巨大な配列を扱うのではない限り,サブ配列を作成するよりも,通常のindexingで新たな配列を作成してしまう方が高速であることも多い.この辺りは,実際に計測してパフォーマンスを確かめてみるのが良いだろう.」
属性 0. eltype(A) 0. length(A) 0. ndims(A) 0. size(A) 0. size(A,n) 0. n番目の次元におけるAのサイズ 0. size(A)で返ってくるtupleの第n要素. 0. strides(A) 0. Aのストライド. 0. 第一要素は必ず1になる. 0. 要素同士が,一番浅い意味での一次元配列上でどれくらい離れているか. 0. stride(A,n) 0. n番目の次元におけるAのストライド
0. [i, j, k, …]または[n:m, i:j, k:l, …]でindexingできる.
代数的構造 0. * 0. 行列乗算 dot付演算子:broadcasting.broadcast(+, A, B)のエイリアスである.broadcast!(+, A, B)とするとAが変更される. 0. component-wiseの演算. 0. A .+ c 0. A + cIと同じ. 0. column-wiseの演算. 0. A .+ B 0. BがAの繰り返し単位になっている場合のみ. 0. つまり,size(B)とsize(A)を各要素ごとに見比べたとき,次の2条件のいずれかを満たすとき. 0. 値が同じ 0. どちらかの値が1 0. 2つ目の条件として,pr_i(size(B)) | pr_i(size(A))だったらもっと使いやすかったがね. 0. broadcast関数 0. broadcast(f, args…)が定義. 0. f.(args…)とも記述できる. 0. ただし,f=+などの時には使えない.fは関数が想定されている. 0. sigmoid.(A)やexp.(A)などである. 0. argsはArrayに限らず,tupleでも良い.
位相的構造 0. map(f, c::collection…) -> collection 0. collection cにelement-wiseにfを適用させる. 0. broadcastingやdot演算と似ているが,fが匿名関数でない場合はdot演算を使うのが良い? 0. reduce(op, itr; [init]) -> obj 0. Aをitrableと見做して,要素ごとにopに突っ込んでいく. 0. 従って,次元が1段階下がる. 0. filter(f, a::collection) -> a’ 0. aを要素ごとにfに突っ込んで,fがfalseを返すものについては脱落させる.
この言葉は 1960 年代に Christopher Strachey によって “functions as first-class citizens” という文脈で初めて使われた。全ての機能を享受できる citizen 的な? ↩︎
Java の generics は Julia に似て不変であるが,C# の generics は in/out キーワードにより共変性をサポートしている.↩︎
where T <:Any
の略記↩︎
しかし,Julia の仕様は,多重ディスパッチにおいては concrete 型に近いものが先に適用されるようになっている.↩︎
意味論的にはそう,全ての型の和集合で,以降はTに代入するたびに同値類のいずれかを得る.↩︎