OCamlでElmのMaybe.map2を実装

OCamlには標準でOption.map関数が有ります。 コレは、Optionな値一つと、それを処理する関数fを渡してあげることで、map関数はOptionな値の中身を取り出して、関数fにその値を渡して実行してくれる、というものです。 Noneが渡されれば渡した関数fは実行されずにNoneがそのまま返されます。 渡した関数fの実行結果はOption.map関数によって自動的にSomeに包まれます。 関数内で態々Optionの中身をアンラップしなくて良いのでコードの見通しが良くなりますね!

utop # Some 10 |> Option.map (fun v -> v + 1) |> Option.map (fun v -> v * 2);;
- : int option = Some 22

utop # None |> Option.map (fun v -> v + 1) |> Option.map (fun v -> v * 2);;
- : int option = None

Option.map関数の使いどころは、最初に「有るかもしれないし、無いかもしれない」というデータを得て、もしデータが存在している(Some)ならそのデータを使って処理を継続していく、途中で自分からOptionな値を返す必要がない、という普通のロジックの場合です。 (もし途中でSomeNoneを返したい場合にはOption.bindを使います)

しかし、map関数が受け取るのはあくまで一つのOptionの値のみです。 例えば2つのOptionな値を渡すことはできません。

Elmではそのために、Maybe.map2という関数が有ります。 OCamlには標準ではそのような関数は存在しませんが、以下のように簡単に自分で実装することが可能です。

utop # let option_map2 f a b =
match (a, b) with
| (None, Some _)
| (Some _, None)
| (None, None) -> None
| (Some v1, Some v2) -> Some (f v1 v2);;
val option_map2 : ('a -> 'b -> 'c) -> 'a option -> 'b option -> 'c option =
  <fun>

実際に試すと以下のようになります。

utop # option_map2 (fun a b -> a + b) None None |> option_map2 (fun a b -> a * b) (Some 10);;
- : int option = None

utop # option_map2 (fun a b -> a + b) None (Some 1) |> option_map2 (fun a b -> a * b) (Some 10);;
- : int option = None

utop # option_map2 (fun a b -> a + b) (Some 1) None |> option_map2 (fun a b -> a * b) (Some 10);;
- : int option = None

utop # option_map2 (fun a b -> a + b) (Some 1) (Some 2) |> option_map2 (fun a b -> a * b) (Some 10);;
- : int option = Some 30

非常に便利になりました。

公開日:2020/07/10

OCaml

About me

ドイツの現地企業でWeb Developer/System Administratorとして働いているアラフォーおじさんです。

プログラミングとかコンピュータに関する事がメインですが、日常的なメモとか雑多なことも書きます。

Links :
目次