NnmnLog

Juliaをさわってみた

作成: 2020-02-09
更新: 2020-02-09

Juliaのドキュメントを読みながら、インストールして、いくつかの機能を調べて試してみました。

インストール

brewでインストール

Macでbrewを使っていて、brew caskを使える状態になっていれば、brew cask installでインストールできます。

dockerイメージを使う

dockerのイメージも提供されているので、それを使う事もできます。 Docker Hubのリポジトリがあるので、docker runで起動イメージにjuliaを指定すると自動でpullしてきて、REPLが立ち上がります。

$ docker run -it --rm --name julia julia
Unable to find image 'julia:latest' locally
latest: Pulling from library/julia
8ec398bc0356: Pull complete
e59afaf5b9ab: Pull complete
a8ff93c6b967: Pull complete
Digest: sha256:3f007403ad08637b46523a8025b2f69ff1515d96b411ab0b7abe29ca200e43a9
Status: Downloaded newer image for julia:latest
               _
   _       _ _(_)_     |  Documentation: https://docs.julialang.org
  (_)     | (_) (_)    |
   _ _   _| |_  __ _   |  Type "?" for help, "]?" for Pkg help.
  | | | | | | |/ _` |  |
  | | |_| | | | (_| |  |  Version 1.3.1 (2019-12-30)
 _/ |\__'_|_|_|\__'_|  |  Official https://julialang.org/ release
|__/                   |

julia>

Juliaの実行方法

Juliaの実行方法には大きく2つあります。 REPL上で実行する場合と、juliaのソースコードをjuliaコマンドに渡す方法です。

REPLで実行する

REPLとは、対話形式でJuliaの式を評価し、結果をみることができるツールです。 Shellのように、プロンプトが表示され、Juliaの式を入力しEnterを入力すると、その式が評価され結果が表示されます。

julia> print("Hello, Julia")
Hello, Julia

ちなみに、REPLは、read-eaval-print loop(Read(読み込む)、Eval(評価する)、Print(出力する)、Loop(繰り返す))の頭文字をとったものです。

juliaコマンドで実行する

$ echo 'print("Hello, julia!\n")' > hello.jl
$ julia hello.jl
Hello, julia!

変数

Juliaの変数は、値に束縛した名前です。 以下は、10xという名前に束縛します。

julia> x = 10
10

変数名には、Unicodeを使用する事もできます。

julia> ハロー = "わーるど"
"わーるど"

julia> ハロー
"わーるど"

JuliaのREPLでは、バックスラッシュをつけたLaTexの数式記号を使うことで、α̂₂のような文字も入力することができます。

REPLで\alpha + <TAB> + \hat + <TAB> + \_2 + <TAB>を入力すると、 α̂₂に変換されます。

julia> α̂₂ = 100
100

非推奨とされていますが、Juliaでは必要があれば、組み込み定数や関数を再定義することができます。 ただし、再定義するには、対象の定数や関数が一度も評価されていない必要があります。

julia> pi = 3
3

julia> pi
3

JuliaのREPLを再起動し、先に評価した場合、上書き時にエラーになります。

julia> pi
π = 3.1415926535897...

julia> pi = 3.14
ERROR: cannot assign a value to variable MathConstants.pi from module Main

Juliaの型は以下のようなものがあります。 整数型と不動小数点数型は、型名の後に型のビット数を指定して表現されます。

  • Boolean型
    • Bool
  • 整数型
    • Int8
    • Int16
    • Int32
    • Int64
    • Int128
    • UInt8
    • UInt16
    • UInt32
    • UInt64
    • UInt128
  • 不動小数点数型
    • Float16
    • Float32
    • Float64
  • 文字
    • Char
  • 文字列
    • String
    • SubString

Boolean

Bool型は、trueまたは、falseを持つことができます。内部的には8bitの整数で表現されており、true(1)false(0)になります。

julia> true == 1
true

julia> false == 0
true

整数型・不動小数点数型

Juliaには、整数型と不動小数点数型があり、typeofを評価するとそれぞれIntFloatが返ってきます。

julia> typeof(100)
Int64

julia> typeof(100.0)
Float64

typemintypemax関数で型が取りうる最小と最大の値を取得できます。

julia> (typemin(Int8), typemax(Int8))
(-128, 127)

文字・文字列

文字列は、文字の並びです。英数字や記号などは、0から127までの整数値にマッピングされたASCIIを使うことができ、日本語などはUTF-8エンコーディングされたユニコードを使えます。

文字は'で、文字列は"で括られたものになります。 文字列は文字の並びなので、インデックスを指定して特定の文字を取得することができます。 文字列のインデックスの単位は1byteで、1から始まり、インデックスを1進めると1byte先の値が参照されます。

日本語などのマルチバイト文字以下の例では、は、3byteなので、str[1]で参照でき、str[2]とstr[3]`は不正な値としてエラーになります。

