- Applicative Functorを使った記述スタイル
- 『Applicative programming with effects』で紹介された
Applicative Functorは以下の三つの関数を持つ
def map[A, B](fa: F[A])(f: A => B): F[B] // Functor def pure[A](a: => A): F[A] def ap[A, B](fa: => F[A])(f: => F[A => B]): F[B]
Haskellの場合
do i <- Just "a" j <- Just "b" return $ i ++ jを
(++) <$> Just "a" <*> Just "b"と書く
Scalaの場合
for { a <- Option("a") b <- Option("b") } yield a + b
これをどう書くかという話
^(Option("a"), Option("b"))(_ + _)
Pros:
Cons:
^("a".right[Int], "b".right[Int])(_ + _) // not work
val F = Apply[({type l[a]=Int\/a})#l] import F.applySyntax._ ^("a".right,"b".right)(_ + _) // by xuwei-k
(Option("a") |@| Option("b"))(_ + _)
Pros:
("a".right[Int] |@| "b".right[Int])(_ + _) // work
Cons:
やや冗長だが直接Applyインスタンスを呼び出すことができる
Apply[Option].apply2(Option("a"), Option("b"))(_ + _)
合成もできる
val F = Apply[List] compose Apply[Option] F.apply2(List(Option("a")), List(Option("b")))(_ + _) // => List(Option("ab"))
複数の型パラメータを受け取る型コンストラクタの場合
val F = Apply[({type l[a]=Int\/a})#l] F.apply2("a".right, "b".right)(_ + _)
Unapplyを使ってもよい
val F = Unapply.unapplyMAB2[Apply, \/, Int, String].TC F.apply2("a".right, "b".right)(_ + _)
effectfully(Option("a").! + Option("b").!)
val F = Unapply.unapplyMA[Monad, Option, String](optionInstance).TC F.bind(Option("a"))(a => F.bind(Option("b"))(b => F.pure(a + b)))
と展開される
Pros:
Cons:
effectfully(Option("abc").!.count(_.isLetter)) // not work
idiom[Option]($(Option("a") + Option("b")))
idioms.option.app( idioms.option.map( (a: String) => (b: String) => a + b )(Option("a")) )(Option("b"))
と展開される
型を指定する方法と
idiom[List]($(List(1,2,3) * List(4,5,6))) // => List(4, 5, 6, 8, 10, 12, 12, 15, 18)
型クラスインスタンスを直接指定する方法がある
idiom(zipList)($(List(1,2,3) * List(4,5,6))) // => List(4, 10, 18)
式全体が$で囲まれている場合以下のような記法もある
$[Option](Option("a") + Option("b"))
合成もできる
idiom(list $ option)($(List(Option("a")) + List(Option("b"))))
Pros:
Cons: