次の型をもつ関数を定義せよ.
'a * ('b, 'c) sum -> ('a * 'b, 'a * 'c) sum
let f1 (x, y) = match y with Left n -> Left (x, n) | Right n -> Right (x, n);;
('a, 'b) sum * ('c, 'd) sum -> (('a * 'c, 'b * 'd) sum, ('a * 'd, 'b * 'c) sum) sum
let f2 (x, y) = match (x, y) with (Left n, Left m) -> Left (Left (n, m)) | (Left n, Right m) -> Right (Left (n, m)) | (Right n, Left m) -> Right (Right (n, m)) | (Right n, Right m) -> Left (Right (n, m));;
('a -> 'b) * ('c -> 'b) -> ('a, 'c) sum -> 'b
let f3 (x, y) = function Left m -> x m | Right m -> y m;;
(('a, 'b) sum -> 'c) -> ('a -> 'c) * ('b -> 'c)
let f4 f = (fun x -> f(Left x), fun y -> f(Right y));;
('a -> 'b, 'a -> 'c) sum -> ('a -> ('b,'c) sum)
let f5 = function Left l -> (fun x -> Left (l x)) | Right r -> (fun x -> Right (r x));;
ただし,
type ('a, 'b) sum = Left of 'a | Right of 'b;;
ref型を
type 'a ref = { mutable contents : 'a};;
こんな定義の更新可能レコードと見て, 関数ref, 前置演算子!, 中置演算子:= をレコード操作で書け.
# let ref x = { contents = x } ;; val ref : 'a -> 'a ref = <fun>
# let ( ! ) x = x.contents ;; val ( ! ) : 'a ref -> 'a = <fun>
# let ( := ) x y = x.contents <- y;; val ( := ) : 'a ref -> 'a -> unit = <fun>
整数の参照をインクリメントする関数incr
# let incr x = x := !x + 1;; val incr : int ref -> unit = <fun>
# let f = ref (fun y -> y+1) let funny_fact x = if x = 1 then 1 else x * (!f(x-1));; # f := funny_fact;; # funny_fact 5;;
let fは単に関数の参照が用意したいだけで,funで定義された関数の中身に意味は無い.
f := funny_factによりfがfunny_factをさすようになる.
その結果,funny_factの定義中の!fが自分自身(funny_fact)を呼ぶ事になり,
階乗を素直に再帰的に定義した時と同じ形になっている.
# let fact_imp n = let i = ref n and res = ref 1 in while ( !i > 0 ) do res := !res * !i; i := !i - 1 done; !res;; val fact_imp : int -> int = <fun>