代数型(datatype)を実装したい
今まで、Scalaのソースコードを読んできたのは、
case class の文法が使い勝手が悪いので、
SMLのようなdatatypeを導入したいと思ったからです。
datatypeを実装するとなると、classと同レベルの位置(構文解析上)に実装することになります。
Parsers.scala をみてみると、トップレベルで宣言されたclassと、
それ以外で宣言されたclassとでは多少扱いが違うようです。
トップレベルの処理は、メソッドtopStatSeq()からメソッドtopLevelTmplDefを呼び出して処理されています。
一方、それ以外の場合には、メソッドdefOrDcl()からメソッドtmplDef()を呼び出して処理されています。
そこで、datatypeの実装方法もトップレベルとそれ以外にわけて考えることにします。
文法を決める
まずは、実装したい構文の文法を決定しなければなりません。
参考にする文法は、Soopyのデータタイプ宣言にします。
構文の例をあげていきます。
datatype Week = Mon | Tue | Wed | Thi | Fri | Sat | Sun
これをパターンマッチで次のように使いたいわけです。
val day: Week = Wed()
day match {
case Mon() => "月曜日"
case Tue() => "火曜日"
case Wed() => "水曜日"
case Thi() => "木曜日"
case Fri() => "金曜日"
case Sat() => "土曜日"
case Sun() => "日曜日"
}
これが出来れば、case classを使うより簡単に書けるようになります。
さらに、次のようにメソッドも使えるようにしたいと思っています。
datatype Week {
def isWorkday: Boolean = true
def isHoliday(): Boolean = ! isWorkday
}
= Mon
| Tue
| Wed
| Thi
| Fri
| Sat {
override def isWorkday = false
}
| Sun {
override def isWorkday = false
}
val day1 = Mon()
val day2 = Sun()
println( day1.isWorkday )
println( day1.isHoliday )
println( day2.isWorkday )
println( day2.isHoliday )
もちろん、コンストラクタは引数を取る事も可能にしたいです。
datatype Fig =
Rect(val x: Double, val y: Double){
def area(): Double = x * y
}
| Circle(val r: Double){
val pi = 3.14
def area(): Double = r * r * pi
}
val r = Rect(5, 7)
val c = Circle(8)
val rect_area = r.area()
val circle_area = c.area()
実装方法
Scalaにdatatypeを実装する方法を考えてみましょう。
上で書いたように、case classの文法が冗長なのをなんとかしたくて考えたのが、datatypeになります。実際にできることも、case classとほぼ同じです。
なので、ここではdatatypeをcase classに変換することで、その機能を実現しようと思います。
(つづく)