Skip to content

Instantly share code, notes, and snippets.

@yonta
Last active February 9, 2022 12:59
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save yonta/0df01ad0fad1bd6eed83 to your computer and use it in GitHub Desktop.
Save yonta/0df01ad0fad1bd6eed83 to your computer and use it in GitHub Desktop.
SML Cheet Sheet

SMLチートシート

  • 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

組、タプル

  • 複数の値の組み合わせを表す
  • n個の組を扱える
(* 構成 *)
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

代数的データ型

  • 数学の再帰的なデータ構造を定義する
  • 分解に使われるのはパターンマッチ
    • 値の判別と束縛を行う
  • 組・レコード・リスト・オプション等にも使える
    • オプションはcaseでパターンマッチすべき
  • _はワイルドカード、全てにマッチする
    • パターンマッチは網羅性のチェックがあるため、ワイルドカードは手軽に使うべきではない
(* 構成 *)
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

例外

  • handleではパターンマッチが使える
(* 構成 *)
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

ファンクター

  • モジュールを受け取ってモジュールを作る
    • valtypestructureなどが引数にとれる
(* 構成 *)
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が使える新たなモジュール定義 *)
@yonta
Copy link
Author

yonta commented Dec 17, 2014

test

fun id x = x;;

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment