OCamlで'a option listから'a listを生成する
タイトルだとなんだかよくわかりません。
やりたいことは、option
な値(SomeかNone)が格納されているリストから、Some
な値の中身だけ抽出してリストにしたい、という感じです。
具体的に言うと
[(Some 1); (Some 2); None; (Some3);]
は[1; 2; 3]
という値になります。
自分で再帰関数を定義
コードは以下のとおりです。
utop # let get_reliable_values list =
let rec f result = function
| [] -> result
| head::tail -> begin
match head with
| Some v -> f (v :: result) tail
| None -> f result tail
end
in
f [] list
;;
val get_reliable_values : 'a option list -> 'a list = <fun>
実行結果は
utop # get_reliable_values [(Some 100); None; None; (Some 200); None];;
- : int list = [200; 100]
utop # get_reliable_values [(Some "aaa"); None; None; (Some "bbb"); None];;
- : string list = ["bbb"; "aaa"]
Option.is_someとOption.get
Option
にis_some
という関数が有るのを発見しました。コレを使うことで上記で自作した再帰関数を使わずとも、Listのfilter
とmap
を使うことで簡単に実現することができました。
utop # [(Some 1); None; (Some 2); None; None; (Some 3)]
|> List.filter Option.is_some
|> List.map Option.get;;
- : int list = [1; 2; 3]
Option.get
はもし値がNone
の場合には例外が投げられます。
が、前の処理のfilterの時点でSome
の値だけ抽出しているので例外の起きようがありません。
Listのfilter_map
F#には、そのものズバリなList.choose
という関数が有るようです。
OCamlでは同等の関数がList.filter_map
として存在しています。(OCaml 4.08以降の新機能)
コレまたTwitterで指摘してもらえるまで全く気づけ来ませんでした。。。
utop # [(Some 1); None; (Some 2); None; None; (Some 3)]
|> List.filter_map (fun v -> v);;
- : int list = [1; 2; 3]
まとめ
新しいOCamlを使っているならList.filter_map
を使いましょう!
古いOCamlでもOption.is_some
とOption_get
を使えば簡単に実現できます!
公開日:2020/07/23