[julia] ワークフロー, スコープ, モジュール
久しぶりに julia にさわるので, 基本的なことを復習するためのメモ.
0. 概要
以下の内容について記載する.
- ワークフロー
- スコープ
- module
1. ワークフロー
1.1 REPLベースのワークフロー
(詳細は julia-1.11.1.pdf / 36.1 REPL-based workflow 参照.)
以下のようなファイルを作成する.
module Tmp
say_hello() = println("Hello!")
# Your other definitions here
end # module
using .Tmp
同じフォルダでREPLを起動し, 以下のように say_hello()
関数を実行できる.
julia> include("Tmp.jl")
julia> Tmp.say_hello()
Hello!
Tmp.jl
を変更した場合, 再度 include
することにより変更が反映される(REPL を再起動する必要がない).
1.2 Revise を使ったワークフロー
上の例では Tmp.jl
を変更するたびに include
を実行する必要があったが, Revise パッケージがインストールされていれば, 更新時の include
の入力を省略することができる(最初の1回は includet
する必要がある).
Revise がインストールされていない場合, REPLから以下のようにインストールする.
julia> ]
(@v1.11) pkg> add Revise
(@v1.11) pkg> [BS]
julia>
([BS]
はバックスペースキーを押すことを表す.)
julia> using Revise
julia> includet("Tmp.jl")
julia> Tmp.say_hello()
Hello!
(include
ではなく, includet
であることに注意.)
Revise
なしの場合と異なり, 一度 includet
しておけば Tmp.jl
が変更されると自動的に REPL にもそれが反映される. vscode で Julia 拡張を導入し, Revise
がインストールされていると, REPL は using Revise
の状態で起動される.
vscode で Julia 拡張のもと, REPL を起動するにはコマンドパレット(Shift
+Ctrl
+p
)からJulia: Start REPL
を選択すればよい(ショートカットは Alt
+j
Alt
+o
).
2. スコープ
(詳細は julia-1.11.1.pdf / 11 Scope of Variables 参照.)
julia のスコープ:
- グローバル
- ソフトローカル
- ハードローカル
2.1 グローバルスコープ
- 何も記載しない状態(デフォルト(
Main
)モジュール), もしくは明示的にmodule
により生成 - モジュール直下のスコープ
- モジュール内でモジュールを定義してもスコープは入れ子にならない
- モジュール名を明示的に付加して変数を指定すれば別のモジュールのグローバル変数も参照可能(
Main.x
など)
2.2 ローカルスコープ
-
if
/begin
では生成されない - 入れ子にでき, ローカルスコープ同士であれば必要に応じて外側の変数を参照できる
- デフォルトではローカルスコープからグローバルスコープの変数を参照できない
- ローカルスコープからグローバルスコープの変数を参照するためには
global
で宣言する - モジュール名を明示的に指定すればグローバルスコープの変数も参照できる(
Main.x
など) - REPL環境では一部のローカルスコープからグローバルスコープの変数が参照できる(ソフトローカルスコープ, 以下を参照)
2.3 ソフトローカルスコープ
(REPL環境における利便性のための機能だと思われる.)
- REPL でのみ適用される特別なローカルスコープ
- REPL 環境において
for
/while
/try
/struct
によって生成されるローカルスコープからはグローバルスコープ(REPL環境)の変数が参照できる - 非対話環境では通常の(ハード)ローカルスコープになる
3. モジュール
3.1 デフォルトモジュール
- モジュールを明示的に指定しなければデフォルトモジュール(
Main
モジュール)とみなされる - REPL環境は
Main
モジュールでの作業
include
, using
, import
3.2 -
include
はその場所に引数のファイルを展開する命令であり, スコープや名前空間の概念とは関係ない -
using
は他のモジュールを現在の名前空間に取り込む(モジュールM
に対してusing M
とするとM.x
,M.f()
などによりモジュールを参照することができるようになる) - モジュールの定義に
export
文を記載しておけば(export x, f
など)using
したときにモジュール名を指定しなくても名前がそのまま使える(x
,f()
のように使える) -
import
は個別の名前を現在の名前空間に取り込む(import M
はusing M: M
と同じ,import M: x
ならM
は取り込まれず,x
のみ取り込まれる)
3.3 モジュールの相対パス
パッケージマネージャーで管理されていないモジュールはモジュールの入れ子構造を .
(自分のモジュールからみた子モジュール), ..
(自分のモジュールから見た親モジュール)で指定して参照することができる.
Discussion