{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"このチュートリアルはJuliaの機能を最速で学ぶためのものです。\n",
"Juliaは科学技術計算を得意とするプログラミング言語で、スクリプト言語のように手軽に書くことができるのにC言語やFortranにも負けない実行速度を誇ります。\n",
"文法や機能はPythonなど他のスクリプト言語とかなり共通しているので、別のプログラミング言語の知識があれば基本的な機能はすぐに習得できるでしょう。\n",
"\n",
"他のスクリプト言語と比較した、Juliaの特異な点をいくつか挙げてみると、\n",
"\n",
"* コンパイル言語に比肩する実行速度\n",
"* シンプルな言語機能と豊富な標準ライブラリ\n",
"* 引数の型により実行される関数が決まる動的ディスパッチ\n",
"* Lispのような強力なマクロ機能\n",
"\n",
"というようなものが挙げられます。\n",
"それゆえ、今までのようにパフォーマンスが必要な部分をC言語など他の言語で書く必要はなく、すべてJuliaで書けます。\n",
"実際、文字列を含むJuliaの標準ライブラリはほとんどJuliaで書かれており、十分なパフォーマンスを持ちます。\n",
"\n",
"\n",
"ここで使用するJuliaのバージョンは2018年9月の最新版であるv1.0(もしくはv0.7)です。\n",
"それでは、早速Juliaを学んでいきましょう!"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Juliaの文法"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"まずはJuliaのコードをざっと見てみましょう。配列をソートするクイックソートのコードです。"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"partition (generic function with 1 method)"
]
},
"execution_count": 1,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"quicksort(xs) = quicksort!(copy(xs))\n",
"quicksort!(xs) = quicksort!(xs, 1, length(xs))\n",
"\n",
"function quicksort!(xs, lo, hi)\n",
" if lo < hi\n",
" p = partition(xs, lo, hi)\n",
" quicksort!(xs, lo, p - 1)\n",
" quicksort!(xs, p + 1, hi)\n",
" end\n",
" return xs\n",
"end\n",
"\n",
"function partition(xs, lo, hi)\n",
" pivot = div(lo + hi, 2)\n",
" pvalue = xs[pivot]\n",
" xs[pivot], xs[hi] = xs[hi], xs[pivot]\n",
" j = lo\n",
" @inbounds for i in lo:hi-1\n",
" if xs[i] <= pvalue\n",
" xs[i], xs[j] = xs[j], xs[i]\n",
" j += 1\n",
" end\n",
" end\n",
" xs[j], xs[hi] = xs[hi], xs[j]\n",
" return j\n",
"end"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"どうでしょう。PythonやRubyをやったことがる人なら初見でも大体の意味が分かるのではないでしょうか。\n",
"まるで擬似コードのような、スッキリした文法です。\n",
"\n",
"関数定義・分岐・反復などの構文はそれぞれ`function ... end`, `if ... end`, `for ... end`, `while ... end`のようにキーワードで始まり`end`で終わります。 ちょうどRubyと同じような感じです。 インデントはPythonのように必要ではありませんが、4スペースでひとつのインデントを表すのが慣習です。\n",
"\n",
"また、6行目の`p = partition(xs, lo, hi)`で分かるように変数の宣言や型の指定は通常必要ありません。\n",
"\n",
"18行目の`@inbounds`というのが気になるかもしれません。\n",
"`@`マークで始まるこの表記は**マクロ呼出し**と言われ、コードを書き換えたりJuliaのコンパイラに最適化のヒントを与えることができます。\n",
"ここで使われている`@inbounds`は添字アクセス(`xs[i]`など)のチェックを省き、少し計算を高速化できますが、配列の範囲外にアクセスした時はセグメンテーション違反などを起こし停止する可能性があります。\n",
"\n",
"こうしたJuliaで書かれたコードはJuliaのLLVMベースのJITコンパイラによりコンパイルされ、C言語などで書いたコードとそれほど変わらない速度で実行できます。\n",
"\n",
"試しに整数の小さい配列をソートしてみると、うまく行っています。"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"6-element Array{Int64,1}:\n",
" 1\n",
" 2\n",
" 3\n",
" 4\n",
" 5\n",
" 6"
]
},
"execution_count": 2,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"quicksort([3, 6, 2, 4, 5, 1])"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"浮動小数点でも動きます。"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"6-element Array{Float64,1}:\n",
" -2.1\n",
" -1.2\n",
" 0.1\n",
" 3.1\n",
" 3.4\n",
" 5.0"
]
},
"execution_count": 3,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"quicksort([-2.1, 3.4, 5.0, -1.2, 3.1, 0.1])"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"1千万要素もあるような浮動小数点数の配列のソートも一瞬です。"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
" 1.211873 seconds (6 allocations: 76.294 MiB, 4.84% gc time)\n"
]
},
{
"data": {
"text/plain": [
"10000000-element Array{Float64,1}:\n",
" -5.201821821719352\n",
" -5.050624909871284\n",
" -4.983261442674312\n",
" -4.974985552832985\n",
" -4.893857076120602\n",
" -4.864517550048943\n",
" -4.85004091215009 \n",
" -4.811551905035468\n",
" -4.785936931795382\n",
" -4.758123564483724\n",
" -4.751953182949212\n",
" -4.751136270866197\n",
" -4.700641597803617\n",
" ⋮ \n",
" 4.643556492102544\n",
" 4.664239936011457\n",
" 4.682333119886756\n",
" 4.685774543279274\n",
" 4.695170058903736\n",
" 4.710676182931005\n",
" 4.824126039132785\n",
" 4.889103328580121\n",
" 4.920689915842902\n",
" 4.976832282177101\n",
" 5.16998796753511 \n",
" 5.293639671892019"
]
},
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"using Random: seed!\n",
"seed!(0xdeadbeef)\n",
"xs = randn(10_000_000)\n",
"@time quicksort(xs)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"ここでひとつ注目すべきことは、`quicksort`関数の定義時に引数の型を指定していなかったにも関わらず、整数にも浮動小数点数にも適用できるということです。\n",
"実は、関数の最初の実行時にそれぞれの型に応じて高速なコードを生成しています。\n",
"この機能のおかげで、**Juliaでは関数の型を一切指定しなくても十分なパフォーマンスが得られます**。\n",
"\n",
"`quicksort`は、数値にかぎらず以下の様な文字や文字列でも適用できます。"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"5-element Array{Char,1}:\n",
" 'A'\n",
" 'B'\n",
" 'C'\n",
" 'D'\n",
" 'E'"
]
},
"execution_count": 5,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"quicksort(['B', 'A', 'D', 'E', 'C'])"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"5-element Array{String,1}:\n",
" \"Alice\" \n",
" \"Bob\" \n",
" \"Charlie\"\n",
" \"Dave\" \n",
" \"Eve\" "
]
},
"execution_count": 6,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"quicksort([\"Bob\", \"Alice\", \"Dave\", \"Eve\", \"Charlie\"])"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### 変数"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Juliaの変数名はとても自由です。英字やアンダースコア(`_`)から始まる英数字/アンダースコアの他に、UTF8の多様な文字が使えます。\n",
"\n",
"使えるもの:\n",
"* `xyz`\n",
"* `_foo3_`\n",
"* `π`\n",
"* `f′`\n",
"\n",
"使えないもの:\n",
"* `33xyz`などの数値から始まるもの\n",
"* `for`, `function`, `end`など予約語\n",
"* `x.y`, `x:y`などの予約されている記号を使ったもの"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"`x`などが使えるのはもちろんですが、"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"100"
]
},
"execution_count": 7,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"x = 100"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"`η`のようなギリシャ文字や漢字も使えます。"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"0.01"
]
},
"execution_count": 8,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"η = 0.01"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"0.01"
]
},
"execution_count": 9,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"漢字変数 = η"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"ここまで見てきたように、変数は特別に宣言せずとも初期化と同時に使用できます。\n",
"\n",
"変数には、その影響するソースコードの範囲である**スコープ**という概念があります。\n",
"`function`や`for`などで始まり、`end`で終わるほとんどのブロックは新たな変数のスコープを作ります。`for ... end`がスコープを作るのはPythonなどと動作が異なりますので注意が必要です。\n",
"\n",
"以下の例では、変数`xx`は`for ... end`の内側のみのスコープを持つため、その外で`xx`にアクセスすると変数未定義の例外が発生しています。"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [
{
"ename": "UndefVarError",
"evalue": "UndefVarError: xx not defined",
"output_type": "error",
"traceback": [
"UndefVarError: xx not defined",
"",
"Stacktrace:",
" [1] top-level scope at In[10]:4"
]
}
],
"source": [
"for i in 1:10\n",
" xx = i\n",
"end\n",
"xx"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"例外的にスコープを作らないのは`if ... end`と`begin ... end`です。すなわち、`if ... end`や`begin ... end`の内側で定義した変数にはその外側でもアクセスできます。"
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"10"
]
},
"execution_count": 11,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"if true\n",
" yy = 10\n",
"end\n",
"yy"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### 数値型"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Juliaの値は型を持ちます。Juliaでは動的に型がつき、様々な機能と密接に関わってきます。\n",
"\n",
"整数型は符号有無と8bit, 16bit, 32bit, 64bit, 128bitの組み合わせの10種類、それに加えて`Bool`型と`BigInt`型で合計12種類あり、それぞれ符号付き64bitは`Int64`や符号なし(unsigned)32bitは`UInt32`など一貫性のある型名がつけられています。\n",
"\n",
"浮動小数点数の型も16bit, 32bit, 64bitと`BigFloat`型で合計4種類があります。型名は`Float64`などのように精度の数値が最後についています。\n",
"\n",
"`BigInt`型と`BigFloat`型はそれぞれ任意精度の整数と浮動小数点数です。"
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"Int64"
]
},
"execution_count": 12,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"Int64"
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"Float64"
]
},
"execution_count": 13,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"Float64"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"他には複素数の`Complex{T}`型があります。\n",
"`T`というのは**型パラメータ(type parameter)**で、実部と虚部の数値の型を指定します。ちょうどC++のテンプレートやHaskellの型変数(type variable)のようなものです。"
]
},
{
"cell_type": "code",
"execution_count": 14,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"Complex{Float64}"
]
},
"execution_count": 14,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"Complex{Float64}"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"特殊な例として、円周率のような定数は`Irrational`型として定義されています。"
]
},
{
"cell_type": "code",
"execution_count": 15,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"π = 3.1415926535897..."
]
},
"execution_count": 15,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"π"
]
},
{
"cell_type": "code",
"execution_count": 16,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"true"
]
},
"execution_count": 16,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"isa(π, Irrational) # isa(x, typ)は値xが型typの値であるかどうかを返す関数"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"科学計算のために作られているJuliaは、このように豊富な数値の型を持つ点が魅力のひとつです。"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### リテラル"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"大抵の場合、何らかの値を作るリテラルは他の言語と同じです。\n",
"\n",
"* 数値\n",
" * 整数 `Int`型: `1`, `42`, `-4`\n",
" * 浮動小数点数 `Float64`型: `3.14`, `-2.1`, `6.0221413e+23`\n",
" * 複素数 `Complex{T}`型: `3 + 2im`, `1.1 - 9.1im`\n",
" * 有理数 `Rational{T}`型: `3 // 2`, `355 // 113`\n",
"* 文字(列)\n",
" * 文字 `Char`型: `'a'`, `'樹'`\n",
" * 文字列 `String`型: `\"deadbeef\"`, `\"漢字\"`, `\"\"\"Triple Quote String\"\"\"`\n",
"* その他\n",
" * 真偽値 `Bool`型: `true`, `false`\n",
" * シングルトン `Nothing`型: `nothing`\n",
" \n",
"実際のソースコードでは`Int`型を目にすることが多いですが、これは環境によって`Int32`または`Int64`のエイリアスになっています。"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"型は以下のように`typeof`で確認できます。"
]
},
{
"cell_type": "code",
"execution_count": 17,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"Int64"
]
},
"execution_count": 17,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"typeof(42)"
]
},
{
"cell_type": "code",
"execution_count": 18,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"Float64"
]
},
"execution_count": 18,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"typeof(42.0)"
]
},
{
"cell_type": "code",
"execution_count": 19,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"Rational{Int64}"
]
},
"execution_count": 19,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"typeof(3 // 2)"
]
},
{
"cell_type": "code",
"execution_count": 20,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"Complex{Int64}"
]
},
"execution_count": 20,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"typeof(2 + 3im)"
]
},
{
"cell_type": "code",
"execution_count": 21,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"Char"
]
},
"execution_count": 21,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"typeof('A')"
]
},
{
"cell_type": "code",
"execution_count": 22,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"Char"
]
},
"execution_count": 22,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"typeof('漢')"
]
},
{
"cell_type": "code",
"execution_count": 23,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"String"
]
},
"execution_count": 23,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"typeof(\"deadbeef\")"
]
},
{
"cell_type": "code",
"execution_count": 24,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"String"
]
},
"execution_count": 24,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"typeof(\"漢字\")"
]
},
{
"cell_type": "code",
"execution_count": 25,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"Bool"
]
},
"execution_count": 25,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"typeof(true)"
]
},
{
"cell_type": "code",
"execution_count": 26,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"Nothing"
]
},
"execution_count": 26,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"typeof(nothing)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"また,ある値がある型であるかは`isa`関数で確認できます。"
]
},
{
"cell_type": "code",
"execution_count": 27,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"true"
]
},
"execution_count": 27,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"isa(1, Int)"
]
},
{
"cell_type": "code",
"execution_count": 28,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"true"
]
},
"execution_count": 28,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"1 isa Int # 中置もできる"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### 配列 / タプル"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Juliaでは1次元配列を**ベクトル(`Vector`)**、2次元配列を**行列(`Matrix`)**とよびます。"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"ベクトル(1次元配列)は`[x,y,...]`で表現します。"
]
},
{
"cell_type": "code",
"execution_count": 29,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"3-element Array{Int64,1}:\n",
" 1\n",
" 2\n",
" 3"
]
},
"execution_count": 29,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"[1,2,3]"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"添字のアクセスはカギ括弧(`[]`)を使います。**添字は`1`から始まり**、配列の長さ分で終わります。"
]
},
{
"cell_type": "code",
"execution_count": 30,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"5-element Array{Int64,1}:\n",
" 1\n",
" 2\n",
" 3\n",
" 4\n",
" 5"
]
},
"execution_count": 30,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# 5要素のベクトル\n",
"xs = [1,2,3,4,5]"
]
},
{
"cell_type": "code",
"execution_count": 31,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"1"
]
},
"execution_count": 31,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"xs[1]"
]
},
{
"cell_type": "code",
"execution_count": 32,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"5"
]
},
"execution_count": 32,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"xs[5]"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"値の更新も標準的な構文で可能です。"
]
},
{
"cell_type": "code",
"execution_count": 33,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"200"
]
},
"execution_count": 33,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"xs[2] = 200"
]
},
{
"cell_type": "code",
"execution_count": 34,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"5-element Array{Int64,1}:\n",
" 1\n",
" 200\n",
" 3\n",
" 4\n",
" 5"
]
},
"execution_count": 34,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"xs"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"配列を末尾からアクセスするときは`end`が使えます。"
]
},
{
"cell_type": "code",
"execution_count": 35,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"5"
]
},
"execution_count": 35,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"xs[end]"
]
},
{
"cell_type": "code",
"execution_count": 36,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"true"
]
},
"execution_count": 36,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"xs[end] == xs[5]"
]
},
{
"cell_type": "code",
"execution_count": 37,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"true"
]
},
"execution_count": 37,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"xs[end-1] == xs[4]"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"ある範囲を切り出すには`n:m`というような書き方ができます。"
]
},
{
"cell_type": "code",
"execution_count": 38,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"2-element Array{Int64,1}:\n",
" 200\n",
" 3"
]
},
"execution_count": 38,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"xs[2:3]"
]
},
{
"cell_type": "code",
"execution_count": 39,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"3-element Array{Int64,1}:\n",
" 3\n",
" 4\n",
" 5"
]
},
"execution_count": 39,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"xs[end-2:end]"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"型もちょっと見てみましょう。`[x,y,...]`で作られるのは`Array`型の値です。\n",
"以下の`{Int64,1}`の意味は後の型システムのところで説明します。"
]
},
{
"cell_type": "code",
"execution_count": 40,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"Array{Int64,1}"
]
},
"execution_count": 40,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"typeof([1,2,3])"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"また、`[1,2,3]`は`Vector`型の値でもあります。これは`isa`関数でチェックできます。"
]
},
{
"cell_type": "code",
"execution_count": 41,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"true"
]
},
"execution_count": 41,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"isa([1,2,3], Vector)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"行列は`[a b c; d e f]`のように書けます。"
]
},
{
"cell_type": "code",
"execution_count": 42,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"2×3 Array{Int64,2}:\n",
" 1 2 3\n",
" 4 5 6"
]
},
"execution_count": 42,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"[1 2 3; 4 5 6]"
]
},
{
"cell_type": "code",
"execution_count": 43,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"2×3 Array{Int64,2}:\n",
" 1 2 3\n",
" 4 5 6"
]
},
"execution_count": 43,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"x = [1 2 3;\n",
" 4 5 6]"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"添字でのアクセスも見ておきましょう。"
]
},
{
"cell_type": "code",
"execution_count": 44,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"2"
]
},
"execution_count": 44,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"x[1,2]"
]
},
{
"cell_type": "code",
"execution_count": 45,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"6"
]
},
"execution_count": 45,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"x[2,end]"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"`Vector`の時と同様に`Matrix`型であることを確認しておきます。"
]
},
{
"cell_type": "code",
"execution_count": 46,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"true"
]
},
"execution_count": 46,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"isa([1 2 3; 4 5 6], Matrix)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"配列の要素数は`length`で取得します。"
]
},
{
"cell_type": "code",
"execution_count": 47,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"3"
]
},
"execution_count": 47,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"length([1,2,3])"
]
},
{
"cell_type": "code",
"execution_count": 48,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"6"
]
},
"execution_count": 48,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"length([1 2 3; 4 5 6])"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"タプル(組)は`(x,y,...)`です。"
]
},
{
"cell_type": "code",
"execution_count": 49,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"(1, 2, 3)"
]
},
"execution_count": 49,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"(1,2,3)"
]
},
{
"cell_type": "code",
"execution_count": 50,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"Tuple{Int64,Int64,Int64}"
]
},
"execution_count": 50,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"typeof((1,2,3))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"タプルもベクトル同様、添字でのアクセスが出来ます"
]
},
{
"cell_type": "code",
"execution_count": 51,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"2"
]
},
"execution_count": 51,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"(1,2,3)[2]"
]
},
{
"cell_type": "code",
"execution_count": 52,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"3"
]
},
"execution_count": 52,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"(1,2,3)[end]"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"タプルの括弧は、曖昧性がなければ省略できます。"
]
},
{
"cell_type": "code",
"execution_count": 53,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"(1, 2, 3)"
]
},
"execution_count": 53,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"1,2,3"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"配列の大きさは`size`関数で得られますが、タプルとして返されます。"
]
},
{
"cell_type": "code",
"execution_count": 54,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"(3,)"
]
},
"execution_count": 54,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"size([1,2,3])"
]
},
{
"cell_type": "code",
"execution_count": 55,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"(2, 3)"
]
},
"execution_count": 55,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"size([1 2 3; 4 5 6])"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"タプルとベクトルはよく似ていますが、内部の構造や動作は大きく異なります。\n",
"\n",
"まず、タプルは不変(immutable)ですが、ベクトルや配列は可変(mutable)です。\n",
"したがって、一度作ったタプルはそれ以降変更できませんが、配列では可能です。\n",
"\n",
"また、タプルはメモリーの割当が起きないことがあるため、オブジェクトの生成コストが極めて小さいです。"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### 範囲"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Juliaには値の範囲を表す範囲型も用意されています。`start:stop`のように書くことで、`start`から`stop`まで、両端を含む範囲を表現します。"
]
},
{
"cell_type": "code",
"execution_count": 56,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"1:10"
]
},
"execution_count": 56,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"1:10"
]
},
{
"cell_type": "code",
"execution_count": 57,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"'a':1:'z'"
]
},
"execution_count": 57,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"'a':'z'"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"これは`for`ループを書くときや、配列や文字列から一部分を切り出す際に用いられます。"
]
},
{
"cell_type": "code",
"execution_count": 58,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"3\n",
"4\n",
"5\n",
"6\n"
]
}
],
"source": [
"for i in 3:6\n",
" println(i)\n",
"end"
]
},
{
"cell_type": "code",
"execution_count": 59,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"6-element Array{Int64,1}:\n",
" 1\n",
" 2\n",
" 3\n",
" 4\n",
" 5\n",
" 6"
]
},
"execution_count": 59,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"x = [1,2,3,4,5,6]"
]
},
{
"cell_type": "code",
"execution_count": 60,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"4-element Array{Int64,1}:\n",
" 3\n",
" 4\n",
" 5\n",
" 6"
]
},
"execution_count": 60,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"x[3:6]"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"`start:step:stop`のように書くことで、ステップ幅を指定することもできます。"
]
},
{
"cell_type": "code",
"execution_count": 61,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"0\n",
"10\n",
"20\n",
"30\n",
"40\n",
"50\n",
"60\n",
"70\n",
"80\n",
"90\n"
]
}
],
"source": [
"for i in 0:10:90\n",
" println(i)\n",
"end"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"ステップ幅に`-1`を指定すれば、逆順の範囲も作れます。"
]
},
{
"cell_type": "code",
"execution_count": 62,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"5\n",
"4\n",
"3\n",
"2\n",
"1\n"
]
}
],
"source": [
"for i in 5:-1:1\n",
" println(i)\n",
"end"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### 辞書"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Juliaでは辞書ももちろん用意されています。"
]
},
{
"cell_type": "code",
"execution_count": 63,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"Dict{String,Int64} with 2 entries:\n",
" \"bar\" => 2\n",
" \"foo\" => 1"
]
},
"execution_count": 63,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"x = Dict(\"foo\" => 1, \"bar\" => 2)"
]
},
{
"cell_type": "code",
"execution_count": 64,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"1"
]
},
"execution_count": 64,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"x[\"foo\"]"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 型システム"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Juliaにおいて、型は非常に重要な意味を持ちます。\n",
"PythonやRubyのようにJuliaは動的型付け言語ですが、オブジェクト指向のプログラミング言語での型の使い方とはかなり異なっています。\n",
"ここでは、Juliaの型システムを理解し、その後に出てくる型の定義や動的ディスパッチの前提知識を固めましょう。"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### 型の階層構造"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Juliaの値はひとつの **具体的な** 型を持ちます。一部例外を除いて、型が自動的に別の型にキャストされることはありません\n",
"(一部例外とは、`1 + 1.5`などの数値計算とコンストラクタです
オプション引数 | `=` | `xs, k=3` |
---|---|---|
キーワード引数 | `;` `=` | `xs; k=3` |
可変長引数 | `...` | `x, xs...` |