Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reverse order of arguments for ap #833

Merged
merged 5 commits into from
Jan 30, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ lazy val commonSettings = Seq(
Resolver.sonatypeRepo("snapshots")
),
libraryDependencies ++= Seq(
"com.github.mpilquist" %%% "simulacrum" % "0.6.1",
"com.github.mpilquist" %%% "simulacrum" % "0.7.0",
"org.spire-math" %%% "algebra" % "0.3.1",
"org.spire-math" %%% "algebra-std" % "0.3.1",
"org.typelevel" %%% "machinist" % "0.4.1",
Expand Down
8 changes: 4 additions & 4 deletions core/src/main/scala/cats/Apply.scala
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,12 @@ trait Apply[F[_]] extends Functor[F] with Cartesian[F] with ApplyArityFunctions[
* Given a value and a function in the Apply context, applies the
* function to the value.
*/
def ap[A, B](fa: F[A])(ff: F[A => B]): F[B]
def ap[A, B](ff: F[A => B])(fa: F[A]): F[B]

/**
* ap2 is a binary version of ap, defined in terms of ap.
*/
def ap2[A, B, Z](fa: F[A], fb: F[B])(ff: F[(A, B) => Z]): F[Z] =
def ap2[A, B, Z](ff: F[(A, B) => Z])(fa: F[A], fb: F[B]): F[Z] =
map(product(fa, product(fb, ff))) { case (a, (b, f)) => f(a, b) }

/**
Expand Down Expand Up @@ -53,8 +53,8 @@ trait CompositeApply[F[_], G[_]]
def F: Apply[F]
def G: Apply[G]

def ap[A, B](fa: F[G[A]])(f: F[G[A => B]]): F[G[B]] =
F.ap(fa)(F.map(f)(gab => G.ap(_)(gab)))
def ap[A, B](f: F[G[A => B]])(fa: F[G[A]]): F[G[B]] =
F.ap(F.map(f)(gab => G.ap(gab)(_)))(fa)

def product[A, B](fa: F[G[A]], fb: F[G[B]]): F[G[(A, B)]] =
F.map2(fa, fb)(G.product)
Expand Down
2 changes: 1 addition & 1 deletion core/src/main/scala/cats/FlatMap.scala
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import simulacrum.typeclass
def flatten[A](ffa: F[F[A]]): F[A] =
flatMap(ffa)(fa => fa)

override def ap[A, B](fa: F[A])(ff: F[A => B]): F[B] =
override def ap[A, B](ff: F[A => B])(fa: F[A]): F[B] =
flatMap(ff)(f => map(fa)(f))

override def product[A, B](fa: F[A], fb: F[B]): F[(A, B)] =
Expand Down
4 changes: 2 additions & 2 deletions core/src/main/scala/cats/data/Const.scala
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ private[data] sealed abstract class ConstInstances0 extends ConstInstances1 {
def pure[A](x: A): Const[C, A] =
Const.empty

def ap[A, B](fa: Const[C, A])(f: Const[C, A => B]): Const[C, B] =
def ap[A, B](f: Const[C, A => B])(fa: Const[C, A]): Const[C, B] =
f.retag[B] combine fa.retag[B]

def map[A, B](fa: Const[C, A])(f: A => B): Const[C, B] =
Expand All @@ -104,7 +104,7 @@ private[data] sealed abstract class ConstInstances1 {
}

implicit def constApply[C: Semigroup]: Apply[Const[C, ?]] = new Apply[Const[C, ?]] {
def ap[A, B](fa: Const[C, A])(f: Const[C, A => B]): Const[C, B] =
def ap[A, B](f: Const[C, A => B])(fa: Const[C, A]): Const[C, B] =
fa.retag[B] combine f.retag[B]

def product[A, B](fa: Const[C, A], fb: Const[C, B]): Const[C, (A, B)] =
Expand Down
8 changes: 4 additions & 4 deletions core/src/main/scala/cats/data/Func.scala
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,8 @@ sealed trait FuncFunctor[F[_], C] extends Functor[Lambda[X => Func[F, C, X]]] {

sealed trait FuncApply[F[_], C] extends Apply[Lambda[X => Func[F, C, X]]] with FuncFunctor[F, C] {
def F: Apply[F]
def ap[A, B](fa: Func[F, C, A])(f: Func[F, C, A => B]): Func[F, C, B] =
Func.func(c => F.ap(fa.run(c))(f.run(c)))
def ap[A, B](f: Func[F, C, A => B])(fa: Func[F, C, A]): Func[F, C, B] =
Func.func(c => F.ap(f.run(c))(fa.run(c)))
def product[A, B](fa: Func[F, C, A], fb: Func[F, C, B]): Func[F, C, (A, B)] =
Func.func(c => F.product(fa.run(c), fb.run(c)))
}
Expand Down Expand Up @@ -123,8 +123,8 @@ private[data] sealed trait AppFuncApplicative[F[_], C] extends Applicative[Lambd
def F: Applicative[F]
def map[A, B](fa: AppFunc[F, C, A])(f: A => B): AppFunc[F, C, B] =
fa.map(f)
def ap[A, B](fa: AppFunc[F, C, A])(f: AppFunc[F, C, A => B]): AppFunc[F, C, B] =
Func.appFunc[F, C, B](c => F.ap(fa.run(c))(f.run(c)))(F)
def ap[A, B](f: AppFunc[F, C, A => B])(fa: AppFunc[F, C, A]): AppFunc[F, C, B] =
Func.appFunc[F, C, B](c => F.ap(f.run(c))(fa.run(c)))(F)
def product[A, B](fa: AppFunc[F, C, A], fb: AppFunc[F, C, B]): AppFunc[F, C, (A, B)] =
Func.appFunc[F, C, (A, B)](c => F.product(fa.run(c), fb.run(c)))(F)
def pure[A](a: A): AppFunc[F, C, A] =
Expand Down
6 changes: 3 additions & 3 deletions core/src/main/scala/cats/data/Kleisli.scala
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import cats.functor.{Contravariant, Strong}
final case class Kleisli[F[_], A, B](run: A => F[B]) { self =>

def apply[C](f: Kleisli[F, A, B => C])(implicit F: Apply[F]): Kleisli[F, A, C] =
Kleisli(a => F.ap(run(a))(f.run(a)))
Kleisli(a => F.ap(f.run(a))(run(a)))

def dimap[C, D](f: C => A)(g: B => D)(implicit F: Functor[F]): Kleisli[F, C, D] =
Kleisli(c => F.map(run(f(c)))(g))
Expand Down Expand Up @@ -143,7 +143,7 @@ private[data] sealed abstract class KleisliInstances1 extends KleisliInstances2
def pure[B](x: B): Kleisli[F, A, B] =
Kleisli.pure[F, A, B](x)

def ap[B, C](fa: Kleisli[F, A, B])(f: Kleisli[F, A, B => C]): Kleisli[F, A, C] =
def ap[B, C](f: Kleisli[F, A, B => C])(fa: Kleisli[F, A, B]): Kleisli[F, A, C] =
fa(f)

def map[B, C](fb: Kleisli[F, A, B])(f: B => C): Kleisli[F, A, C] =
Expand All @@ -156,7 +156,7 @@ private[data] sealed abstract class KleisliInstances1 extends KleisliInstances2

private[data] sealed abstract class KleisliInstances2 extends KleisliInstances3 {
implicit def kleisliApply[F[_]: Apply, A]: Apply[Kleisli[F, A, ?]] = new Apply[Kleisli[F, A, ?]] {
def ap[B, C](fa: Kleisli[F, A, B])(f: Kleisli[F, A, B => C]): Kleisli[F, A, C] =
def ap[B, C](f: Kleisli[F, A, B => C])(fa: Kleisli[F, A, B]): Kleisli[F, A, C] =
fa(f)

def product[B, C](fb: Kleisli[F, A, B], fc: Kleisli[F, A, C]): Kleisli[F, A, (B, C)] =
Expand Down
2 changes: 1 addition & 1 deletion core/src/main/scala/cats/data/OneAnd.scala
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ trait OneAndLowPriority2 extends OneAndLowPriority1 {
def traverse[G[_], A, B](fa: OneAnd[F, A])(f: (A) => G[B])(implicit G: Applicative[G]): G[OneAnd[F, B]] = {
val tail = F.traverse(fa.tail)(f)
val head = f(fa.head)
G.ap2(head, tail)(G.pure(OneAnd(_, _)))
G.ap2[B, F[B], OneAnd[F, B]](G.pure(OneAnd(_, _)))(head, tail)
}

def foldLeft[A, B](fa: OneAnd[F, A], b: B)(f: (B, A) => B): B = {
Expand Down
4 changes: 2 additions & 2 deletions core/src/main/scala/cats/data/Prod.scala
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,8 @@ sealed trait ProdFunctor[F[_], G[_]] extends Functor[Lambda[X => Prod[F, G, X]]]
sealed trait ProdApply[F[_], G[_]] extends Apply[Lambda[X => Prod[F, G, X]]] with ProdFunctor[F, G] {
def F: Apply[F]
def G: Apply[G]
def ap[A, B](fa: Prod[F, G, A])(f: Prod[F, G, A => B]): Prod[F, G, B] =
Prod(F.ap(fa.first)(f.first), G.ap(fa.second)(f.second))
def ap[A, B](f: Prod[F, G, A => B])(fa: Prod[F, G, A]): Prod[F, G, B] =
Prod(F.ap(f.first)(fa.first), G.ap(f.second)(fa.second))
def product[A, B](fa: Prod[F, G, A], fb: Prod[F, G, B]): Prod[F, G, (A, B)] =
Prod(F.product(fa.first, fb.first), G.product(fa.second, fb.second))
}
Expand Down
2 changes: 1 addition & 1 deletion core/src/main/scala/cats/data/Validated.scala
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,7 @@ private[data] sealed abstract class ValidatedInstances extends ValidatedInstance
override def map[A, B](fa: Validated[E,A])(f: A => B): Validated[E, B] =
fa.map(f)

def ap[A,B](fa: Validated[E,A])(f: Validated[E,A=>B]): Validated[E, B] =
def ap[A,B](f: Validated[E,A=>B])(fa: Validated[E,A]): Validated[E, B] =
fa.ap(f)(E)

def product[A, B](fa: Validated[E, A], fb: Validated[E, B]): Validated[E, (A, B)] =
Expand Down
3 changes: 2 additions & 1 deletion core/src/main/scala/cats/data/WriterT.scala
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ private[data] sealed trait WriterTApply[F[_], L] extends WriterTFunctor[F, L] wi
override implicit def F0: Apply[F]
implicit def L0: Semigroup[L]

def ap[A, B](fa: WriterT[F, L, A])(f: WriterT[F, L, A => B]): WriterT[F, L, B] =
def ap[A, B](f: WriterT[F, L, A => B])(fa: WriterT[F, L, A]): WriterT[F, L, B] =
fa ap f
def product[A, B](fa: WriterT[F, L, A], fb: WriterT[F, L, B]): WriterT[F, L, (A, B)] =
WriterT(F0.map(F0.product(fa.run, fb.run)) { case ((l1, a), (l2, b)) => (L0.combine(l1, l2), (a, b)) })
Expand Down Expand Up @@ -230,3 +230,4 @@ trait WriterTFunctions {
}



2 changes: 1 addition & 1 deletion core/src/main/scala/cats/data/XorT.scala
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ final case class XorT[F[_], A, B](value: F[A Xor B]) {
def bimap[C, D](fa: A => C, fb: B => D)(implicit F: Functor[F]): XorT[F, C, D] = XorT(F.map(value)(_.bimap(fa, fb)))

def applyAlt[D](ff: XorT[F, A, B => D])(implicit F: Apply[F]): XorT[F, A, D] =
XorT[F, A, D](F.map2(this.value, ff.value)((xb, xbd) => Apply[A Xor ?].ap(xb)(xbd)))
XorT[F, A, D](F.map2(this.value, ff.value)((xb, xbd) => Apply[A Xor ?].ap(xbd)(xb)))

def flatMap[AA >: A, D](f: B => XorT[F, AA, D])(implicit F: Monad[F]): XorT[F, AA, D] =
XorT(F.flatMap(value) {
Expand Down
4 changes: 2 additions & 2 deletions core/src/main/scala/cats/free/FreeApplicative.scala
Original file line number Diff line number Diff line change
Expand Up @@ -79,9 +79,9 @@ object FreeApplicative {

implicit final def freeApplicative[S[_]]: Applicative[FA[S, ?]] = {
new Applicative[FA[S, ?]] {
def product[A, B](fa: FA[S, A], fb: FA[S, B]): FA[S, (A, B)] = ap(fb)(fa.map(a => b => (a, b)))
def product[A, B](fa: FA[S, A], fb: FA[S, B]): FA[S, (A, B)] = ap(fa.map((a: A) => (b: B) => (a, b)))(fb)
def map[A, B](fa: FA[S, A])(f: A => B): FA[S, B] = fa.map(f)
override def ap[A, B](fa: FA[S, A])(f: FA[S, A => B]): FA[S, B] = fa.ap(f)
override def ap[A, B](f: FA[S, A => B])(fa: FA[S, A]): FA[S, B] = fa.ap(f)
def pure[A](a: A): FA[S, A] = Pure(a)
}
}
Expand Down
2 changes: 1 addition & 1 deletion core/src/main/scala/cats/package.scala
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ package object cats {
def flatMap[A, B](a: A)(f: A => B): B = f(a)
def coflatMap[A, B](a: A)(f: A => B): B = f(a)
override def map[A, B](fa: A)(f: A => B): B = f(fa)
override def ap[A, B](fa: A)(ff: A => B): B = ff(fa)
override def ap[A, B](ff: A => B)(fa: A): B = ff(fa)
override def flatten[A](ffa: A): A = ffa
override def map2[A, B, Z](fa: A, fb: B)(f: (A, B) => Z): Z = f(fa, fb)
override def lift[A, B](f: A => B): A => B = f
Expand Down
4 changes: 2 additions & 2 deletions core/src/main/scala/cats/std/map.scala
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,10 @@ trait MapInstances extends algebra.std.MapInstances {
override def map2[A, B, Z](fa: Map[K, A], fb: Map[K, B])(f: (A, B) => Z): Map[K, Z] =
fa.flatMap { case (k, a) => fb.get(k).map(b => (k, f(a, b))) }

override def ap[A, B](fa: Map[K, A])(ff: Map[K, A => B]): Map[K, B] =
override def ap[A, B](ff: Map[K, A => B])(fa: Map[K, A]): Map[K, B] =
fa.flatMap { case (k, a) => ff.get(k).map(f => (k, f(a))) }

override def ap2[A, B, Z](fa: Map[K, A], fb: Map[K, B])(f: Map[K, (A, B) => Z]): Map[K, Z] =
override def ap2[A, B, Z](f: Map[K, (A, B) => Z])(fa: Map[K, A], fb: Map[K, B]): Map[K, Z] =
f.flatMap { case (k, f) =>
for { a <- fa.get(k); b <- fb.get(k) } yield (k, f(a, b))
}
Expand Down
26 changes: 13 additions & 13 deletions docs/src/main/tut/apply.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ val double: Int => Int = _ * 2
val addTwo: Int => Int = _ + 2

implicit val optionApply: Apply[Option] = new Apply[Option] {
def ap[A, B](fa: Option[A])(f: Option[A => B]): Option[B] =
def ap[A, B](f: Option[A => B])(fa: Option[A]): Option[B] =
fa.flatMap (a => f.map (ff => ff(a)))

def map[A,B](fa: Option[A])(f: A => B): Option[B] = fa map f
Expand All @@ -32,7 +32,7 @@ implicit val optionApply: Apply[Option] = new Apply[Option] {
}

implicit val listApply: Apply[List] = new Apply[List] {
def ap[A, B](fa: List[A])(f: List[A => B]): List[B] =
def ap[A, B](f: List[A => B])(fa: List[A]): List[B] =
fa.flatMap (a => f.map (ff => ff(a)))

def map[A,B](fa: List[A])(f: A => B): List[B] = fa map f
Expand All @@ -59,17 +59,17 @@ And like functors, `Apply` instances also compose:
```tut
val listOpt = Apply[List] compose Apply[Option]
val plusOne = (x:Int) => x + 1
listOpt.ap(List(Some(1), None, Some(3)))(List(Some(plusOne)))
listOpt.ap(List(Some(plusOne)))(List(Some(1), None, Some(3)))
```

### ap
The `ap` method is a method that `Functor` does not have:

```tut
Apply[Option].ap(Some(1))(Some(intToString))
Apply[Option].ap(Some(1))(Some(double))
Apply[Option].ap(None)(Some(double))
Apply[Option].ap(Some(1))(None)
Apply[Option].ap(Some(intToString))(Some(1))
Apply[Option].ap(Some(double))(Some(1))
Apply[Option].ap(Some(double))(None)
Apply[Option].ap(None)(Some(1))
Apply[Option].ap(None)(None)
```

Expand All @@ -82,19 +82,19 @@ For example:

```tut
val addArity2 = (a: Int, b: Int) => a + b
Apply[Option].ap2(Some(1), Some(2))(Some(addArity2))
Apply[Option].ap2(Some(addArity2))(Some(1), Some(2))

val addArity3 = (a: Int, b: Int, c: Int) => a + b + c
Apply[Option].ap3(Some(1), Some(2), Some(3))(Some(addArity3))
Apply[Option].ap3(Some(addArity3))(Some(1), Some(2), Some(3))
```

Note that if any of the arguments of this example is `None`, the
final result is `None` as well. The effects of the context we are operating on
are carried through the entire computation:

```tut
Apply[Option].ap2(Some(1), None)(Some(addArity2))
Apply[Option].ap4(Some(1), Some(2), Some(3), Some(4))(None)
Apply[Option].ap2(Some(addArity2))(Some(1), None)
Apply[Option].ap4(None)(Some(1), Some(2), Some(3), Some(4))
```

### map2, map3, etc
Expand Down Expand Up @@ -146,8 +146,8 @@ val option3 = option2 |@| Option.empty[Int]
option2 map addArity2
option3 map addArity3

option2 ap Some(addArity2)
option3 ap Some(addArity3)
option2 apWith Some(addArity2)
option3 apWith Some(addArity3)

option2.tupled
option3.tupled
Expand Down
4 changes: 2 additions & 2 deletions docs/src/main/tut/const.md
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,7 @@ implicit def constApplicative[Z]: Applicative[Const[Z, ?]] =
new Applicative[Const[Z, ?]] {
def pure[A](a: A): Const[Z, A] = ???

def ap[A, B](fa: Const[Z, A])(f: Const[Z, A => B]): Const[Z, B] = ???
def ap[A, B](f: Const[Z, A => B])(fa: Const[Z, A]): Const[Z, B] = ???

def map[A, B](fa: Const[Z, A])(f: A => B): Const[Z, B] = ???

Expand All @@ -244,7 +244,7 @@ implicit def constApplicative[Z : Monoid]: Applicative[Const[Z, ?]] =
new Applicative[Const[Z, ?]] {
def pure[A](a: A): Const[Z, A] = Const(Monoid[Z].empty)

def ap[A, B](fa: Const[Z, A])(f: Const[Z, A => B]): Const[Z, B] =
def ap[A, B](f: Const[Z, A => B])(fa: Const[Z, A]): Const[Z, B] =
Const(Monoid[Z].combine(fa.getConst, f.getConst))

def map[A, B](fa: Const[Z, A])(f: A => B): Const[Z, B] =
Expand Down
9 changes: 5 additions & 4 deletions docs/src/main/tut/validated.md
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ import cats.Applicative

implicit def validatedApplicative[E : Semigroup]: Applicative[Validated[E, ?]] =
new Applicative[Validated[E, ?]] {
def ap[A, B](fa: Validated[E, A])(f: Validated[E, A => B]): Validated[E, B] =
def ap[A, B](f: Validated[E, A => B])(fa: Validated[E, A]): Validated[E, B] =
(fa, f) match {
case (Valid(a), Valid(fab)) => Valid(fab(a))
case (i@Invalid(_), Valid(_)) => i
Expand All @@ -200,12 +200,13 @@ implicit def validatedApplicative[E : Semigroup]: Applicative[Validated[E, ?]] =

def pure[A](x: A): Validated[E, A] = Validated.valid(x)
def map[A, B](fa: Validated[E, A])(f: A => B): Validated[E, B] = fa.map(f)
def product[A, B](fa: Validated[E, A], fb: Validated[E, B]): Validated[E, (A, B)] = ap(fb)(fa.map(a => b => (a, b)))
def product[A, B](fa: Validated[E, A], fb: Validated[E, B]): Validated[E, (A, B)] =
ap(fa.map(a => (b: B) => (a, b)))(fb)
}
```

Awesome! And now we also get access to all the goodness of `Applicative`, among which include
`map{2-22}`, as well as the `Apply` syntax `|@|`.
Awesome! And now we also get access to all the goodness of `Applicative`, which includes `map{2-22}`, as well as the
`Cartesian` syntax `|@|`.

We can now easily ask for several bits of configuration and get any and all errors returned back.

Expand Down
4 changes: 2 additions & 2 deletions laws/src/main/scala/cats/laws/AlternativeLaws.scala
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@ trait AlternativeLaws[F[_]] extends ApplicativeLaws[F] with MonoidKLaws[F] {
implicit def algebra[A]: Monoid[F[A]] = F.algebra[A]

def alternativeRightAbsorption[A, B](ff: F[A => B]): IsEq[F[B]] =
(F.empty[A] ap ff) <-> F.empty[B]
(ff ap F.empty[A]) <-> F.empty[B]

def alternativeLeftDistributivity[A, B](fa: F[A], fa2: F[A], f: A => B): IsEq[F[B]] =
((fa |+| fa2) map f) <-> ((fa map f) |+| (fa2 map f))

def alternativeRightDistributivity[A, B](fa: F[A], ff: F[A => B], fg: F[A => B]): IsEq[F[B]] =
(fa ap (ff |+| fg)) <-> ((fa ap ff) |+| (fa ap fg))
((ff |+| fg) ap fa) <-> ((ff ap fa) |+| (fg ap fa))

}

Expand Down
12 changes: 6 additions & 6 deletions laws/src/main/scala/cats/laws/ApplicativeLaws.scala
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,16 @@ trait ApplicativeLaws[F[_]] extends ApplyLaws[F] {
implicit override def F: Applicative[F]

def applicativeIdentity[A](fa: F[A]): IsEq[F[A]] =
fa.ap(F.pure((a: A) => a)) <-> fa
F.pure((a: A) => a).ap(fa) <-> fa

def applicativeHomomorphism[A, B](a: A, f: A => B): IsEq[F[B]] =
F.pure(a).ap(F.pure(f)) <-> F.pure(f(a))
F.pure(f).ap(F.pure(a)) <-> F.pure(f(a))

def applicativeInterchange[A, B](a: A, ff: F[A => B]): IsEq[F[B]] =
F.pure(a).ap(ff) <-> ff.ap(F.pure(f => f(a)))
ff.ap(F.pure(a)) <-> F.pure((f: A => B) => f(a)).ap(ff)

def applicativeMap[A, B](fa: F[A], f: A => B): IsEq[F[B]] =
fa.map(f) <-> fa.ap(F.pure(f))
fa.map(f) <-> F.pure(f).ap(fa)

/**
* This law is [[applyComposition]] stated in terms of `pure`. It is a
Expand All @@ -29,11 +29,11 @@ trait ApplicativeLaws[F[_]] extends ApplyLaws[F] {
*/
def applicativeComposition[A, B, C](fa: F[A], fab: F[A => B], fbc: F[B => C]): IsEq[F[C]] = {
val compose: (B => C) => (A => B) => (A => C) = _.compose
fa.ap(fab.ap(fbc.ap(F.pure(compose)))) <-> fa.ap(fab).ap(fbc)
F.pure(compose).ap(fbc).ap(fab).ap(fa) <-> fbc.ap(fab.ap(fa))
}

def apProductConsistent[A, B](fa: F[A], f: F[A => B]): IsEq[F[B]] =
F.ap(fa)(f) <-> F.map(F.product(f, fa)) { case (f, a) => f(a) }
F.ap(f)(fa) <-> F.map(F.product(f, fa)) { case (f, a) => f(a) }

// The following are the lax monoidal functor identity laws - the associativity law is covered by
// Cartesian's associativity law.
Expand Down
2 changes: 1 addition & 1 deletion laws/src/main/scala/cats/laws/ApplyLaws.scala
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ trait ApplyLaws[F[_]] extends FunctorLaws[F] with CartesianLaws[F] {

def applyComposition[A, B, C](fa: F[A], fab: F[A => B], fbc: F[B => C]): IsEq[F[C]] = {
val compose: (B => C) => (A => B) => (A => C) = _.compose
fa.ap(fab).ap(fbc) <-> fa.ap(fab.ap(fbc.map(compose)))
fbc.ap(fab.ap(fa)) <-> fbc.map(compose).ap(fab).ap(fa)
}
}

Expand Down
2 changes: 1 addition & 1 deletion laws/src/main/scala/cats/laws/FlatMapLaws.scala
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ trait FlatMapLaws[F[_]] extends ApplyLaws[F] {
fa.flatMap(f).flatMap(g) <-> fa.flatMap(a => f(a).flatMap(g))

def flatMapConsistentApply[A, B](fa: F[A], fab: F[A => B]): IsEq[F[B]] =
fa.ap(fab) <-> fab.flatMap(f => fa.map(f))
fab.ap(fa) <-> fab.flatMap(f => fa.map(f))

/**
* The composition of `cats.data.Kleisli` arrows is associative. This is
Expand Down
4 changes: 2 additions & 2 deletions laws/src/main/scala/cats/laws/TraverseLaws.scala
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,10 @@ trait TraverseLaws[F[_]] extends FunctorLaws[F] with FoldableLaws[F] {
type MN[Z] = (M[Z], N[Z])
implicit val MN = new Applicative[MN] {
def pure[X](x: X): MN[X] = (M.pure(x), N.pure(x))
def ap[X, Y](fa: MN[X])(f: MN[X => Y]): MN[Y] = {
def ap[X, Y](f: MN[X => Y])(fa: MN[X]): MN[Y] = {
val (fam, fan) = fa
val (fm, fn) = f
(M.ap(fam)(fm), N.ap(fan)(fn))
(M.ap(fm)(fam), N.ap(fn)(fan))
}
def map[X, Y](fx: MN[X])(f: X => Y): MN[Y] = {
val (mx, nx) = fx
Expand Down
Loading