http://research.microsoft.com/en- us/um/cambridge/projects/fsharp/default.aspx – Standard ML of New Jersey (SML/nj) http://www.smlnj.org/ – Alice http://www.ps.uni-saarland.de/alice/ – SML# http://www.pllab.riec.tohoku.ac.jp/smlsharp/ja/ • Haskell • Closure • Concurrent Clean • Lisp/scheme
15 and foobar2 = 20;; let testfunc a = print_string “answer is “; print_int (a + 30) ;; let testfunc a b = a + b;; let testfun a:int = a;; • スコープ付き変数・関数の定義 let foobar = 10 in foobar + 10 ;; • 名前無し関数(closure)定義 fun a -> a + 10;; let testfunc a b = a + b;; ===== let testfunc = fun a b -> a + b;; 連続した命令は”;”で分ける これは再代入とは違うので注意!! (新規に領域を作って名前をbindしている) 引数の型は明示的にも宣言可
= 10 A = 0 A = 10 let testFunc a = let rec testFun1 a b = if (a < 1) then b else testFun1 (a-1) (b+a) in testFun1 a 0 末尾再帰! testFun1 10 0 testFun1 10 0 testFun1 9 10 testFun1 8 19 … testFun1 0 55 testFun1 0 55 55
a = if (a < 1) then 0 else a + testFun (a-1) # testFun 100000000;; Stack overflow during evaluation (looping recursion?). let rec testFun a b = if (a < 1) then b else testFun (a-1) (b+a) # testFun 1000000000;; - : int = 5000000050000000 非末尾再帰で一億 末尾再帰で十億
int; b : int; };; type pair_of_ints = { a : int; b : int; } # {a = 10; b = 20};; - : pair_of_ints = {a = 10; b = 20} # let p = {a = 10; b = 20};; val p : pair_of_ints = {a = 10; b = 20} # p.a;; - : int = 10 # let {a=k; b=l} = p;; val k : int = 10 val l : int = 20 レコード定義c 書けば型は推論 取るときは”.”を 使って こうやってもOK
{ enum type_ { TEST_VOID, TEST_INT, TEST_FLOAT, TEST_CHAR } type; union { int i; float d; char c; } val; } foobar; # type foobar = Void | Int of int | Float of float | Char of char | Pair of (int * int);; type foobar = Void | Int of int | Float of float | Char of string | Pair of (int * int) 非常にシンプル!
: foobar = Pair (10, 20) # let Pair(a,b) = p;; Warning P: this pattern-matching is not exhaustive. Here is an example of a value that is not matched: (Char _|Float _|Int _|Void) val a : int = 10 val b : int = 20 # let p = (10,20);; val p : int * int = (10, 20) # let (a, b) = p;; val a : int = 10 val b : int = 20 # let (a, _) = p;; val a : int = 10 # しかしやや強引 単に値を取る場合 ペア等には有効 “_”で値を無視
-> "Void" | Int a when a > 100 -> "BigInt" | Int _ -> "Int" | _ -> "Others";; val foobarToStr : foobar -> string = <fun> # foobarToStr (Int 10);; - : string = "Int" # foobarToStr (Int 200);; - : string = "BigInt" # let foob# let foobarToStr a = match a with Void -> "Void" | Int _ -> "Int" | Int a when a > 100 -> "BigInt" | _ -> "Others";; Warning U: this match case is unused. val foobarToStr : foobar -> string = <fun> # foobarToStr (Int 200);; - : string = "Int" When で 条件追加 比較は上から順番 なのでこの場合 BigIntが無視
: 'a * 'b -> 'b = <fun> ペアの右を 返す関数 ‘a , ‘b : “型”の変数で’どんな型が来ても構わない’ということ. ‘a と’bが同じでも構わない.ただし一回目の’bと二回目の’bは同じ # let getHead (h::t) = h;; Warning P: this pattern-matching is not exhaustive. Here is an example of a value that is not matched: [] val getHead : 'a list -> 'a = <fun> # let getHead l = match l with (h::t) -> Some h | [] -> None;; val getHead : 'a list -> 'a option = <fun> どんな型のリスト も対応する関数
; b : int; };; type 'a pairs = { a : 'a; b : int; } # type 'a tree = None | Node of ('a * 'a tree * 'a tree);; type 'a tree = None | Node of ('a * 'a tree * 'a tree) # Node(10, Node(20, None, None), Node(30, None, None));; - : int tree = Node (10, Node (20, None, None), Node (30, None, None)) # 多相型レコード 多相型バリアントで バイナリツリー 10 20 30