Hatena::ブログ(Diary)

みずぴー日記 Twitter

2011-12-16(金)

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

| ちょっと便利な関数の紹介を含むブックマーク

(* この記事は、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

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

最後に

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

mclh46mclh46 2011/12/16 07:35 この記事を読んで、自分のやり方を書いてみました。
http://d.hatena.ne.jp/mclh46/20111216/1323986621
F#の標準のライブラリは、1つの関数、クラスの利用範囲が広く、また弱点のある道具は不採用になっていると思われます。
maybeやteeの考え方はとても参考になりました。

vebbytanakavebbytanaka 2018/06/21 16:05 になっていると思われます。
maybeやteeの考え方はとても参考になりました

pelangi4dpelangi4d 2018/06/21 16:06 つの関数、クラスの利用範囲が広く、また弱点のある道具