Tutorial
Hello, World! プログラム
コンソールに Hello, World! と表示するMudプログラムはこんなふうです。
puts "Hello, World!"
これを プレイグラウンド のエディターに入力して実行すると、こう表示されます。
Hello, World!
もしくは mud コマンドを インストール することもできます(しないと思うけど)。 上記の内容を hello.mu として保存すると、以下のように実行できます。
% mud run hello.mu
Hello, World!
四則演算
四則演算のような計算は通常どおりにできます。
(1+2)*3 #=> 9
2*3.3 #=> 6.6
(上の例の #=> は、左側を評価した結果が右側になるという意味を表します)
基本的なデータ型
基本的なデータ型としては次の5つがあります。
- 整数 (Int) : 例 42
- 倍精度浮動小数点数 (Double) : 例 1.23
- 文字列 (String) : 例 “hello, world”
- 真偽値 (Bool) : True, False の二つのみ
- リスト ([a]) : 例 [1,2,3]
文字列は + で連結することができます。
"hello " + "world" #=> "hello world"
リスト も + で連結できます。
[1,2,3] + [4,5] #=> [1,2,3,4,5]
リストの各要素は同じ型である必要があります。 たとえば [1,2,3] は型 [Int] を持ち、 [“hello”, “mud”] は 型 [String] を持つことになります。
変わったところでは、真偽値も + 演算を持っています。
True + False #=> True
真偽値に対する + は、論理和を表します。合わせて論理積も * で表すことができます。
True * False #=> False
もちろん、他の言語にある && と || も普通にあります。
True && False #=> False
True || False #=> False
変数
変数の使い方はこんなふうです。
% mud repl
> a=1
1
> b=2
2
> c=a+b
3
(これは mud をREPLモードで実行した例です。> で始まる行がユーザーの入力を、次の行が結果を表しています。)
上の例で c は Int 型を持ちますが、c : Int = a + b のように型を注釈する必要はありません。右辺の値から自動的に型が計算されます。
未定義の変数を参照することはできません。
> c
1:variable 'c' not found.
また、一度定義した変数を再び定義することはできません。
> a=1
1
> a=2
1:variable 'a' already exists
変数名の例は次のようになります。とくに、変数名の最後に ? や ! を使うことができます。
find_devisor
prime?
関数
うけとった整数を2倍にして返す関数 double はこんなふうに書けます。
fun double : Int -> Int = {
x -> x + x
}
double の右側にある : Int -> Int は、関数の型が Int -> Int (整数を受け取って整数を返す) であることを表しています。次の行の x -> x + x は、引数 x を受け取って x + x を返すという意味になります。
double を使って 10 の2倍を計算してみます。
> double 10
20
関数名の後にカッコは必要ありません。
引数が2つの場合の例として、2つの整数を受け取ってそれらを足す関数 add を考えます。
fun add : Int -> Int -> Int = {
x y -> x + y
}
使い方はこうです。
> add 10 20
30
add の型 Int -> Int -> Int は、引数としてInt と Int を受け取り、Int を返すという意味になります。(Haskellを知っている人にはいかにもカリー化されているように見えるかもしれませんが、実際にはそうなってません。)
関数のシンプルな記法
double や add のような簡単な関数は、一行で書くこともできます。
fun double : Int -> Int = x -> x + x
fun add : Int -> Int -> Int = x y -> x + y
さらに関数の型も省略できます。
fun double = x -> x + x
fun add = x y -> x + y
なおかつ fun も省略できます。
double = x -> x + x
add = x y -> x + y
簡単。
パターンマッチ
関数の定義では、<- の左辺にパターンマッチを使うことができます。たとえば、1からnまでを掛け合わせた数を計算する関数 fact は次のように書けます。
fun fact : Int -> Int = {
1 -> 1
n -> n * fact (n-1)
}
fact 5 #=> 120 (=1*2*3*4*5)
本体の「.. -> ..」は、関数の引数が左辺にマッチする場合には右辺を評価するという意味になります。 パターンは上から順にテストされ、最初にマッチした行の右辺が評価されます。
引数が複数ある場合は、-> の左辺に個数分のパターンを並べます。
# mul a b で a * b を計算する
fun mul : Int -> Int -> Int = {
a 1 -> a
a b -> a + mul a (b-1)
}
mul 3 4 #=> 12
”.“演算子によるオブジェクト指向っぽい見た目
いま関数 inc を、整数に1を足したものを返すものとします。
fun inc : Int -> Int = {
x -> x + 1
}
inc 10 #=> 11
このとき、”.” 演算子を使って inc 10 をこうも書けます。
10.inc #=> 11
つまり “.” を使うと関数の第1引数と関数名の順序を入れ替えることができます。 なんとなくオブジェクト指向っぽい見た目でしょう。
次にこんな例を考えてみます。以下で sort はリストをソートする関数、uniq はリストの重複を除く関数、reverse はリストを逆順にする関数とします。
reverse (uniq (sort [2,4,2,1]))
#=> [4,2,1]
これは「リスト [2,4,2,1] をソートし、重複を取り除き、逆順にしたもの」を表します。ただ、その意味をとるためには、式を「右から左に」読む必要があってちょっと読みづらいです。
”.“演算子を連続して使えば、こう書き直すことができます。
[2,4,2,1].sort.uniq.reverse
#=> [4,2,1]
左から右へ、自然に読めるようになりました。これもオブジェクト指向言語(たとえばRuby)なら自然な書き方です。
多重ディスパッチ
関数は、同じ名前でも、引数の型が違えばまったく異なる定義を持つようにできます。
関数が呼ばれた際には、すべての引数の型を見た上でどの定義を呼び出すかが決まります。このような仕組みを多重ディスパッチ(multiple dispatch)といいます。
# 同じ関数名でも引数の型によって異なる関数が呼び出される
fun incr : Int -> Int = {
x -> x + 1
}
fun incr : String -> String = {
'zero' -> 'one'
'one' -> 'two'
'two' -> 'three'
}
incr 2 #=> 3
incr 'two' #=> 'three'
上の例では、incr という関数の定義が2つあります。
整数2を引数に適用した場合には上のほうの定義が呼び出され、結果は3になります。 文字列 ‘two’ の場合は下の定義が呼び出されて ‘three’ になります。
引数が2つ以上の場合は、すべての型の組み合わせごとに異なる定義を与えることができます。
# ベクトルの定数倍
fun * : [Int] -> Int -> [Int] = {
xs y -> xs.map (a -> a * y)
}
[1,2,3] * 3 #=> [3,6,9]
# ベクトルの内積
fun * : [Int] -> [Int] -> Int = {
xs [] -> 0
[] ys -> 0
[x;xs] [y;ys] -> x * y + xs * ys
}
[1,2,3] * [4,5,6] #=> 32 (=1*4+2*5+3*6)
上の例では、同じ掛け算 * の記号を、一つはベクトルの定数倍、一つはベクトルどうしの内積と、まったく違う意味に使い分けています(アドホック多相といいます)。
典型的なオブジェクト指向言語では、ふつうに書くとベクトルクラスの * メソッドを、引数が数の場合とベクトルの場合で場合分けして定義するようなコードになると思いますが、多重ディスパッチのおかげですっきりと書けます。
なお、この言語の名前 Mud は Multiple Dispatch の頭文字から取っています。
インストール
インストールは一応できますが、実際にやる人はいないと思います。よければブラウザーからコードの編集と実行が可能な プレイグラウンド を試してください。
とはいえ、インストール手順は次のとおりです。
1: Haskell の パッケージ管理ツールである stack をインストール
curl -sSL https://get.haskellstack.org/ |
2: 本レポジトリを git clone したのち、以下のコマンドを実行
cd mud
stack build && stack install
3: $HOME/.local/bin/ に mud バイナリが設置されますので、必要であれば $HOME/.local/bin/ を実行パスに追加してください。
4: mud コマンドを実行するとヘルプが表示されます
% mud
Mud is a functional programming language that supports multiple dispatch.
Usage:
mud command [arguments]
The commands are:
run run Mud program
eval run one liner program
repl run read-eval-print loop