2012年6月27日水曜日

Scala Tips / Reducer (3) - モノイド化

前前回はIntとIntMultiplicationを結びつけるIntProductRecuder、前回は任意の型TとList[T]を結びつけるListReducerについて説明しました。

Reducerは、「あるクラス」と「あるクラス」に対する別モノイド演算を定義した「別のクラス」を結びつける演算を行うオブジェクトです。元のクラスである「あるクラス」をC、「追加のモノイド演算」と「あるクラス」を結びつける「別のクラス」をMと表記することにします。

IntProductReducerの場合CはInt、MはIntMultiplicationです。またListReducerの場合はCは任意の型T、MはListです。

ここで着目したいのはMはMonoidでなければなりませんが、Cは任意の型でよいという点です。つまりReducerはモノイド演算を持たない任意のクラスに対してモノイド演算を行うためのツールとして使うことができるということです。

例を使って考えてみましょう。

ケースクラスPersonを定義します。

scala> case class Person(name: String)
defined class Person

Monoidにするための設定はしていないので当然Monoidではありません。モノイド演算の演算子|+|はMonoidの親型クラスSemigroupで定義しているので、PersonはSemigroupでない、というエラーになります。

scala> Person("Taro") |+| Person("Hanako")
<console>:16: error: could not find implicit value for parameter s: scalaz.Semigroup[Person]
              Person("Taro") |+| Person("Hanako")
                             ^

Personに対してListによるモノイド演算を行うためにListRecuderを取得します。

scala> val r = ListReducer[Person]
r: scalaz.Reducer[Person,List[Person]] = scalaz.Reducers$$anon$1@62bb8ae8

ListReducerのunitメソッドを使ってPersonをList[Person]にします。

scala> r.unit(Person("Taro"))
res7: List[Person] = List(Person(Taro))

consメソッドを使って、2をList(3)の左側からモノイド演算すると以下になります。

scala> r.cons(Person("Hanako"), r.unit(Person("Taro")))
res8: List[Person] = List(Person(Hanako), Person(Taro))

snocメソッドを使って、2をList(3)の右側からモノイド演算すると以下になります。

scala> r.snoc(r.unit(Person("Taro")), Person("Hanako"))
res9: List[Person] = List(Person(Taro), Person(Hanako))

List

参考のために以上の処理をListを直接使って書くと以下になります。

scala> List(Person("Taro"))
res10: List[Person] = List(Person(Taro))

scala> Person("Hanako") :: List(Person("Taro"))
res11: List[Person] = List(Person(Hanako), Person(Taro))

scala> List(Person("Taro")) :+ Person("Hanako")
res12: List[Person] = List(Person(Taro), Person(Hanako))

諸元

  • Scala 2.9.2
  • Scalaz 6.0.4

0 件のコメント:

コメントを投稿