2011年12月7日水曜日

Functor

Pure, Functor, Pointed, Apply, Applicative, Bindを倒さないとMonadへはたどり着けない・・・・・

ということでFunctorの紹介。

Functor

Pureと同じように型パラメータを1つとる型を型パラメータにとります。

fmapというコレクションでおなじみのmapと似た関数を持っています。

mapと違うところは要素を包む型が多相であるというところです。

case class Ikamusume[A](value: A)
implicit def IkamusumeEqual[A]: Equal[Ikamusume[A]] = equalA
implicit def IkamusumeShow[A]: Show[Ikamusume[A]] = showA
implicit def IkamusumeFunctor: Functor[Ikamusume] = new Functor[Ikamusume] {
def fmap[A, B](r: Ikamusume[A], f: A => B): Ikamusume[B] = Ikamusume(f(r.value))
}
def mapAppend[M[_]: Functor, A: Semigroup](m: M[A], a: A) = m.map(_ |+| a)
mapAppend(List(1, 2, 4), 2) assert_=== List(3, 4, 6)
mapAppend(Ikamusume(100), 1) assert_=== Ikamusume(101)
view raw functor1.scala hosted with ❤ by GitHub

Identity

mapply

値を内包された関数に適用します。

1.mapply((1 |+| (_: Int)).some) assert_=== 2.some
List(1).mapply(List(1 +>: (_: List[Int]), (_: List[Int]) |+| List(1, 1))) assert_=== List(List(1, 1), List(1, 1, 1))
view raw functor3.scala hosted with ❤ by GitHub

MA

map, map2, >|

mapは関数を渡し、内包する値に適用します。
map2はFunctorがネストしている場合に利用でき、ma.map(_.map(f))と等価です。
>| は値を渡し、その値で塗りつぶします。

(1, 2).map(1 +) assert_=== (1, 3)
((_: Int) + 1).map(2 *).apply(5) assert_=== 12
List(1.some, 2.some, 4.some).map2[Option, Int, Int](2 +) assert_=== List(3.some, 4.some, 6.some)
List(List(1, 2, 3), List(2, 2, 2)).map2[List, Int, Int](2 *) assert_=== List(2.replicate[List](3, _ |+| 2), 4.replicate[List](3))
1.replicate[Stream](5) >| 3 assert_=== 3.replicate[Stream](5)
view raw functor2.scala hosted with ❤ by GitHub

fpair, fpure

fpairは内包された値のペアを作ります。
fpureは内包された値を指定した型で包みます。

1.some.fpair assert_=== Some((1, 1))
List(1, 2, 3).fpair assert_=== List((1,1), (2,2), (3,3))
1.some.fpure[List] assert_=== Some(List(1))
List(1, 2, 3).fpure[Option] assert_=== List(Some(1), Some(2), Some(3))
view raw functor4.scala hosted with ❤ by GitHub

comp

Option[List[Int]]をMA[M[_], A]とみなすとき、MにOptionが、AにList[Int]が適用されMA[Option, List[Int]]となります。
compではMにOption[List[_]]を、AにIntを適用したMA[({ type X[A] = Option[List[A]] })#X, Int]を返します。
MAの型としては型の部分適用されたものが返るので普通の型クラスは対応していません。
しかしCompをインポートすることでApplicativeとFunctorのimplicit valueを得ることができます。

import Comp._
List.fill(2, 2)(1).comp.map(10 *) assert_=== List.fill(2, 2)(10)
List(1).some.comp.fpure[Option] assert_=== List(1.some).some
Ikamusume(100).some.comp.map(2 *) assert_=== Ikamusume(200).some
view raw functor5.scala hosted with ❤ by GitHub

InvariantFunctor

FunctorはInvatiantFunctorを継承しています。 

MA

xmap

一度別の型に変換し、また元の型へ変換します。

("Hello" |+| "World")(Semigroup.IntSemigroup.xmap(_.shows)(_.size)) assert_=== "10"
(1 |+| 1)(Semigroup.StringSemigroup.xmap(_.toInt)(_.shows)) assert_=== 11

Semigroup以外に、Endo, Monoid, Memoのインスタンスが定義されています。

xmapはともかく、mapやmap2,compは使いどころが多いと思います。
積極的に使っていってコードをScalazで染め上げましょう!

0 件のコメント:

コメントを投稿