code

2016年10月28日 星期五

Scala 筆記16 - Pattern matching

接續前一篇the expression problem,Scala提供了pattern matching的機制:

一個subclass如果在宣告時加上一個case keyword,compiler會建立一個object,並且implement跟constructor一樣參數的apply method,也就是偷偷弄了一個syntatic sugar,可以做此class的factory method:

case class Number(n: Int) extends Expr {
  def isNumber: Boolean = true  def isSum: Boolean = false  def numValue: Int = n
  def leftOp: Expr = throw new Error("Number.leftOp")
  def rightOp: Expr = throw new Error("Number.rightOp")
}

Number(5) //res0: Number = Number(5)

如果沒有case keyword的話,只能用new Number(5)的方式來建立instance。


有了這個case keyword宣告的subclass,我們改寫eval function,用上match..case語法:

def eval(e: Expr): Int = e match {
  case Number(n) => n
  case Sum(e1, e2) => eval(e1) + eval(e2)
}

case後面接的sybmol就是pattern,可以match
1. constructor pattern
2. variable pattern
3. constant pattern

利用patter matching,我們Expr class hierarchy可以改寫成:

trait Expr {}

case class Number(n: Int) extends Expr {}
case class Sum(e1: Expr, e2: Expr) extends Expr {}
case class Prod(e1: Expr, e2: Expr) extends Expr {}
case class Var(x: String) extends Expr {}

def eval(e: Expr): Int = e match {
  case Number(n) => n
  case Sum(e1, e2) => eval(e1) + eval(e2)
}

def show(e: Expr):String = e match {
  case Number(n:Int) => n.toString()
  case Prod(e1: Sum, e2: Expr) => "(" + show(e1) + ") * " + show(e2)
  case Prod(e1: Expr, e2: Expr) => show(e1) + " * " + show(e2)
  case Sum(e1: Expr, e2:Expr) => show(e1) + " + " + show(e2)
  case Var(x: String) => x
}


結論就是用pattern matching可以
1. 避免low-level type matching
2. 避免type classifiers
3. 避免無謂的accessor (例如Expr 中不用再定義numValue這個method,因為在pattern-matching的過程中就能bind到這個value)


沒有留言:

張貼留言