Skip to content

Commit

Permalink
product and map can be implemented in terms of ap, fixes #904
Browse files Browse the repository at this point in the history
  • Loading branch information
adelbertc committed Apr 4, 2016
1 parent 7cdd661 commit 051fb84
Show file tree
Hide file tree
Showing 13 changed files with 25 additions and 39 deletions.
3 changes: 3 additions & 0 deletions core/src/main/scala/cats/Applicative.scala
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ import cats.std.list._
*/
def pureEval[A](x: Eval[A]): F[A] = pure(x.value)

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

/**
* Given `fa` and `n`, apply `fa` `n` times to construct an `F[List[A]]` value.
*/
Expand Down
6 changes: 4 additions & 2 deletions core/src/main/scala/cats/Apply.scala
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ trait Apply[F[_]] extends Functor[F] with Cartesian[F] with ApplyArityFunctions[
*/
def ap[A, B](ff: F[A => B])(fa: F[A]): F[B]

override def product[A, B](fa: F[A], fb: F[B]): F[(A, B)] =
ap(map(fa)(a => (b: B) => (a, b)))(fb)

/**
* ap2 is a binary version of ap, defined in terms of ap.
*/
Expand Down Expand Up @@ -56,7 +59,6 @@ trait CompositeApply[F[_], G[_]]
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)]] =
override def product[A, B](fa: F[G[A]], fb: F[G[B]]): F[G[(A, B)]] =
F.map2(fa, fb)(G.product)

}
6 changes: 3 additions & 3 deletions core/src/main/scala/cats/data/Const.scala
Original file line number Diff line number Diff line change
Expand Up @@ -98,10 +98,10 @@ private[data] sealed abstract class ConstInstances0 extends ConstInstances1 {
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] =
override def map[A, B](fa: Const[C, A])(f: A => B): Const[C, B] =
fa.retag[B]

def product[A, B](fa: Const[C, A], fb: Const[C, B]): Const[C, (A, B)] =
override def product[A, B](fa: Const[C, A], fb: Const[C, B]): Const[C, (A, B)] =
fa.retag[(A, B)] combine fb.retag[(A, B)]
}
}
Expand All @@ -116,7 +116,7 @@ private[data] sealed abstract class ConstInstances1 {
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)] =
override def product[A, B](fa: Const[C, A], fb: Const[C, B]): Const[C, (A, B)] =
fa.retag[(A, B)] combine fb.retag[(A, B)]

def map[A, B](fa: Const[C, A])(f: A => B): Const[C, 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 @@ -54,15 +54,15 @@ private[data] abstract class FuncInstances1 {

sealed trait FuncFunctor[F[_], C] extends Functor[Lambda[X => Func[F, C, X]]] {
def F: Functor[F]
def map[A, B](fa: Func[F, C, A])(f: A => B): Func[F, C, B] =
override def map[A, B](fa: Func[F, C, A])(f: A => B): Func[F, C, B] =
fa.map(f)(F)
}

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](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)] =
override 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 @@ -121,11 +121,11 @@ private[data] abstract class AppFuncInstances {

private[data] sealed trait AppFuncApplicative[F[_], C] extends Applicative[Lambda[X => AppFunc[F, C, X]]] {
def F: Applicative[F]
def map[A, B](fa: AppFunc[F, C, A])(f: A => B): AppFunc[F, C, B] =
override def map[A, B](fa: AppFunc[F, C, A])(f: A => B): AppFunc[F, C, B] =
fa.map(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)] =
override 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] =
Func.appFunc[F, C, A](c => F.pure(a))(F)
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 @@ -153,10 +153,10 @@ private[data] sealed abstract class KleisliInstances1 extends KleisliInstances2
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] =
override def map[B, C](fb: Kleisli[F, A, B])(f: B => C): Kleisli[F, A, C] =
fb.map(f)

def product[B, C](fb: Kleisli[F, A, B], fc: Kleisli[F, A, C]): Kleisli[F, A, (B, C)] =
override def product[B, C](fb: Kleisli[F, A, B], fc: Kleisli[F, A, C]): Kleisli[F, A, (B, C)] =
Kleisli(a => Applicative[F].product(fb.run(a), fc.run(a)))
}
}
Expand All @@ -166,7 +166,7 @@ private[data] sealed abstract class KleisliInstances2 extends KleisliInstances3
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)] =
override def product[B, C](fb: Kleisli[F, A, B], fc: Kleisli[F, A, C]): Kleisli[F, A, (B, C)] =
Kleisli(a => Apply[F].product(fb.run(a), fc.run(a)))

