MonadTって自動でMonadにはならないの???
Monadって難しいって話。
元ネタは xuweiさんのブログ
いやね、最近PlayでWebアプリ作ろうと頑張ってるんですよ。
そこでログ出力のために、引数で渡すものを必要に応じてWriterにできればなとか考えてたんですよ。
結果うまくはいかなかったんですが。
本編以外を極力省くため、試すコードはただの足し算。
def add(a: Int, b: Int): Int = a + b
これをブログを参考にIdでくるむ。
import scalaz._, Scalaz._ def add(a: Id[Int], b: Id[Int]): Id[Int] = for { x <- a y <- b } yield x + y // 実行 > val a = add(1, 2) a: scalaz.Scalaz.Id[Int] = 3
それぞれIdに入っちゃったから取り出すためのfor書いて、中の値を使って処理。
これをさらにブログに書いてある通り、任意の入れ物から取り出せるように変更。
import scalaz._, Scalaz._ import scala.language.higherKinds def add[F[_]](a: F[Int], b: F[Int])(implicit F: Monad[F]): F[Int] = for { x <- a y <- b } yield x + y // 実行 > val a = add[Id](1, 2) a: scalaz.Scalaz.Id[Int] = 3
[Id]
って書かないと実行できなくなった。。。
まあそこはIdで使うかどうかなのできっと問題無いのかな?
OptionやListで渡していれば予想通りの動き。
> val a = add(1.some, 2.some) a: Option[Int] = Some(3) > val b = add(List(1, 3, 5), List(7, 8)) b: List[Int] = List(8, 9, 10, 11, 12, 13)
MonadTransformer使って合成
> val a = List(1, 2, 3).liftM[OptionT] a: scalaz.OptionT[List,Int] = OptionT(List(Some(1), Some(2), Some(3))) > val b = List(5, 7).liftM[OptionT] b: scalaz.OptionT[List,Int] = OptionT(List(Some(5), Some(7))) > val c = add(a, b) error: no type parameters for method add: (a: F[Int], b: F[Int])(implicit F: scalaz.Monad[F])F[Int] exist so that it can be applied to arguments (scalaz.OptionT[List,Int], scalaz.OptionT[List,Int])
!?!?
OptionT[List, Int]なんてMonadじゃねぇぞ!!!って言われる。なんで?なんで?
よーしパパMonadとか実装しちゃうぞー(結婚したい)
type OptionTList[A] = OptionT[List, A] implicit val OptionTListMonad = new Monad[OptionTList] { def point[A](a: => A) = List(a).liftM[OptionT] def bind[A, B](fa: OptionTList[A])(f: A => OptionTList[B]) = fa flatMap f } > val c = add(a, b) error: no type parameters for method add: (a: F[Int], b: F[Int])(implicit F: scalaz.Monad[F])F[Int] exist so that it can be applied to arguments (scalaz.OptionT[List,Int], scalaz.OptionT[List,Int])
通らない・・・
> val c = add[OptionTList](a, b) c: OptionTList[Int] = OptionT(List(Some(6), Some(8), Some(7), Some(9), Some(8), Some(10)))
これなら通る。 つまりこう?
> val a: OptionTList[Int] = List(1, 2, 3).liftM[OptionT] a: OptionTList[Int] = OptionT(List(Some(1), Some(2), Some(3))) > val b: OptionTList[Int] = List(5, 7).liftM[OptionT] b: OptionTList[Int] = OptionT(List(Some(5), Some(7))) > val c = add(a, b) c: OptionTList[Int] = OptionT(List(Some(6), Some(8), Some(7), Some(9), Some(8), Some(10)))
むぅー。。。
やり方を間違っている気しかしない。。。
やっぱり元ブログみたいにTraitでくるんでコンストラクターを中で呼び出さないとダメなのかな?
それとも、Monadの代わりに何かそれっぽいのがMonad Transformer用にある???
2015/04/23 追記 Scala勉強会にてねこはる先生に教えてもらった。
> val a = List(2, 3, 5).liftM[OptionT] a: scalaz.OptionT[List,Int] = OptionT(List(Some(2), Some(3), Some(5))) > val b = List(1, 9).liftM[OptionT] b: scalaz.OptionT[List,Int] = OptionT(List(Some(1), Some(9))) > val c = add[({type F[A] = OptionT[List, A]})#F](a, b) c: scalaz.OptionT[[+A]List[A],Int] = OptionT(List(Some(3), Some(11), Some(4), Some(12), Some(6), Some(14))