nextind()を使うと、次の文字のインデックスが取得できます。

julia> str = "ハロー、Julia"
"ハロー、Julia"

julia> str[1]
'ハ': Unicode U+30cf (category Lo: Letter, other)

julia> str[2]
ERROR: StringIndexError("ハロー、Julia", 2)
Stacktrace:
 [1] string_index_err(::String, ::Int64) at ./strings/string.jl:12
 [2] getindex_continued(::String, ::Int64, ::UInt32) at ./strings/string.jl:220
 [3] getindex(::String, ::Int64) at ./strings/string.jl:213
 [4] top-level scope at REPL[81]:1

julia> str[3]
ERROR: StringIndexError("ハロー、Julia", 3)
Stacktrace:
 [1] string_index_err(::String, ::Int64) at ./strings/string.jl:12
 [2] getindex_continued(::String, ::Int64, ::UInt32) at ./strings/string.jl:220
 [3] getindex(::String, ::Int64) at ./strings/string.jl:213
 [4] top-level scope at REPL[82]:1

julia> str[4]
'ロ': Unicode U+30ed (category Lo: Letter, other)

julia> str[nextind(str, 1)]
'ロ': Unicode U+30ed (category Lo: Letter, other)

変数名の前に$がついた文字列が、文字列内にある場合は、それを変数として展開します。

julia> who = "Julia"
"Julia"

julia> "Hello, $who"
"Hello, Julia"

文字は、Int型の整数にマッピングされているため、大小関係が存在し計算も可能です。

julia> Int('A')
65

julia> Int('a')
97

julia> 'A' < 'a'
true

julia> 'a' - 32
'A': ASCII/Unicode U+0041 (category Lu: Letter, uppercase)

正規表現

Juliaで正規表現を使う場合は、r"<正規表現>"という構文で、Regex型を宣言します。

julia> typeof(r"Ju.*")
Regex

正規表現が対称の文字列に出現するかどうかを調べたい場合は、occursin関数が使えます。 occursin関数は、正規表現が検索対象の文字列に含まれるかどうかを評価しbooleanを返します。

julia> occursin(r"Ju.*", "Julia")
true

julia> occursin(r"Ju.*", "July")
true

julia> occursin(r"Ju.*", "hoge")
false

match関数を使うと、正規表現にマッチした文字列を取得できます。

julia> match(r"(Ju.*)", "Hello, Julia")
RegexMatch("Julia", 1="Julia")

julia> ans[1]
"Julia"

関数

Juliaの関数は、引数から戻り値への写像オブジェクトです。 function <関数名>(<引数>) endで宣言します。

julia> function f(x)
           2x + 1
       end
f (generic function with 1 method)

julia> f(1)
3

また、g(x) = 2x + 1のように宣言することも可能です。

julia> g(x) = 2x + 1
g (generic function with 1 method)

julia> g(1)
3

Juliaの関数は、関数内で最後に評価された式を返却しますが、return 式を使うと明示的に特定の式を返却することができます。

julia> function g(x,y)
           return x * y
           x + y
       end
g (generic function with 2 methods)

julia> g(1,1)
1

無名関数

functionキーワードに関数名を指定しないで関数を定義する。 または、->(アロー演算子)を使って、無名関数を作ることができます。

julia> x -> x^2 + 2x - 1
#4 (generic function with 1 method)

julia> function(x)
           x^2 + 2x - 1
       end
#6 (generic function with 1 method)

