2. 多相再帰って何?
再帰を一つ進める前と後とで型が異なること。
datatype a Seq = NIL' | CONS' of a * (a * a) Seq
fun sizeS NIL' = 0
| sizeS (CONS' (x, ps)) = 1 + 2 * sizeS ps
sizeS関数の型は...
☆ 左辺 => sizeS: a Seq -> int
☆ 右辺 => sizeS: (a * a) Seq -> int
4. 多相再帰=>単相再帰
datatype a Seq = NIL' | CONS' of a * (a * a) Seq
↓単相へ変換
datatype a EP = ELEM of a | PAIR of a EP * a EP
datatype a Seq = NIL' | CONS' of a EP * a Seq
のように多相再帰=>単相再帰への変換が必
ず可能です。
6. OCamlだと
type 'a my_seq = Nil | Cons of 'a * ('a * 'a) my_seq
let rec sizeS : 'a. 'a my_seq -> int = function
| Nil -> 0
| Cons (_, my_seq) -> 1 + 2 * sizeS my_seq
OCaml 3.12.0 以降であれば、関数に直接型
宣言書くだけでOK。
7. Haskellだと
data MySeq a = MSNil | MSCons (a, MySeq (a,a))
sizeS :: MySeq a -> Int
sizeS MSNil = 0
sizeS (MSCons (_, ps)) = 1 + 2 * sizeS ps
こちらも型宣言書けば問題ない。
8. 再帰関数に型宣言付けるのがキモ
型宣言を付けないと、こんなエラーになってしま
います。
MySeq.hs:7:40:
Occurs check: cannot construct the infinite type: t0 = (t0, t0)
Expected type: MySeq t0
Actual type: MySeq (t0, t0)
In the first argument of `sizeS', namely `ps'
In the second argument of `(*)', namely `sizeS ps'
型変数t0が何者なのか調べようとして、発散し
てしまうらしい。