OCaml熱さいかい(三日坊主になりませんように)

大学の図書館でThe Little Schemerを探したら貸し出し中だったので、なんかおもしれー本ねーかなーと探していたらThe Little MLerなる本を見つけた。おもしろそうなので借りた。読んだ。おもしろい。ちんたら読んでるので前の方しかまだ読んでないけど、パターンマッチパターンマッチパターンマッチ。

そんなわけで、よしMLで遊ぼうと思った。で、StandardMLとOCamlのどっちにしようかなと迷ったけれども、http://www.mpi-sws.mpg.de/~rossberg/sml-vs-ocaml.html を見て、OCamlはなんでもletで束縛するのが好みで、逆にSMLは~1.0、andalso、orelseみたいなのが嫌かもと思ったのでOCamlに。

The Little MLerに出てくるプログラム片はこんなの。

# fact 5;;
- : int = 120
# type shish_kebab = Skewer
  | Onion of shish_kebab
  | Lamb of shish_kebab
  | Tomato of shish_kebab;;
type shish_kebab =
    Skewer
  | Onion of shish_kebab
  | Lamb of shish_kebab
  | Tomato of shish_kebab
# Skewer;;
- : shish_kebab = Skewer
# Lamb(Skewer);;
- : shish_kebab = Lamb Skewer
# let rec only_onions = function Skewer -> true | Onion(x) -> only_onions(x)
  | Lamb(x) -> false | Tomato(x) -> false;;
val only_onions : shish_kebab -> bool = <fun>
# only_onions(Lamb(Skewer));;
- : bool = false
# only_onions(Onion(Lamb(Onion(Skewer))));;
- : bool = false
# only_onions(Onion(Onion(Onion(Skewer))));;
- : bool = true

本に載ってるのはSMLのコードですけど。

パターンマッチ使っていつぞ書いたfactとか書くとこうか。

# let rec fact = function 0 -> 1 | n -> n*(fact (n-1));;
val fact : int -> int = <fun>
# fact 10;;
- : int = 3628800

リファレンス。http://caml.inria.fr/pub/docs/manual-ocaml/index.html
日本語もあった。http://ocaml.jp/archive/ocaml-manual-3.06-ja/

SICPっぽくすると

末尾再帰で。こうか。途中の(0,a)とかはたぶんtupleとかいうやつ。

# let fact x =
    let rec f = function (0,a) -> a | (x,a) -> f(x-1,a*x) in
  f(x,1);;
val fact : int -> int = <fun>
# fact 10;;
- : int = 3628800

リストを逆順に並べるとか。

# let rec my_reverse = function [] -> [] | hd::tl -> (my_reverse tl) @ [hd];;
val my_reverse : 'a list -> 'a list = <fun>
# my_reverse [1;2;3;4;];;
- : int list = [4; 3; 2; 1]
# let my_reverse ls =
    let rec rev = function ([],rls) -> rls | (hd::tl,rls) -> rev(tl, [hd]@rls) in
  rev (ls,[]);;
val my_reverse : 'a list -> 'a list = <fun>
# my_reverse [1;2;3;4];;
- : int list = [4; 3; 2; 1]

ふむ。パタンマッチいいなこれは確かに。hd::tlはcar::cdrと書くとLisperに優しいですね。

test