def map[B, C](fa: Kleisli[F, A, B])(f: B => C): Kleisli[F, A, C] =
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 @@ -71,15 +71,15 @@ private[data] sealed abstract class ProdInstances4 {
sealed trait ProdFunctor[F[_], G[_]] extends Functor[Lambda[X => Prod[F, G, X]]] {
def F: Functor[F]
def G: Functor[G]
def map[A, B](fa: Prod[F, G, A])(f: A => B): Prod[F, G, B] = Prod(F.map(fa.first)(f), G.map(fa.second)(f))
override def map[A, B](fa: Prod[F, G, A])(f: A => B): Prod[F, G, B] = Prod(F.map(fa.first)(f), G.map(fa.second)(f))
}

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](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)] =
override 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 @@ -254,7 +254,7 @@ private[data] sealed abstract class ValidatedInstances extends ValidatedInstance
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)] =
override def product[A, B](fa: Validated[E, A], fb: Validated[E, B]): Validated[E, (A, B)] =
fa.product(fb)(E)

def handleErrorWith[A](fa: Validated[E, A])(f: E => Validated[E, A]): Validated[E, A] =
Expand Down
2 changes: 1 addition & 1 deletion core/src/main/scala/cats/data/WriterT.scala
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ private[data] sealed trait WriterTApply[F[_], L] extends WriterTFunctor[F, L] wi

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)] =
override 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
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,8 +79,8 @@ 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(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 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)
override def map[A, B](fa: FA[S, A])(f: A => B): FA[S, B] = fa.map(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
6 changes: 0 additions & 6 deletions docs/src/main/tut/apply.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,19 +26,13 @@ implicit val optionApply: Apply[Option] = new Apply[Option] {
fa.flatMap (a => f.map (ff => ff(a)))
def map[A,B](fa: Option[A])(f: A => B): Option[B] = fa map f
def product[A, B](fa: Option[A], fb: Option[B]): Option[(A, B)] =
fa.flatMap(a => fb.map(b => (a, b)))
}
implicit val listApply: Apply[List] = new Apply[List] {
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
def product[A, B](fa: List[A], fb: List[B]): List[(A, B)] =
fa.zip(fb)
}
```

Expand Down
10 changes: 0 additions & 10 deletions docs/src/main/tut/const.md
Original file line number Diff line number Diff line change
Expand Up @@ -219,10 +219,6 @@ implicit def constApplicative[Z]: Applicative[Const[Z, ?]] =
def pure[A](a: A): Const[Z, A] = ???
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] = ???
def product[A, B](fa: Const[Z, A],fb: Const[Z, B]): Const[Z, (A, B)] = ???
}
```

Expand All @@ -246,12 +242,6 @@ implicit def constApplicative[Z : Monoid]: Applicative[Const[Z, ?]] =
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] =
Const(fa.getConst)
def product[A, B](fa: Const[Z, A],fb: Const[Z, B]): Const[Z, (A, B)] =
Const(Monoid[Z].combine(fa.getConst, fb.getConst))
}
```

Expand Down
3 changes: 0 additions & 3 deletions docs/src/main/tut/validated.md
Original file line number Diff line number Diff line change
Expand Up @@ -199,9 +199,6 @@ 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(fa.map(a => (b: B) => (a, b)))(fb)
}
```

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 @@ -44,11 +44,11 @@ trait TraverseLaws[F[_]] extends FunctorLaws[F] with FoldableLaws[F] {
val (fm, fn) = f
(M.ap(fm)(fam), N.ap(fn)(fan))
}
def map[X, Y](fx: MN[X])(f: X => Y): MN[Y] = {
override def map[X, Y](fx: MN[X])(f: X => Y): MN[Y] = {
val (mx, nx) = fx
(M.map(mx)(f), N.map(nx)(f))
}
def product[X, Y](fx: MN[X], fy: MN[Y]): MN[(X, Y)] = {
override def product[X, Y](fx: MN[X], fy: MN[Y]): MN[(X, Y)] = {
val (mx, nx) = fx
val (my, ny) = fy
(M.product(mx, my), N.product(nx, ny))
Expand Down

0 comments on commit 051fb84

Please sign in to comment.