Created
July 9, 2015 06:01
Revisions
-
manjuraj created this gist
Jul 9, 2015 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,156 @@ // // Apply extends the Functor Typeclass by adding a method `ap` which // is similar to `map` from Functor in that it takes a functor that // that has a function in it and another functor and extracts that // function from the first functor and then maps it over the second // one // // Alternatively, you can say `ap` lets you apply a function in a // context to a value in a context // trait Apply[F[_]] extends Functor[F] { self => def ap[A, B](fa: => F[A])(f: => F[A => B]): F[B] // Flipped variant of `ap` def apF[A,B](f: => F[A => B]): F[A] => F[B] = ap(_)(f) // Lift a function of multiple arguments into Applicative context def apply2[A, B, C](fa: => F[A], fb: => F[B])(f: (A, B) => C): F[C] = ap(fb)(map(fa)(f.curried)) def ap2[A,B,C](fa: => F[A], fb: => F[B])(f: F[(A,B) => C]): F[C] = ap(fb)(ap(fa)(map(f)(_.curried))) ... } // // Applicative // // Whereas a Functor allows application of a pure function to // a value in a context, an Applicative allows application // of a function in a context to a value in a context (`ap`) // // Applicative instances come in a few flavours: // - All scalaz.Monad are also Applicative // - Any scalaz.Monoid can be treated as an Applicative // // Every scalaz.Monad is an applicative functor (scalaz.Applicative); // every applicative functor is a scalaz.Functor. Not every // applicative functor is a Monad // trait Applicative[F[_]] extends Apply[F] { self => // Takes a value of type A and returns F[A] -- an applicative // value with that value inside it def point[A](a: => A): F[A] final def pure[A](a: => A): F[A] = point(a) override def map[A, B](fa: F[A])(f: A => B): F[B] = ap(fa)(point(f)) ... } import scalaz._ import scalaz.std.AllInstances._ scala> type EitherS[T] = \/[String, T] defined type alias EitherS scala> Apply[Option] res0: scalaz.Apply[Option] = scalaz.std.OptionInstances$$anon$1@15b60deb scala> Apply[List] res1: scalaz.Apply[List] = scalaz.std.ListInstances$$anon$1@2fd3c4b5 scala> Apply[EitherS] res3: scalaz.Apply[EitherS] = scalaz.DisjunctionInstances1$$anon$1@f2a853f scala> Applicative[Option] res4: scalaz.Applicative[Option] = scalaz.std.OptionInstances$$anon$1@15b60deb scala> Applicative[List] res5: scalaz.Applicative[List] = scalaz.std.ListInstances$$anon$1@2fd3c4b5 scala> Applicative[EitherS] res6: scalaz.Applicative[EitherS] = scalaz.DisjunctionInstances1$$anon$1@f34d301 // // Applicative abstracts out the constructor of higher kinded // Applicative types // import scalaz._ import scalaz.syntax.applicative._ import scalaz.std.list._ scala> 1.point[List] res1: List[Int] = List(1) import scalaz._ import scalaz.syntax.applicative._ import scalaz.std.option._ scala> 1.point[Option] res0: Option[Int] = Some(1) import scalaz._ import scalaz.syntax.applicative._ import scalaz.std.either._ scala> type EitherS[T] = \/[String, T] defined type alias EitherS scala> 1.point[EitherS] res4: EitherS[Int] = \/-(1) // // Usage of `ap` in Applicative // import scalaz._ import scalaz.std.option._ import scalaz.syntax.std.option._ import scalaz.syntax.apply._ val intToString: Int => String = _.toString val double: Int => Int = _ * 2 val addTwo: Int => Int = _ + 2 scala> Apply[Option].ap(2.some)(intToString.some) res0: Option[String] = Some(2) scala> 9.some <*> {double.some} res1: Option[Int] = Some(18) scala> 1.some <* 2.some res2: Option[Int] = Some(1) scala> 1.some *> 2.some res3: Option[Int] = Some(2) // // |@| - "applicative builder" syntax. // // If you have a function `f` that takes n arguments, then // (x1 |@| x2 // |@| ... |@| xn)(f) is that function `f` // lifted into an applicative functor // import scalaz._ import scalaz.syntax.apply._ import scalaz.std.option._ import scalaz.syntax.std.option._ scala> (1.some |@| 2.some) { _ + _ } res1: Option[Int] = Some(3) scala> (1.some |@| 2.some |@| 3.some) { _ + _ + _} res1: Option[Int] = Some(6) import scalaz._ import scalaz.syntax.applicative._ import scalaz.std.option._ import scalaz.syntax.std.option._ import scalaz.syntax.apply._ scala> 9.some <*> { (_: Int) + 3 }.some res0: Option[Int] = Some(12)