【解答例】Scala 代数的データ型 超入門

[Scala 代数的データ型 超入門](http://qiita.com/shigemk2/items/31f6bdbf4dfebb0b9adc)の解答例です。

# 列挙型

【問1】光の三原色と、2つの色を混合する関数`mix`を定義してください。混ぜることによってできる色も定義の対象とします。ただし同じ成分同士は強め合わないものとします。

条件を列挙します。逆の組み合わせを一括処理しているのがポイントです。

```scala:mix.scala
object Color extends Enumeration {
  val Blue, Red, Magenta, Green, Cyan, Yellow, White = Value
}

object Main {
  import Color._

  def mix(a:Color.Value, b:Color.Value): Color.Value = {
    (a, b) match {
      case (Blue, Red)       => Magenta
      case (Blue, Magenta)   => Magenta
      case (Blue, Green)     => Cyan
      case (Blue, Cyan)      => Cyan
      case (Blue, Yellow)    => White
      case (Red, Magenta)    => Magenta
      case (Red, Green)      => Yellow
      case (Red, Cyan)       => White
      case (Red, Yellow)     => Yellow
      case (Magenta, Green)  => White
      case (Magenta, Cyan)   => White
      case (Magenta, Yellow) => White
      case (Green, Cyan)     => Cyan
      case (Green, Yellow)   => Yellow
      case (Cyan, Yellow)    => White
      case (White, _)        => White
      case (a, b) if a == b  => a
      case (a, b)            => mix(b, a)
    }
  }

  def main(args: Array[String]): Unit = {
    println(mix(Red, Red))
    println(mix(Red, Blue))
    println(mix(Blue, mix(Blue, Green)))
  }
}
```
```text:実行結果
Red
Magenta
Cyan
```

# 直積型

【問2】x,y,w,hを表現した`Rect`型を定義して、`Rect`に`Point`が含まれるかどうかを判定する関数`contains`を実装してください。

```scala:rect_answer.scala
sealed trait Coordinates
case class Point(x: Int, y: Int) extends Coordinates
case class Rect(x: Int, y: Int, w: Int, h: Int) extends Coordinates

def contains(r: Rect, p: Point): Boolean = {
  r.x <= p.x && p.x < r.x + r.w && r.y <= p.y && p.y < r.y + r.h
}

println(contains(new Rect(2, 2, 3, 3), new Point(1, 1)))
println(contains(new Rect(2, 2, 3, 3), new Point(2, 2)))
println(contains(new Rect(2, 2, 3, 3), new Point(3, 3)))
println(contains(new Rect(2, 2, 3, 3), new Point(4, 4)))
println(contains(new Rect(2, 2, 3, 3), new Point(5, 5)))

```
```text:実行結果
false
true
true
true
false
```

# 直和型

【問3】`Rect`と`Point`を2次元と3次元の両方に対応させて、問2の`contains`も対応させてください。

```scala:rect3d_answer.scala
sealed trait Coordinates
case class Point(x: Int, y: Int) extends Coordinates
case class Point3D(x: Int, y: Int, z: Int) extends Coordinates
case class Rect(x: Int, y: Int, w: Int, h: Int) extends Coordinates
case class Rect3D(x: Int, y: Int, z: Int, w: Int, h: Int, d: Int) extends Coordinates

def contains(r: Rect, p: Point): Boolean = {
  r.x <= p.x && p.x < r.x + r.w && r.y <= p.y && p.y < r.y + r.h
}

def contains(r: Rect3D, p: Point3D): Boolean = {
  r.x <= p.x && p.x < r.x + r.w &&
  r.y <= p.y && p.y < r.y + r.h &&
  r.z <= p.z && p.z < r.z + r.d
}

println(contains(new Rect(2, 2, 3, 3), new Point(1, 1)))
println(contains(new Rect(2, 2, 3, 3), new Point(2, 2)))
println(contains(new Rect(2, 2, 3, 3), new Point(3, 3)))
println(contains(new Rect(2, 2, 3, 3), new Point(4, 4)))
println(contains(new Rect(2, 2, 3, 3), new Point(5, 5)))
println(contains(new Rect3D(2, 2, 2, 3, 3, 3), new Point3D(1, 1, 1)))
println(contains(new Rect3D(2, 2, 2, 3, 3, 3), new Point3D(2, 2, 2)))
println(contains(new Rect3D(2, 2, 2, 3, 3, 3), new Point3D(3, 3, 3)))
println(contains(new Rect3D(2, 2, 2, 3, 3, 3), new Point3D(4, 4, 4)))
println(contains(new Rect3D(2, 2, 2, 3, 3, 3), new Point3D(5, 5, 5)))
```
```text:実行結果
false
true
true
true
false
false
true
true
true
false
```

# レコード構文

【問4】問2の解答をレコード構文で書き直してください。

```scala.rect_record_answer.scala
sealed trait Coordinates
case class Point(x: Int, y: Int) extends Coordinates
case class Rect(x: Int, y: Int, w: Int, h: Int) extends Coordinates

def contains(r: Rect, p: Point): Boolean = {
  r.x <= p.x && p.x < r.x + r.w && r.y <= p.y && p.y < r.y + r.h
}

println(contains(new Rect(x = 2, y = 2, w = 3, h = 3), new Point(x = 1, y = 1)))
println(contains(new Rect(x = 2, y = 2, w = 3, h = 3), new Point(x = 2, y = 2)))
println(contains(new Rect(x = 2, y = 2, w = 3, h = 3), new Point(x = 3, y = 3)))
println(contains(new Rect(x = 2, y = 2, w = 3, h = 3), new Point(x = 4, y = 4)))
println(contains(new Rect(x = 2, y = 2, w = 3, h = 3), new Point(x = 5, y = 5)))
```

```text:実行結果
false
true
true
true
false
```