DefaultTraverse doesn't pass all Traverse laws
ceedubs opened this issue · comments
It's possible that I'm doing something silly here, but I thought that I would report in case that's not what's happening. Either way, it would probably be good for droste to be doing more law-checking in tests.
Consider the following simple data type:
import cats.implicits._
import qq.droste.util.DefaultTraverse
import cats.{Applicative, Eq, Traverse}
import org.scalacheck.Arbitrary
final case class Pair[A](l: A, r: A)
object Pair {
implicit val traversePair: Traverse[Pair] = new DefaultTraverse[Pair] {
def traverse[G[_], A, B](fa: Pair[A])(f: A => G[B])(implicit G: Applicative[G]): G[Pair[B]] =
G.map2(f(fa.l), f(fa.r))(Pair(_, _))
}
implicit def eqPair[A](implicit eqA: Eq[A]): Eq[Pair[A]] = Eq.instance((p1, p2) =>
p1.l === p2.l && p1.r === p2.r
)
}
Now run the following test:
import cats.tests.CatsSuite
import cats.laws.discipline.TraverseTests
class DefaultTraverseTests extends CatsSuite {
implicit def arbPair[A](implicit arbA: Arbitrary[A]): Arbitrary[Pair[A]] = Arbitrary(
arbA.arbitrary.flatMap(a1 => arbA.arbitrary.map(a2 => Pair(a1, a2))))
checkAll("Pair", TraverseTests[Pair].traverse[Int, Int, Int, Set[Int], Option, Option])
}
The collectFirstSome
and foldM identity
laws consistently fail. Here is some example output:
- Pair.traverse.collectFirstSome reference *** FAILED ***
GeneratorDrivenPropertyCheckFailedException was thrown during property evaluation.
(Discipline.scala:14)
Falsified after 10 successful property evaluations.
Location: (Discipline.scala:14)
Occurred when passed generated values (
arg0 = Pair(1,1284725810),
arg1 = org.scalacheck.GenArities$$Lambda$11995/1290092155@1195eb5b
)
Label of failing property:
Expected: Some(Set())
Received: Some(Set(-1))
- Pair.traverse.foldM identity *** FAILED ***
GeneratorDrivenPropertyCheckFailedException was thrown during property evaluation.
(Discipline.scala:14)
Falsified after 5 successful property evaluations.
Location: (Discipline.scala:14)
Occurred when passed generated values (
arg0 = Pair(0,2147483647),
arg1 = Set(2061683075),
arg2 = org.scalacheck.GenArities$$Lambda$12122/454406410@5b35771c
)
Label of failing property:
Expected: Set()
Received: Set(-225533737)
Both of these are ultimately implemented in terms of foldRight
, so I suspect that there is an issue with the DefaultTraverse.foldRight
implementation.
I believe this issue was resolved in #81, as the test has been ported over and is now passing. Happy to reopen this issue if we need to.