Applicative
#cats
#型クラス
概要
依存性のない計算
F[A]、F[B]の値を組み合わせることを可能にする(計算、作用を組み合わせることを可能にしている)→mapN
F[A]に変換を適用することしかできないFunctorより強力
F[A]の値に応じてF[B]を構築できるMonadよりは弱い
アクションをシンプルに組み合わせて最後の値を返すみたいな。
普通のプログラミングでは文をつらつらと書いていく場面をApplicativeで記述できる
IO.sleep(5.second) *> IO.println("hello") *> IO.delay("ok"): IO[String]
code:scala
sleep(5);
println("hello");
return "ok";
Applicativeインスタンスは一般に合成可能
ApplicativeなF[_]とG[_]とがあった場合、F[G[_]]もApplicativeになる
文脈自由文法
条件
ap/product
二つのコンテキスト値を独立して組み合わせる能力
def ap[A, B](ff: F[A => B])(fa: F[A]): F[B]
def product[A, B](fa: F[A], fb: F[B]): F[(A, B)]
pure
値をコンテキストに入れる能力
Associativity(結合法則)
組み合わせの順番に寄らず等しくなる
fa.product(fb).product(fc) ~ fa.product(fb.product(fc))
Left identity
pure(()).product(fa) ~ fa
Right identity
fa.product(pure(())) ~ fa
例
Validated
Webフォームみたいに全て入力してもらってエラーがある箇所は全てエラーメッセージと一緒にユーザーに示す
→Eitherでは以前の計算に依存できる故に一つのフォームが失敗すると以降は実行すらされない
cats
Semigroupal
二つの文脈を組み合わせることができる型クラス
code:scala
trait Semigroupal[F_] {
def productA, B(fa: FA, fb: FB): F(A, B)
}
catsではSemigroupal,Functorを継承してApply
Applyを継承してApplicative
Scala
code:scala
trait Applicative[F_] extends FunctorF {
def apA, B(ff: FA => B)(fa: FA): FB
def pureA(a: A): FA
def mapA, B(fa: FA)(f: A => B): FB = ap(pure(f))(fa)
}
code:scala
(Option(123), Option("abc")).tupled
// res8: Option(Int, String) = Some((123, "abc"))
SemigroupalList.product(List(1, 2), List(3, 4))
(List(1, 2), List(3, 4), List(5,6)).tupled
//それぞれのListから一つずつ選ぶ組み合わせ 2^3
// Cartesian product(直積集合)
二つの文脈を組み合わせる
ListでのSemigroupalは(1,3,5)...みたいな感じで他の文脈値と交わった値が出来上がっている(直積集合)。これはApplicativeでの独立した組み合わせに反している。このような挙動なのはListがMonadであるから。そのMonadのflatMapでproductが実装されているから。