OCamlには、いわゆる代数的データ型の一種として、バリアント型(A型の値かもしれないし、B型の値かもしれないし……、を表現する型)と呼ばれるものがあるそうです。
ocaml.orgに載っている、シンプルな二分木を引用します。
(* Binary tree with leaves carrying an integer. *)
type tree = Leaf of int | Node of tree * tree
let rec exists_leaf test tree =
match tree with
| Leaf v -> test v
| Node (left, right) ->
exists_leaf test left
|| exists_leaf test right
let has_even_leaf tree =
exists_leaf (fun n -> n mod 2 = 0) tree
OCamlを読むのは初めてなのですが、文法知らなくても分かりやすいですね。
これをScalaで書いてみたいと思います。Scala標準にバリアント型そのものはないので、どうしたものかというところなのですが……、Effective Scalaの"Case classes as algebraic data types"に答えが載っていて、継承とcase classを使って表現するのが一般的なようです。
OCamlのコードと比較しやすいように書くと、こんな感じ。
sealed trait Tree[T]
case class Leaf[T](v: T) extends Tree[T]
case class Node[T](left: Tree[T], right: Tree[T]) extends Tree[T]
def exists_leaf[T](test: T => Boolean, tree: Tree[T]): Boolean = {
tree match {
case Leaf(v) => test(v)
case Node(left, right) =>
exists_leaf(test, left) ||
exists_leaf(test, right)
}
}
def has_even_leaf(tree: Tree[Int]): Boolean =
exists_leaf[Int](_ % 2 == 0, tree)