Created
July 9, 2015 06:01
-
-
Save manjuraj/f0c832584131ac345f92 to your computer and use it in GitHub Desktop.
scalaz applicative
This file contains 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 characters
// | |
// 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) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment