7
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

MLAdvent Calendar 2020

Day 9

OCaml Upcoming Changes 2020: Either

Last updated at Posted at 2020-12-08

この記事はML Advent Calendar 2020 9日目の記事です。

OCamlにそろそろ入りそうな機能を紹介します。

今回は、次のOCaml 4.12で入る Eitherモジュールの紹介をします。

背景

Either.t 型はタプル型の双対で、タプル型 'a * 'b が「'a'b 両方」を表すのに対して、 ('a, 'b) Either.t は「'a または 'b のいずれか」を表す。

either型はOCaml以外にもHaskellやCoq, Scalaといったさまざまな言語に採用されている(この記事ではCoqの sumboolをeither相当として扱う)。

また、Either型には「左派」と「右派」がいることも知られている。コンストラクタが2つだけのinductive typeについて最初のコンストラクタを真値として扱う(if式の仕様)Coqは left を正常値とする左派であり、型パラメータの部分適用ができるHaskellは最後の型パラメータを使う Right が正常値とする右派だ。Scalaは左派、右派どちらでもない中道派だったのだが、2.12(2016年ごろ)から右派になった。

OCamlは、 either は左右中立な型であるべし、ということで、成功/失敗といったバイアスの入ったeither型は別に result 型と呼びならわしている。このような流派には他にRustがある。

そんなOCamlに Either.t が入ったのは、 List.partition_map の導入がきっかけだ。

List.partition_map('a -> ('b, 'c) Either.t) -> 'a List.t -> ('b List.t * 'c List.t) のような型の関数で、mapした関数の戻り値に応じてリストをふたつに分割する。

OCamlでは、このような場合は多相バリアントを使い ('a -> [`Fst of 'b | `Snd of 'c]) -> 'a List.t -> ('b List.t * 'c List.t) のようにして、わざわざ型を定義せずに済ませる人もいた(containersライブラリとか)。今回の List.partition_map のPRも最初は result 型で書かれていたが、 result 型の Ok/Error をそのような意味で使うのは気持ち悪いということで、 Either.t が導入されることになった。

実装

前置きはこのくらいにしてEither モジュールのシグネチャ を見てみよう。とは言っても、実装上面白いことは特にないので型定義と map まわりの関数の型だけ見てみる。

type ('a, 'b) t = Left of 'a | Right of 'b

val map_left : ('a1 -> 'a2) -> ('a1, 'b) t -> ('a2, 'b) t

val map_right : ('b1 -> 'b2) -> ('a, 'b1) t -> ('a, 'b2) t

val map :
  left:('a1 -> 'a2) -> right:('b1 -> 'b2) -> ('a1, 'b1) t -> ('a2, 'b2) t

最初に言っていた通り、OCamlの Either.t は左右に偏らない型なので、 Left にmapする map_leftRight にmapする map_right があり、両方にmapする関数を map と呼んでいる。ラベル付き引数を使っているのがOCamlの標準ライブラリとしては新しめなスタイルだろうか。

他の関数も同様に *_left*_right が用意されている。

おまけ: 他のML語族の言語のeither型

OCamlの御先祖様であるLCF MLには α + β 型という形でeither相当の型が存在した。 α × β なタプル型が生き残ったのに対し、 + の方は現代のMLには受け継がれなかった。この型の値は inl : α → α + βinr : β → α + β といった関数でつくる。

Standard ML 97のBasisライブラリにはeither型は存在しない。 Successor MLではEitherモジュールが提案されており、こちらもOCamlと同じく左右の偏りのない定義になっている。

F#でeither型にあたるのは Choice<'T1, 'T2>だ。判別共用体のタグ名も Choice1Of2Choice2Of2 と、leftやrightといった言葉すら使っていない(F#はリストの畳み込みもfoldfoldBackだったりする)。似たような命名法として、OCamlのJanestreet baseライブラリでは type ('f, 's) t = | First of 'f | Second of 's のようにfirst, secondを使っていたりする。

7
3
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?