ここは俺の備忘録だ

少なくとも日本語での言及が少ない話をするつもりです

ズンドコOCaml

元ネタと流れ

qiita.com

流行りには乗れ。

コード (ppx_deriving.show)

type zundoko = ZUN | DOKO [@@deriving show]

let rec sing cnt gen = match gen () with
  | DOKO -> if cnt = 4 then print_endline "KIYOSHI!" else sing 0 gen
  | ZUN -> sing (cnt + 1) gen

let () = sing 0 (fun () ->
    let zd = if Random.bool () then ZUN else DOKO in
    print_endline @@ show_zundoko zd; zd)

初めはすごいHな言語の例を受けて「batteriesのLazyListとパターンマッチで数字なんて出てこない!イケイケ!モダン!ヒュー!抱いて!」となる予定だったが汚物が建立したので潔くカウントした。 メモリも無駄にせずリストに有り勝ちな無駄O(n)走査も無くforとifの塊よか簡潔…と思いたい。 文字列で済ませば依存性も無くなるしより短くもなるけれど網羅性を担保せずしてな~にがパターンマッチじゃと実家のキャットに言われたので。

コード(ppx_deriving.show, Batteries.LazyList)

5つのまとまりで考えて良いことを忘れていたので修正した所マシになったため追記。

open Batteries.Legacy
open Batteries.LazyList

type zundoko = ZUN | DOKO [@@deriving show]

let rec sing l = match take 5 l |> to_list with
  | ZUN :: ZUN :: ZUN :: ZUN :: DOKO :: [] -> print_endline "KIYOSHI!"
  | _ -> print_newline (); sing @@ drop 5 l

let () = sing @@ from (fun () ->
    let zd = if Random.bool () then ZUN else DOKO in
    print_endline @@ show_zundoko zd; zd)

LazyListは文字通り遅延リストで、fromに遅延評価時のthunkを渡して生成できる。このthunkでコンソールに出力すれば良い。 あとはリストを5ずつ見て所定の配列になるまで捨てていくだけ。

BatteriesはString.println stdout ~というコードを提供し、標準ライブラリのprint_系を隠してしまう。 細々し過ぎているという気持ちも分からなくもないが、今回は使いたいのでLegacyで引っ張りだしている。

先程と比べ、コードの状態を追わなくても一目瞭然になったのはより「らしいコード」と言えるかもしれない。

広告

速い短い型安全。

改行位置の自由度が高いシンタックスや、言語仕様が複雑じゃない所もポイントです。

正格評価かつ最適化が支配的でないため、計算量の見通しが容易で自身による最適化がコードに反映され易いのも直感的で良し。 (これは受け売り半分ですが…

可能な限り副作用を抑え安全を指向しながらも、冗長になってしまう所は副作用で殴ってしまえるのも1つの力でしょう。

OCamlはいいぞ。