julia> map(x -> x^2 + 2x + 1, [1, 2, 3, 4, 5])
5-element Array{Int64,1}:
  4
  9
 16
 25
 36

引数の型

<変数名>::<型>の形式で引数を宣言することで、関数に渡す引数の型を指定することができます。

julia> function f(x::Int64)
         typeof(x)
       end
f (generic function with 2 methods)

julia> f(1)
Int64

julia> f("Julia")
ERROR: MethodError: no method matching *(::Int64, ::String)
Closest candidates are:
  *(::Any, ::Any, ::Any, ::Any...) at operators.jl:529
  *(::Missing, ::AbstractString) at missing.jl:170
  *(::T, ::T) where T<:Union{Int128, Int16, Int32, Int64, Int8, UInt128, UInt16, UInt32, UInt64, UInt8} at int.jl:54
  ...
Stacktrace:
 [1] f(::String) at ./REPL[8]:2
 [2] top-level scope at REPL[33]:1

オプション引数

デフォルト値を設定した引数を持つ関数を定義できます。

julia> function optionalarg(a=10)
           a^2
       end
optionalarg (generic function with 2 methods)

julia> optionalarg()
100

julia> optionalarg(2)
4

キーワード引数

キーワード引数を定義する事もできます。 キーワード引数は、引数の宣言部分で、;(セミコロン)の後に記述します。

julia> function keywordarg(x; key=10)
           x + key
       end
keywordarg (generic function with 1 method)

julia> keywordarg(10, key=100)
110

フロー制御

Juliaのフロー制御には主に以下のものができます。

  • ブロック
    • begin-end
    • ;チェイン
  • 条件分岐
    • if-elseif-else
  • 繰り返し
    • while
    • for
  • 例外
    • try-catcherrorthrow

ブロック

begin-end;チェインを使って、ブロックを作成することができます。

julia> x = begin
         a = 100
         b = 3
         a * b
       end
300

julia> x
300

julia> x = (a = 100; b = 100; a + b)
200

julia> x
200

条件分岐

if-elseif-elseで条件分岐することができます。

julia> function f(p::Char)
           if p == 'J'
               println("Julia")
           elseif p == 'P'
               println("Python")
           elseif p == 'R'
               println("Ruby")
           else
               println("Unknown")
           end
       end
f (generic function with 3 methods)

julia> f('J')
Julia

julia> f('P')
Python

繰り返し評価

他の多くの言語と同様に繰り返し処理は、while文かfor文を使えます。 whileは以下です。

julia> counter = 0
0

julia> while counter < 3
           println("counter = $counter")
           global counter += 1
       end
counter = 0
counter = 1
counter = 2

forは以下です。

julia> for counter = 0:2
           println("counter = $counter")
       end
counter = 0
counter = 1
counter = 2

例外制御

組み込み済みの例外は以下のものが用意されています。

  • Exception
  • ArgumentError
  • BoundsError
  • CompositeException
  • DimensionMismatch
  • DivideError
  • DomainError
  • EOFError
  • ErrorException
  • InexactError
  • InitError
  • InterruptException
  • InvalidStateException
  • KeyError
  • LoadError
  • OutOfMemoryError
  • ReadOnlyMemoryError
  • RemoteException
  • MethodError
  • OverflowError
  • Meta.ParseError
  • SystemError
  • TypeError
  • UndefRefError
  • UndefVarError
  • StringIndexError

例外を投げるには、throw関数を使います。

julia> function throwerror()
           throw(DomainError("test"))
       end
throwerror (generic function with 1 method)

julia> throwerror()
ERROR: DomainError with test:

Stacktrace:
 [1] throwerror() at ./REPL[51]:2
 [2] top-level scope at REPL[52]:1

例外が発生した際の制御は、try-catchを使います。

julia> try
           throw(DomainError("test"))
       catch e
           println("Catch error")
       end
Catch error

まとめ

まだ、全ての機能をさわれていな意ですが、Juliaのマニュアルを読んでどのような機能があるのか確認しました。 数学的な記述方法でコードを書くための機能が充実している印象を受けました。 他にもmacroなどいろいろな機能があるので、後々試してみたいと思います。