#### 103 lines 3.3 KiB Scala Raw Permalink Blame History

 ```package green.thisfieldwas.embracingnondeterminism.control ``` ``` ``` ```import green.thisfieldwas.embracingnondeterminism.data.Functor ``` ``` ``` ```/** Applicative is a specialization of Functor where the type contained within ``` ``` * the context, `A` in `F[A]`, in known specifically to have some type of `A => ``` ``` * B`. That is, the Functor contains a function and has the form of `F[A => ``` ``` * B]`. This make the Functor an ''Applicative'' Functor, which allows it to be ``` ``` * treated as a lifted function. ``` ``` * ``` ``` * @tparam F ``` ``` * The context type. ``` ``` */ ``` ```trait Applicative[F[_]] extends Functor[F] { ``` ``` ``` ``` /** Applicative provides a default map() implementation. This can be ``` ``` * overridden if it makes sense to. ``` ``` * ``` ``` * @param fa ``` ``` * The instance of the structure to apply the function to. ``` ``` * @param f ``` ``` * The function to apply, if the structure is in the desired case. ``` ``` * @tparam A ``` ``` * The type of instances contained within the structure. ``` ``` * @tparam B ``` ``` * The type to map the instances into. ``` ``` * @return ``` ``` * The resulting structure. ``` ``` */ ``` ``` override def map[A, B](fa: F[A])(f: A => B): F[B] = ap(pure(f))(fa) ``` ``` ``` ``` /** Lifts the pure value of a computation into the context. This is an ``` ``` * abstracted constructor for the `Applicative` and concretely for contexts ``` ``` * `Option` it is `Some`, and for `Either` it is `Right`. It always creates a ``` ``` * new context in the desired case. ``` ``` * ``` ``` * @param a ``` ``` * The value to lift. ``` ``` * @tparam A ``` ``` * The type of the value. ``` ``` * @return ``` ``` * A new context in the desired case. ``` ``` */ ``` ``` def pure[A](a: A): F[A] ``` ``` ``` ``` /** Pronounced "apply", this function takes an applicative functor of the form ``` ``` * `F[A => B]` and applies it to the functor `F[A]`, giving the result of ``` ``` * `F[B]`. ``` ``` * ``` ``` * @param ff ``` ``` * The applicative functor, or lifted function. ``` ``` * @param fa ``` ``` * The argument context, or lifted argument. ``` ``` * @tparam A ``` ``` * The type of the argument. ``` ``` * @tparam B ``` ``` * The type of the result. ``` ``` * @return ``` ``` * The lifted result. ``` ``` */ ``` ``` def ap[A, B](ff: F[A => B])(fa: F[A]): F[B] ``` ``` ``` ``` /** A two-argument analog of `map()`. ``` ``` * ``` ``` * @param fa ``` ``` * The first argument context. ``` ``` * @param fb ``` ``` * The second argument context. ``` ``` * @param f ``` ``` * The function to apply to the contents of the arguments. ``` ``` * @tparam A ``` ``` * The type of the first argument. ``` ``` * @tparam B ``` ``` * The type of the second argument. ``` ``` * @tparam C ``` ``` * The type of the result. ``` ``` * @return ``` ``` * The lifted result. ``` ``` */ ``` ``` def map2[A, B, C](fa: F[A], fb: F[B])(f: (A, B) => C): F[C] = ``` ``` ap(ap(pure(f.curried))(fa))(fb) ``` ``` ``` ``` /** Take a list of contexts and transform them into a context containing a ``` ``` * list of their contents. If all contexts are in their desired case, then ``` ``` * the output context will be a desired case containing a list of their ``` ``` * contents. Otherwise, the output context will be in the undesired case if ``` ``` * any context is in the undesired case. ``` ``` * ``` ``` * @param listFa ``` ``` * The list of functors. ``` ``` * @tparam A ``` ``` * The type contained within the functors. ``` ``` * @return ``` ``` */ ``` ``` def sequence[A](listFa: List[F[A]]): F[List[A]] = ``` ``` listFa.foldLeft(pure(List[A]()))((fListA, fa) => map2(fa, fListA)(_ :: _)) ``` ```} ``` ``` ``` ```object Applicative { ``` ``` ``` ``` def apply[F[_]: Applicative]: Applicative[F] = implicitly[Applicative[F]] ``` ```} ```