Fight the Future


ScalaのAdvanced Exampleを写経する(6)-extractor

ScalaのAdvanced Exampleを写経する(5)-case class - Fight the Future じゅくのblogを変更したソース。
extractorPatterns.scala | The Scala Programming Language


package sample.snippet

object ExtractorPatterns {
  /** Here, er replaced case classes of Patterns.scala
   * with objects that hide the actual implementation of Blanch and Leaf.
   * Note that the remaining code does not change.
   * In this way, we can change the implementation lator without affecting clients,
   * which is called representation independence.
  abstract class Tree
  object Branch {
    /* method to contruct brancheds @see ExtractorPatterns.tree1 */
    def apply(left: Tree, right: Tree): Tree = {
      println("Branch#apply is called.")
      new BranchImpl(left, right)
    /* extractor method referenced in match expressions @see RxtractorPatterns.sumLeave */
    def unapply(x: Tree): Option[(Tree, Tree)] ={
      println("Brach#unapply is called.")      
	    x match {
	      case y:BranchImpl => Some(y.left, y.right)
	      case _ => None
    private class BranchImpl(val left: Tree, val right: Tree) extends Tree
  object Leaf {
    def apply(x: Int): Tree = {
      println("Leaf#apply is called. x = " + x)
      new LeafImpl(x)
    def unapply(x: Tree): Option[Int] = {
      println("Leaf#unapply is called.")
      x match {
        case y: LeafImpl => Some(y.x)
        case _ => None
    private class LeafImpl(val x: Int) extends Tree
  /** Here, the task of the case class condtructor is perfomed by the 
   * method Branch.apply - the singleton Branch is treated as if it 
   * were a function value. This trick words with any value that
   * has apply method.
  val tree1 = Branch(Branch(Leaf(1), Leaf(2)), Branch(Leaf(3), Leaf(4)))
  /** For extractors, it is not the name of a case class, but the name of
   * the singleton object Branch which is used to refer to its extractor method
   * Branch.unapply - the pattern is the 'reverse' of a method
   * call, with the result being matched in the subpatterns. This works
   * for any value that has an appropriate extractor method.
  def sumLeaves(t: Tree): Int = t match {
    case Branch(l, r) => sumLeaves(l) + sumLeaves(r)
    case Leaf(x) => x
  def find[A, B](it: Iterator[Pair[A, B]], x: A): Option[B] = {
    var result: Option[B] = None
    while(it.hasNext && result == None) {
      val Pair(x1, y) =;
      if(x == x1) result = Some(y)
  def printFinds[A](xs: List[Pair[A, String]], x: A) = 
    find(xs.elements, x) match {
      case Some(y) => println(y)
      case None => println("no match")
  def main(args: Array[String]) {
    println("main starts.")
    println("sum of leafs = " + sumLeaves(tree1))
    val l = List(Pair(3, "three"), Pair(4, "four"))
    printFinds(l, 4)
    printFinds(l, 10)





Leaf#apply is called. x = 1
Leaf#apply is called. x = 2
Branch#apply is called.
Leaf#apply is called. x = 3
Leaf#apply is called. x = 4
Branch#apply is called.
Branch#apply is called.
main starts.
Brach#unapply is called.
Brach#unapply is called.
Brach#unapply is called.
Leaf#unapply is called.
Brach#unapply is called.
Leaf#unapply is called.
Brach#unapply is called.
Brach#unapply is called.
Leaf#unapply is called.
Brach#unapply is called.
Leaf#unapply is called.
sum of leafs = 10
no match