ひょっとしたら役に立つかもしれないScala Tips(4) - パターンの漏れを検出する
ScalaでMLやHaskellのalgebraic data typeを模倣するときの定番は、abstract class(or trait)とcase classを使って、
trait Exp case class Add(l: Exp, r: Exp) extends Exp case class Num(v: Int) extends Exp
のようにすることだが、非常に残念なことに、これでは、MLなどと違って、パターンマッチ時にパターンの漏れがあってもコンパイル時にそれを検出することができない。たとえば、
def eval(e: Exp): Int = e match { case Add(l, r) => eval(l) + eval(r) //case Num(...)が抜けてる! }
のようなコードを書いても、コンパイラは警告を出すことなく、黙って受け入れてしまう。このようなことを防ぎ、MLなどと同様に警告を出すようにするには、sealedを使って、
sealed trait Exp case class Add(l: Exp, r: Exp) extends Exp case class Num(v: Int) extends Exp
とすれば良い。このようにすれば、
def eval(e: Exp): Int = e match { case Add(l, r) => eval(l) + eval(r) //case Num(...)が抜けてる! }
のような関数を書くと、コンパイラが
<console>:8: warning: match is not exhaustive! missing combination Num def eval(e: Exp): Int = e match {
のように書き漏らしたパターンを報告してくれるようになる。ちなみに、標準ライブラリのOption型等はsealedを使って書かれているため、書き漏らしたパターンがある場合、ちゃんとコンパイラがそのことを報告してくれる。