2012年6月5日火曜日

わたしのScalazプログラミングその2

型クラスについて。

例によって有理数で。

case class Rational(n: Int, d: Int)
view raw rational1.scala hosted with ❤ by GitHub

Groupのインスタンスを定義します。
Groupとは、結合演算子、単位元、逆元を持つもののことです。

trait RationalInstances {
implicit object rationalInstance extends Group[Rational] {
def zero = Rational(0, 1)
def inverse(r: Rational) = Rational(-r.n, r.d)
def append(r1: Rational, r2: => Rational) =
Rational(r1.n * r2.d + r2.n * r1.d, r1.d * r2.d)
}
}
object Rational extends RationalInstances
view raw rational2.scala hosted with ❤ by GitHub

動かしてみる。

scala> import scalaz._, Scalaz._
import scalaz._
import Scalaz._
scala> Rational(1, 2) |+| Rational(2, 3)
res0: Rational = Rational(7,6)
scala> Rational(1, 2) |-| Rational(2, 3)
res1: Rational = Rational(-1,6)
scala> Rational(1, 2) multiply 2
res2: Rational = Rational(4,4)
scala> -Rational(1, 2)
res3: Rational = Rational(-1,2)
view raw repl1.scala hosted with ❤ by GitHub

Groupのインスタンスを定義するだけでこれだけのことができます。

自分でデータ型を定義するときは、インスタンス自体に関数を定義より、データ型にメソッドとして定義したほうがいいかもしれません。
また、Groupのインスタンスからメソッドが定義できます。

case class Rational(n: Int, d: Int) {
def +(r: Rational) =
Rational(n * r.d + r.n * d, d * r.d)
def -(r: Rational) =
Rational.rationalInstance.minus(this, r)
def unary_- = Rational(-n, d)
}
trait RationalInstances { self: Rational.type =>
implicit object rationalInstance extends Group[Rational] {
def zero = Rational(0, 1)
def inverse(r: Rational) = -r
def append(r1: Rational, r2: => Rational) = r1 + r2
}
}
object Rational extends RationalInstances
view raw rational4.scala hosted with ❤ by GitHub

scala> Rational(1, 2) + Rational(2, 3)
res0: Rational = Rational(7,6)
scala> Rational(1, 2) - Rational(2, 3)
res1: Rational = Rational(-1,6)
view raw repl2.scala hosted with ❤ by GitHub

乗算、除算も定義してみます。

import scalaz._, Scalaz._, Tags._
case class Rational(n: Int, d: Int) {
def +(r: Rational) =
Rational(n * r.d + r.n * d, d * r.d)
def -(r: Rational) =
Rational.rationalInstance.minus(this, r)
def *(r: Rational) =
Rational(n * r.n, r.d * d)
def /(r: Rational): Rational =
Rational.rationalMultiplicationInstance.minus(Tag(this), Tag(r))
def unary_- = Rational(-n, d)
def unary_~ = Rational(d, n)
}
trait RationalInstances { self: Rational.type =>
implicit object rationalInstance extends Group[Rational] {
def zero = Rational(0, 1)
def inverse(r: Rational) = -r
def append(r1: Rational, r2: => Rational) = r1 + r2
}
implicit object rationalMultiplicationInstance extends Group[Rational @@ Multiplication] {
def zero = Tag(Rational(1, 1))
def inverse(r: Rational @@ Multiplication) = Tag(~r)
def append(r1: Rational @@ Multiplication, r2: => Rational @@ Multiplication) =
Tag(r1 * r2)
}
}
object Rational extends RationalInstances
view raw rational5.scala hosted with ❤ by GitHub

scala> import scalaz._, Scalaz._, Tags._
import scalaz._
import Scalaz._
scala> Rational(1, 2) * Rational(2, 3)
res0: Rational = Rational(2,6)
scala> Rational(1, 2) / Rational(2, 3)
res1: Rational = Rational(3,4)
scala> Foldable[List].fold(List(Rational(1, 2), Rational(2, 3)))
res2: Rational = Rational(7,6)
scala> Foldable[List].fold(List(Tag[Rational, Multiplication](Rational(1, 2)), Tag[Rational, Multiplication](Rational(2, 3))))
res3: scalaz.package.@@[Rational,scalaz.Tags.Multiplication] = Rational(2, 6)
view raw repl3.scala hosted with ❤ by GitHub

べんり!

0 件のコメント:

コメントを投稿