- SMLは宣言を並べていく言語
- 宣言同士は
;
で区切れる(省略可)
- REPLの多くは
;
ごとにコンパイルが走る
- 拡張子は
.sml
- シグネチャーは
.sig
- SML#ではインタフェースファイル
.smi
もある
- NJではコンパイル用に
.cm
、MLtonでは.mlb
なども
- 構成、分解の例を使って説明する
- 構成は値の定義方法を表す
- 分解は定義した値の利用方法を表す
- 値を束縛する
- 例の1行目は、「xに1を束縛する」と言う
- 「代入」ではない
- 関数宣言では後述するパターンマッチを引数部に使える
- REPLでは宣言ではなく式を書いて評価すると、
val it =
という宣言として解釈される
(* 構成 *)
val x = 1;
fun add x y = x + y
fun mul 0 _ = 0
| mul x y = x * y;
1.0; (* val it = 1.0;と同意 *)
(* 分解 *)
val r = it;
val a = add 1 2;
(* comment (* nested *) *)
val unit = ()
val char = chr (ord (#"c"))
val string = "str" ^ "ing"
val int = 10 div 2 mod 3
val real = ~1.0
val bool = if true andalso false orelse true
then true
else false
val lambda = fn (x : real) => 3.0 * x + 1.0
(* 構成 *)
val tuple = (1, #"c", "string")
(* 分解 *)
val int = #1 tuple
val c = #2 tuple
- キー付きの値の組を表す
- 実は、前述の組はフィールド名が1から始まる数字ラベルのレコード
(* 構成 *)
val record = {name = "koro", age = 16}
(* 分解 *)
val n = #name record
val a = #age record
- 複数の値の並びを表す
- 言わずと知れた、関数型プログラミングの基本的なデータ構造
(* 構成 *)
val list = []
val list = nil
val list = 1 :: 2 :: nil
val list = [1, 2]
(* 分解 *)
val head = hd list
val tail = tl list
- ある値の「ある」「ない」を表す
null
なんてない
(* 構成 *)
val some = SOME 1
val none = NONE
(* 分解 *)
val int = valOf some
- 数学の再帰的なデータ構造を定義する
- 分解に使われるのはパターンマッチ
- 組・レコード・リスト・オプション等にも使える
_
はワイルドカード、全てにマッチする
- パターンマッチは網羅性のチェックがあるため、ワイルドカードは手軽に使うべきではない
(* 構成 *)
datatype mytype = A | B of int | C
(* 分解、パターンマッチ *)
val a =
case B 1 of
A => 0
| B n => n
| _ => ~1
fun f intOption =
case intOption of
SOME n => n
| NONE => 0
- 宣言内容を一部範囲でしか使えないようにする
let 宣言A in 式B end
とすれば、宣言Aは式Bでしか使えない
local 宣言A in 宣言B end
とすれば、宣言Aは宣言Bでしか使えない
val x =
let
val x = 1
in
x + 1
end
local
val a = 2
in
fun f x = x + a
end
(* 構成 *)
exception Error of string
raise Error "Missed"
(* 分解 *)
raise Error "Missed"
handle e message => print message
- 型や宣言の集まり
type
は型の別名付け
:
を:>
にすると型の実装が隠され、外から見ると隠蔽された型となる
open
でモジュールを展開できるが、名前環境がシャドウイングされる可能性があるためオススメしない
(* 構成 *)
signature MY_SIG =
sig
type t
val zero : () -> t
val succ : t -> t
end
structure MyModule : MY_SIG =
struct
type t = int
fun zero () = 0
fun succ t = t + 1
end
(* 分解 *)
val t = MyModule.zero()
open MyModule
val t = succ t
- ここのこれとかで探す
- SMLはBasisライブラリという基本ライブラリが定義されている
- 各種処理系のライブラリもあるのでそれは各処理系のドキュメント参照
- REPL上で
open
構文を使うと、ライブラリ(正確にはモジュール)の中身がプリントされることが多い
open List
open String
open Word
open Array
open Vector
- モジュールを受け取ってモジュールを作る
val
、type
、structure
などが引数にとれる
(* 構成 *)
signature MY_SIG = (* MY_SIG宣言 *)
sig
type t
val zero : () -> t
val succ : t -> t
end
functor AddSub (structure Module : MY_SIG) = (* ファンクター *)
struct
open Module (* Moduleの中身を展開 *)
fun sub (x : t) = x - 1 (* 関数subを追加 *)
end
(* 分解 *)
structure MyModule : MY_SIG =
struct
type t = int
fun zero () = 0
fun succ t = t + 1
end
structure NewModule = AddSub(MyModule) (* t,zero,succ,subが使える新たなモジュール定義 *)
test
fun id x = x;;