Julia言語 を導入し人生を N ≥ 1 歩進める(2022 年 12 月 版)

# 本日は

アドベントカレンダーの2日目です

https://qiita.com/advent-calendar/2022/julia

プログラミング言語 Julia の導入をします．

# インストール

適当なシェル環境で `julia` と入力したら下記のような対話環境を出力することを目標にします．

```julia
% julia
               _
   _       _ _(_)_     |  Documentation: https://docs.julialang.org
  (_)     | (_) (_)    |
   _ _   _| |_  __ _   |  Type "?" for help, "]?" for Pkg help.
  | | | | | | |/ _` |  |
  | | |_| | | | (_| |  |  Version 1.8.3 (2022-11-14)
 _/ |\__'_|_|_|\__'_|  |  Official https://julialang.org/ release
|__/                   |

julia>
```

概ね下記の方法1, 方法2のどちらかで行えば良いです．個人的には方法2 を使っています.

## 方法1: 手動でバイナリを入手する方法

バイナリは https://julialang.org/ から入手することができます. ダウンロードしたバイナリのパスを `PATH` 環境変数に追加すれば動作します. 具体的なやり方は使用する OS 毎の説明がある https://julialang.org/downloads/platform/ をご覧ください．

## 方法2: Cross-platform installer を用いる方法

### juliaup を用いた場合

`juliaup` を使うと新しい Julia のバージョンがリリースされた際にわざわざバイナリを手動で入手することなく `juliaup` コマンドを経由して使用するバージョンを切り替えることができます．Linux 環境では [juliaup](https://github.com/JuliaLang/juliaup) の README の通りにすると導入することができます:

https://github.com/JuliaLang/juliaup


```console
curl -fsSL https://install.julialang.org | sh
```

以下のスクリーンショットは GCP の Cloud Shell で行ったものをキャプチャしたものです．

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/135978/7bfa8770-c613-afad-ccf3-a92f85ce0aaa.png)

特にこだわりがなければ `Proceed with installation` のまま Enter を押して進めます．

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/135978/bb053d05-d1ea-51d5-dc6b-ae252c97e3b9.png)

`julia` を入力して使えることを確認します.

特定のバージョン，例えば [LTS 扱い](https://julialang.org/downloads/#long_term_support_release) の 1.6 系を導入する場合は

```console
$ # 1.6 をインストール
$ juliaup add 1.6
$ # バージョンは切り替わらない
$ julia --version
julia version 1.8.3
$ # 暫定的に使う場合
julia +1.6
$ # 1.6 を既定にする場合
$ juliaup default 1.6
$ # 元に戻す場合
$ juliaup default 1.8
```

とはいえ `1.6` とか `1.8` というような数値は覚えたくないと思うので

```console
$ # 安定リリース版を使う場合
$ juliaup default release
$ # LTS 版を使う場合
$ juliaup default lts
```

を覚えておけば良いです．特にこだわりがなければ安定最新版(release) の方を使うと良いです．

### Windows の場合

Windows 環境ですと [Microsoft Store](https://apps.microsoft.com/store/search?hl=ja-jp&gl=jp&publisher=Julia%20Computing%2C%20Inc.) からインストールすると `juliaup` というコマンドと `julia` が使えるようになります．

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/135978/289cd437-d01e-e48c-929d-767952b2267e.png)

`winget` を使っても入手できるようです．`winget` は Windows 11 ではデフォルトで入っているようなので導入が楽になっています．

```powershell
winget install julia -s msstore
```

### jill を用いた方法

普段は Python を使っていて `juliaup` の導入時に `curl ...` コマンドが覚えられない. そんな人は `jill` を使うのもありでしょう:

https://github.com/johnnychen94/jill.py

```console
$ pip3 install jill
$ jill install 1.8
```

# REPL で遊ぶ

インストールが完了できれば `julia` コマンドによって下記のような対話環境が得られます.これを REPL (read-eval-print loop) と呼びます.

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/135978/efbe4fd5-749d-fcf9-c98d-864aff53835c.png)

Julia は Python のようにインデントに関してセンシティブではないので巷にあるサンプルコードをコピーして REPL にペーストしてコードを実行させることができます. 例えば下記の `julia>` も含んだコードは REPL 上で動かすことを念頭に置いています．`julia>` の部分を丸ごとコピーして貼り付けても REPL 側でよしなに処理してくれます．

```julia
julia> msg = "Hello"
"Hello"

julia> println(msg)
Hello

julia> (.*)(1:9, (1:9)') # ブロードキャストで九九表を作成
9×9 Matrix{Int64}:
 1   2   3   4   5   6   7   8   9
 2   4   6   8  10  12  14  16  18
 3   6   9  12  15  18  21  24  27
 4   8  12  16  20  24  28  32  36
 5  10  15  20  25  30  35  40  45
 6  12  18  24  30  36  42  48  54
 7  14  21  28  35  42  49  56  63
 8  16  24  32  40  48  56  64  72
 9  18  27  36  45  54  63  72  81
```

Julia の REPL は便利な機能が含まれています．時間のある方はYouTubeにある Julia のワークショップが参考になります．

https://www.youtube.com/watch?v=bHLXEUt5KLc

こんなこともできます.

https://terasakisatoshi.github.io/MathSeminar.jl/slideshow/repl/build/#1

# 簡易逆引き

これをするにはどすればいい？というのを簡単にですがまとめます. (スペースの都合で余分な改行は省略しています.)

## Hello World

```julia
julia> msg = "Hello World" # "Hello World" を `msg` に紐づける
"Hello World"

julia> msg * " " * "Julia" # 文字列の結合は `*` を使う
"Hello World Julia"

julia> println(msg)
Hello World

julia> print(msg); print(" "); print("Julia")
Hello World Julia
julia> name = "Goma"; "Hello $name"
"Hello Goma"
```

- `println` 出力の最後に改行を追加します. `print` は改行を含めません.
- `#` の隣には Python と同様にコメントを書くことができます．
- `"$(name)"` で `name` の値を補間することができます(string-interpolation):

https://docs.julialang.org/en/v1/manual/strings/#string-interpolation
- セミコロンを挟むことで複数行のコードを1行にまとめることができます.

## 簡易的な電卓として

$x=3$ のときに $2x+5$, $x^2$ を計算したい場合はほぼそのままコードに落とし込むことができます.

```julia
julia> x = 3
3
julia> 2x + 5
11
julia> 2 * x + 5
11
julia> x ^ 2 # x の二乗を計算
9
julia> 5 / 2
2.5
julia> div(5, 2) # これは 5 を 2 で割った商を出す
2
```

## 数式を数式らしくコードにしたい

Julia は Unicode 文字を変数名に採用することができ入力を支援する機能がそなわっています. 円周率 $\pi$ は `pi` でも使うことができますが `\pi` のあとTABキーを入力することで $π$ を使うことができます. $\LaTeX$ を触ったことがある方は習熟しやすいでしょう．

```julia
julia> θ = π/6 # \theta
0.5235987755982988

julia> sin(2θ) ≈ 2sin(θ)*cos(θ)
true
```

## ↑の `≈` は何？

`≈` は `isapprox` 関数のエイリアスです. `\approx` + TAB で入力ができます.
それを調べるには REPL で `?≈` を入力するとヘルプモードにアクセスします：

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/135978/a9ce881a-5ebe-ced4-f3d9-8fd48e354352.png)

例えば下記のコードは Julia の文法として意味のあるコードです．

```julia
julia> 3 ∈ [1, 2, 3] ∩ [3, 4, 5]
true

julia> x₁ = 1; x₂ = 2; x₃ = 3
3

julia> 𝐱 = [x₁, x₂, x₃]
3-element Vector{Int64}:
 1
 2
 3
```

## 関数とかループとか条件分岐とか知りたい

乱数を振って円周率を計算する例で全部例示できます．

```julia
julia> function calcpi(N)
           cnt = 0
           for i in 1:N
               x = rand()
               y = rand()
               if x^2 + y^2 < 1
                   cnt += 1
               end
           end
           4cnt/N
       end
calcpi (generic function with 1 method)

julia> calcpi(10000)
3.14
```

- `function calcpi(N)... end` で `caclpi` という名前の関数名を定義できます. 
   - [`return` キーワード](https://docs.julialang.org/en/v1/base/base/#return) がないですが最後に評価した式の値を返す仕様になっています．もちろんつけても OK です. つけるかつけないかは個々の趣味やチーム毎のコーディング規約に依存します．
- `calcpi(10000)` で呼び出せます. `for i in 1:N ... end` で繰り返し処理を書きます.
- 条件分岐は `if 条件式 ... end` で書けます. 
    - 今回の場合は `x^2 + y^2 < 1 && (cnt += 1)` と1行で書くこともできます. 
https://docs.julialang.org/en/v1/manual/control-flow/#Short-Circuit-Evaluation
    - 条件式の値は型が Bool 値になること要請します. 
    ```julia
    julia> 1 && true
    ERROR: TypeError: non-boolean (Int64) used in boolean context
    ```

## ライブラリを使ってみたい.

### 導入

パッケージと呼ぶことが多いです. 例を示すために [Example.jl パッケージ](https://github.com/JuliaLang/Example.jl) を導入してみましょう.

```julia
julia> using Pkg; Pkg.add("Example")
```

`Pkg.add("Example")` で `Example.jl` パッケージをインストールすることができます．`Pkg` は Julia に組み込みされているパッケージマネージャ（の機能を扱うパッケージ)です.

https://pkgdocs.julialang.org/v1/
https://docs.julialang.org/en/v1/stdlib/Pkg/

### 使う

`using Example` を実行すると `Example.jl` パッケージオブジェクトに提供されている `hello` 関数を使うことができます.

```julia
julia> using Example

julia> Example.hello("Goma")
"Hello, Goma"

julia> hello("Goma")
"Hello, Goma"
```

`using Example` と実行することで `Example.hello` とするだけでなく `hello` を使うことができています. `Example.jl` 内部で定義している名前・識別子を現在の（グローバルの）名前空間に導入します.どのような名前を知るには Example.jl パッケージを読む必要があります．

https://github.com/JuliaLang/Example.jl/blob/78406c204b8fca4c32cd27c94aab794d6253b7e7/src/Example.jl#L2

```julia
export hello, domath
```

とあるので `using Example` によって `hello` と(実は) `domath` を現在の Julia のセッションに導入していることがわかります.

Python ユーザーにとってはちょっと気持悪いと感じるかもしれませんが, 慣れてくると少量のタイプ量で多くの機能にアクセスできる体験の良さがわかってきます. むしろ `from ... import ...` がめんどいと感じるようになるはずです．

#### どうしても導入される名前を制御したい

何かしらの理由で `domath` のみを導入したい場合, 特定の関数や値・型がどのパッケージから由来するのか明示したい場合は `using Example` の代わりに `using Example: domath` をすればOKです. `hello` 単体では使うことができないことが確認できるでしょう. 極論 `using Example: Example` とすれば `Example` 以外の名前を導入を抑えることができます.

#### ひとまずは `using <パッケージ名>` でOK

Julia では `Example.hello` みたいに仰々しくモジュール（ここでは `Example`のこと）名を付与することはしません．開発者は多重ディスパッチを使って同じ名前のメソッドを実装しユーザーはシンプルで柔軟なインターフェースを使って機能にアクセスすることができます. ユーザーとして Julia を使うのであれば `using Plots` とか `using Distributions` とか `using Images` のように `using BenchmarkTools` みたいに `using` を積極的に使うと良いです. 

追記: 2024 年 ただし，パッケージを開発する際は多くのパッケージに依存すると後からメンテナンスする際にどの識別子がどのパッケージからやってきたかを判断するのは現時点でも（手動で検索しなければいけない程度には）難しいので，パッケージ開発時には `using Something: myfunc` のような書き方を身につけておくと良いでしょう．３ヶ月後のソースコードは他人が書いたもののように記憶が消し去ります．

## もう少し実用的なライブラリを触りたい．

### REPL でグラフを描く: `UnicodePlots.jl`

関数のグラフを書いてみましょう.

```julia
julia> using UnicodePlots
julia> plt = lineplot(sin)
julia> lineplot!(plt, cos)
julia> lineplot!(plt, x-> 1 - 0.01x^2, name="Quadratic")
```

`using UnicodePlots` によって `lineplot`, `lineplot!` を使うことができます．$\sin$, $\cos$, $f(x) = 1 - 0.001x^2$ を描画できます.

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/135978/2d349ca1-4954-b585-bb4c-a247e5173526.png)

関数の末尾に `!` がある場合入力引数に影響を与えますよというプログラマの意図を読む側に伝える目的を持っています. 例えば $\sin$ を描画後 $\cos$ を描画する際にグラフオブジェクト `plt` の状態が変わります. 文法的に強制されているわけではないですがコーディング規約として用いられています.

`x-> 1 - 0.01x^2` の代わりに `f(x) = 1 - 0.001x^2` と `f` を定義して `lineplot!(plt, f)` でも OK です．

https://docs.julialang.org/en/v1/base/punctuation/

関数だけでなく座標の列を入力させることもできます.

```julia
julia> lineplot([1,2,3],[3,1,2])
     ┌────────────────────────────────────────┐
   3 │⠣⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│
     │⠀⠱⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│
     │⠀⠀⠈⢆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│
     │⠀⠀⠀⠀⢣⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│
     │⠀⠀⠀⠀⠀⠱⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│
     │⠀⠀⠀⠀⠀⠀⠘⢄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│
     │⠀⠀⠀⠀⠀⠀⠀⠈⢢⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│
     │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠑⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡠│
     │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⢆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⠔⠊⠀│
     │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠣⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⡠⠊⠁⠀⠀⠀│
     │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠑⡄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡠⠔⠁⠀⠀⠀⠀⠀⠀│
     │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⢆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⠔⠊⠀⠀⠀⠀⠀⠀⠀⠀⠀│
     │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠣⡀⠀⠀⠀⠀⠀⠀⠀⢀⡠⠊⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│
     │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠑⡄⠀⠀⠀⠀⡠⠔⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│
   1 │⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⢆⣀⠔⠊⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀│
     └────────────────────────────────────────┘
     ⠀1⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀3⠀
```

Julia の良さの一つに多重ディスパッチがあります．`lineplot` の名前さえ覚えておけばあとはなんとなく「こうすればいいだろ」という想像力を持って入力を与えておけば開発者が用意した適切なメソッドを呼び出してくれます．`@which lineplot(sin)` によって `lineplot` 関数に紐づくどの実装（メソッド）を呼ぶのかを人間に教えてくれます:

```julia
julia> @which lineplot(sin)
lineplot(f::Function; kw...) in UnicodePlots at ~/.julia/packages/UnicodePlots/Z7FG6/src/interface/lineplot.jl:223

julia> @which lineplot([1,2,3],[3,1,2])
lineplot(x::AbstractVector, y::AbstractVector) in UnicodePlots at ~/.julia/packages/UnicodePlots/Z7FG6/src/interface/lineplot.jl:65
```

これにより初見でも特定の識別子がどこからやってきたのかをある程度知ることができます．詳細には VSCode などでデバッガを起動して掘り下げていくことになります．

## 乱数発生をさせたい: `Distributions.jl`

一様乱数や標準正規分布に従う乱数を発生させるのはとても簡単です. 各々 `rand`, `randn` で生成できます．

```julia
julia> using UnicodePlots
julia> xs = rand(100000);
julia> ns = randn(100000);
```

末尾にセミコロンを入れると冗長な出力を抑えることができます. `UnicodePlots.jl` でサンプルのヒストグラムを可視化できます:

```julia
julia> histogram(xs)
julia> histogram(ns)
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/135978/673c6bd4-3593-d1e5-3469-ef1f881b8f81.png)

Distributions.jl は幅広い分布の種類をカバーします．

```julia
julia> using StatsPlots, Distributions
julia> unicodeplots() # おまじない
julia> plot(Exponential(0.1), linecolor=:red)
julia> plot(Laplace(0, 1), linecolor=:green)
```

StatsPlots.jl は Distributions.jl で定義されている分布の密度関数を可視化してくれます．

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/135978/6bd49d38-482c-1cc7-19b8-89c0c2c10bb8.png)

また下記の点にも注意しましょう:

```julia
julia> @which rand(100)
rand() in Random at /Applications/Julia-1.8.app/Contents/Resources/julia/share/julia/stdlib/v1.8/Random/src/Random.jl:278

julia> @which rand(Laplace(0, 1), 100)
rand(s::Sampleable, dims::Int64...) in Distributions at ~/.julia/packages/Distributions/gggmX/src/genericrand.jl:22
```

前者は前述の通り一様分布を後者はラプラス分布 `Laplace(0, 1)` に従うサンプルを 100 個生成するメソッドの定義場所を示しています. `using Distributions` をすることによって `rand` ができること(機能が増えていること)がわかります. 実は Distributions.jl は 標準で使える `rand` を拡張して機能を提供しています．これも Julia の多重ディスパッチの恩恵です．

### シードを付与して乱数の発生を制御したい

実験の再現性などで擬似乱数の生成を決定的にしたい場合は
擬似乱数生成アルゴリズムとシード値を明示的に指定し擬似乱数アルゴリズムのインスタンスを `rand` に入力すればOKです．標準ライブラリの Random が提供する `Xoshiro` を使ってみましょう. 

```julia
julia> using Random, Distributions

julia> rand(Xoshiro(0), Bernoulli(0.2), 5)
5-element Vector{Bool}:
 0
 1
 0
 1
 0

julia> rand(Xoshiro(0), Bernoulli(0.2), 5)
5-element Vector{Bool}:
 0
 1
 0
 1
 0
```

## パフォーマンス計測

BenchmarkTools.jl パッケージがあります.

```julia
julia> @benchmark minimum(rand(1000))
julia> @benchmark minimum($(rand(1000)))
```

以下の例はランダムに生成した配列の最小値を求める関数のベンチマークをとっています.

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/135978/6b6ba8f2-62b9-ba7c-9413-49787d294a55.png)

前者は試行毎に `rand(1000)` が実行されます．従って乱数生成の時間と `minimum` 関数の計算の両方を含んでいます. 後者は `rand(1000)` の値を補間して `minimum` 側の計算にフォーカスしてベンチマークをとっています.

https://juliaci.github.io/BenchmarkTools.jl/stable/

を眺めておくと良いでしょう.

## `@ほにゃらら` はなに？

マクロの呼び出しをしています. マクロはコード断片を入力とし適切に変換されたコード生成します. 例えば Python での f-string の機能を使うと `f"{x=}"` `x=<xの値>` が出力されます. Julia では `@show` マクロを使うと実現できます．

```julia
julia> x = 3
3

julia> @show x
x = 3
3
```

`@macroexpand` というマクロを使うとマクロがどのようなコードを生成するのかを観察することができます:

```julia
julia> @macroexpand @show x
quote
    Base.println("x = ", Base.repr(begin
                #= show.jl:1047 =#
                local var"#13#value" = x
            end))
    var"#13#value"
end
```

大雑把にいえば `x` というコードの断片を入力することで下記のようなコードを生成・評価していることを意味しています．

```julia
println("x = ", x)
x
```

関数の１回あたりの実行時間を計測する `@elapsed` マクロについても調べてみましょう:

```julia
julia> @elapsed rand(100)
2.973e-6
```

```julia
julia> @macroexpand @elapsed rand(100)
quote
    #= timing.jl:380 =#
    $(Expr(:meta, :force_compile))
    #= timing.jl:381 =#
    local var"#21#t0" = Base.time_ns()
    #= timing.jl:382 =#
    rand(100)
    #= timing.jl:383 =#
    (Base.time_ns() - var"#21#t0") / 1.0e9
end
```

大雑把にいえば下記のようなコードを生成・評価していることがわかります．

```julia
s = time_ns()
rand(100) # これが入力したコードの断片
e = time_ns()
(e - s) / 1.0e9
```

## 配列

Julia は(デフォルトでは) 1 始まりです. Python や C/C++ のプログラムにどっぷり使ってると Julia に移植する際に微妙な混乱を引き起こします．

Python のコードで表現できる場合は `0` を使う場合は配列の最初の位置の値を取得する目的が多いと思います．その場合は下記のような表記で要素のアクセスを抽象化できます.


```julia
julia> arr = [-1,-2,-3]
3-element Vector{Int64}:
 -1
 -2
 -3

julia> arr[1]
-1

julia> arr[begin] # arr[end]
-1

julia> first(arr) # last(arr)
-1
```

- 剰余系の完全代表系を 1 始まりにしたい場合は `mod` ではなく `mod1` にすると良いです．
- どうしても 1 始まりが気持ち悪い．コードを line by line で忠実に移植する必要があれば OffsetArrays.jl を使って添字の原点を調整することができます:

```julia
julia> using OffsetArrays: Origin

julia> oa = Origin(0)([1,2,3])
3-element OffsetArray(::Vector{Int64}, 0:2) with eltype Int64 with indices 0:2:
 1
 2
 3

julia> oa[0]
1

julia> oa[begin]
1

julia> first(oa)
1
```


https://github.com/JuliaArrays/OffsetArrays.jl
- 多次元配列で役立つと思われるパッケージも併せて紹介しておきます:
  - https://github.com/SciML/EllipsisNotation.jl

# まとめ

書いたらキリがないですが，入門時に知っておくと良いことを書いておきました．

Python 入門系は Jupyter Notebook の環境を構築して云々してようやくスタートに立てますが，Julia は REPL だけで色々遊ぶことができます．最近はパッケージのインストールの失敗で諦めるという事象は減ってきてると思うので特殊な環境でない入門では限り困らないと思います．

必要に応じて　`help?>` を使ったりドキュメントを読んだり，ソースコードを追いかけたり Web 上の解説を読むと良いでしょう．

ちなみに Julia は 2009 年に開発がスタートし 2012 年に公開されました．ということは公開から１０周年です．ちょうどいい節目を逃す前に記念にトライしてはいかがでしょうか？