In Eric Torreborre\'s blogpost on the paper Essence of the Iterator Pattern, he describes how the cartesian product of a traverse is also a traverse.
Can anyone show me
I'm adding my own answer, building on Jason's one, to show different ways of traversing the list:
import org.specs2._
import scalaz.std.anyVal._, scalaz.std.list._
import scalaz._, std.tuple._
import scalaz.{Monoid, Applicative}
class TraverseSpec extends mutable.Specification {
implicit val Sum = Monoid[Int].applicative
implicit val Concat = Monoid[List[String]].applicative
implicit val A: Applicative[({type λ[α] = (Int, List[String])})#λ] = Sum.product[({type λ[α]=List[String]})#λ](Concat)
val xs = List(1, 2, 3, 4)
"traverse - by folding the list with a Monoid" >> {
val (sum, text) = Foldable[List].foldMap(xs)(a => (a, List(a.toString + "Z")))
(sum, text) === (10, List("1Z", "2Z","3Z", "4Z"))
}
"traverse - with a function returning a tuple" >> {
val (sum, text) = A.traverse(xs)(a => (a, List(a.toString + "Z")))
(sum, text.reverse) === (10, List("1Z", "2Z","3Z", "4Z"))
}
"traverse - with 2 functions and 2 traversals" >> {
val count = (a: Int) => a
val collect = (a: Int) => List(a.toString+"Z")
val sum = Sum.traverse(xs)(count)
val text = Concat.traverse(xs)(collect)
(sum, text.reverse) === (10, List("1Z", "2Z","3Z", "4Z"))
}
"traverse - with 2 functions and 1 fused traversal" >> {
val sum = (a: Int) => a
val collect = (a: Int) => List(a.toString+"Z")
implicit def product[A, B, C](f: A => B): Product[A, B] = Product(f)
case class Product[A, B](f: A => B) {
def <#>[C](g: A => C) = (a: A) => (f(a), g(a))
}
val (total, text) = A.traverse(xs)(sum <#> collect)
(total, text.reverse) === (10, List("1Z", "2Z","3Z", "4Z"))
}
}
I think that the last example shows what you're after: 2 independently defined functions which can be composed to do just one traversal.