ちょっと便利な関数の紹介

(* この記事は、F# Advent Calendar 2011の16日目の記事です。 *)

こんにちは、mzpです。 クリスマスたのしみですね。
さて、関数型プログラマは自分だけの関数を持っていることが多いものです。 ライブラリ化にするほどの規模でないので、コピペによって各プロジェクトを移動しながら、洗練されたり新しいオペレータが追加されれたりします。
というわけで今日はOCamlハカーのosiireさんのオペレータを紹介していきます。

F#標準

まずはF#だと不要な関数です。

let id x = x
let (@@) f x = f x
let (+>) f g = g f
let (+$) f g x = f (g x)

それぞれid, (<|), (|>),(<<)に対応してます。「え、こんなのもデフォルトで定義されてないんですか(笑)」と言うと効率的にOCamlerをdisれるのでおすすめです。

Haskellからの輸入

Haskellで定義されている関数を輸入した関数です。

let curry f x y = f (x, y)
let uncurry f (x, y) = f x y
let flip f x y = f y x

順番を入れ替えたりできるので、引数の形を変更するだけの無名関数を書くのを避けれます。

> List.map (fun (x,y) -> x + y) [(1,2); (3,4)] 
val it : int list = [3; 7]

> List.map (uncurry (+)) [(1,2); (3,4)]
val it : int list = [3; 7]

無限ループ

無限ループするための関数です。

let rec forever f x =
  let v = f x in
  forever f v

同じ処理を繰り返すプログラムの本体部分で使ったりします。

let _ =
  forever read_eval_print ()

例外とOption型の変換

let maybe f x = try Some (f x) with e -> None
let may x f = match x with None -> None | Some v -> Some (f v)
let may_default d f = function Some v -> f v | None -> d
let default d = function Some v -> v | None -> d

option型を返さずに例外を投げてくる関数を扱うための関数です。

maybe List.hd xs
|> may do_something_for_head
|> default 0

ただ複数引数とる関数の場合は、ちょっと不恰好になります。

(* List.tryFind相当 *)
maybe (List.find x) xs

デバッグ

let tee f x = ignore (f x); x

Unixのteeコマンドのように処理を挟みこんだりするときに便利です。

do_A ()
|> do_B
|> tee printfn
|> do_C

みたいにすれば、パイプライン中の値を覗けます。

最後に

人のコード読むのはたのしいですね。