Skip to content

Commit

Permalink
Swap effect order of apply2 and map2
Browse files Browse the repository at this point in the history
Fixes typelevel#167

I think one thing that everyone agrees on is that if we are going to
require a predictable order of effects with apply2, map2, traverse, etc
that order should be left to right.
  • Loading branch information
ceedubs committed Feb 28, 2015
1 parent a95eff9 commit 56dd134
Show file tree
Hide file tree
Showing 3 changed files with 22 additions and 9 deletions.
4 changes: 2 additions & 2 deletions core/src/main/scala/cats/Apply.scala
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,15 @@ trait Apply[F[_]] extends Functor[F] with ApplyArityFunctions[F] { self =>
* apply2 is a binary version of apply, defined in terms of apply.
*/
def apply2[A, B, Z](fa: F[A], fb: F[B])(f: F[(A, B) => Z]): F[Z] =
apply(fa)(apply(fb)(map(f)(f => (b: B) => (a: A) => f(a, b))))
apply(fb)(apply(fa)(map(f)(f => (a: A) => (b: B) => f(a, b))))

/**
* Applies the pure (binary) function f to the effectful values fa and fb.
*
* map2 can be seen as a binary version of [[cats.Functor]]#map.
*/
def map2[A, B, Z](fa: F[A], fb: F[B])(f: (A, B) => Z): F[Z] =
apply(fa)(map(fb)(b => (a: A) => f(a, b)))
apply(fb)(map(fa)(a => (b: B) => f(a, b)))

/**
* Two sequentially dependent Applys can be composed.
Expand Down
11 changes: 4 additions & 7 deletions std/src/main/scala/cats/std/list.scala
Original file line number Diff line number Diff line change
Expand Up @@ -44,13 +44,10 @@ trait ListInstances {
def foldLazy[A, B](fa: List[A], b: Lazy[B])(f: A => Fold[B]): Lazy[B] =
Fold.iterateRight(fa, b)(f)

def traverse[G[_]: Applicative, A, B](fa: List[A])(f: A => G[B]): G[List[B]] = {
val G = Applicative[G]
val init = G.pure(ListBuffer.empty[B])
val gbuf = fa.foldLeft(init) { (gbuf, a) =>
G.map2(f(a), gbuf)((b, buf) => buf += b)
}
G.map(gbuf)(_.toList)
def traverse[G[_], A, B](fa: List[A])(f: A => G[B])(implicit G: Applicative[G]): G[List[B]] = {
val gba = G.pure(ListBuffer.empty[B])
val gbb = fa.foldLeft(gba)((buf, a) => G.map2(buf, f(a))(_ += _))
G.map(gbb)(_.toList)
}
}

Expand Down
16 changes: 16 additions & 0 deletions tests/src/test/scala/cats/tests/RegressionTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -49,4 +49,20 @@ class RegressionTests extends CatsSuite {
// ensure that side-effects occurred in "correct" order
assert(buf.toList == names)
}

test("#167: confirm apply2 order") {
val twelve = Apply[State[String, ?]].apply2(
State[String, Unit](s => ((), s + "1")),
State[String, Unit](s => ((), s + "2"))
)(State.instance[String].pure((_: Unit, _: Unit) => ())).run("")._2
assert(twelve == "12")
}

test("#167: confirm map2 order") {
val twelve = Apply[State[String, ?]].map2(
State[String, Unit](s => ((), s + "1")),
State[String, Unit](s => ((), s + "2"))
)((_: Unit, _: Unit) => ()).run("")._2
assert(twelve == "12")
}
}

0 comments on commit 56dd134

Please sign in to comment.