笛卡尔积在斯卡拉兹中

oxb*_*kes 5 functional-programming scala traversal scalaz

Eric Torreborre关于迭代器模式的本质论文的,他描述了导线的笛卡尔积也是如何遍历.

任何人都可以使用scalaz库向我展示这个例子,因为我无法弄明白.让我们说问题是,对于List[Int]我想提供的两个:

  1. Int列表中元素的总和
  2. List[String]其中的元件通过附加"Z"到的String表示创建的Int小号

我的理解是,我可以使用traverse这种方式,但只是实际遍历我的结构一次,不像这个解决方案:

val xs = List(1, 2, 3, 4)
val (sum, strings)  = (xs.sum, xs map (_.toString + "Z"))
Run Code Online (Sandbox Code Playgroud)

注1 - 我知道还有其他方法可以做到这一点,我不需要遍历这个例子,也不一定是最简单的解决方法.但是,我试图理解遍历,所以我真的在寻找所述问题的答案


编辑 - 感谢missfaktor下面显示如何使用State.我想我想知道的是我如何编写两个独立的计算.例如; 我的职能在概念上如下:

val shape = (_ : List[Int]) map (_.toString + "Z")
val accum = (_ : List[Int]).sum
Run Code Online (Sandbox Code Playgroud)

我希望这些累积机制彼此独立,然后选择是否List[Int]使用其中一个两个来遍历我.我想象一些代码有点像这样:

xs traverse shape //A List[String]
xs traverse accum //An Int

xs traverse (shape <x> accum) //The pair (List[String], Int)
Run Code Online (Sandbox Code Playgroud)

Eric意味着这是可能的,但我不知道如何做到这一点〜即我没有看到如何定义shapeaccum以这样的方式,他们可以组成,也不知道如何组成它们.

注2: shapeaccum并不意味着字面上是具有如上述的特征的功能.它们是具有执行上述遍历所必需的类型的表达式.

Eri*_*ric 4

我在 Jason 的答案的基础上添加了我自己的答案,以展示遍历列表的不同方式:

\n\n
import org.specs2._\nimport scalaz.std.anyVal._, scalaz.std.list._\nimport scalaz._, std.tuple._\nimport scalaz.{Monoid, Applicative}\n\nclass TraverseSpec extends mutable.Specification {\n\n  implicit val Sum = Monoid[Int].applicative\n  implicit val Concat = Monoid[List[String]].applicative\n  implicit val A: Applicative[({type \xce\xbb[\xce\xb1] = (Int, List[String])})#\xce\xbb] = Sum.product[({type \xce\xbb[\xce\xb1]=List[String]})#\xce\xbb](Concat)\n  val xs = List(1, 2, 3, 4)\n\n  "traverse - by folding the list with a Monoid" >> {\n    val (sum, text) = Foldable[List].foldMap(xs)(a => (a, List(a.toString + "Z")))\n    (sum, text) === (10, List("1Z", "2Z","3Z", "4Z"))\n  }\n  "traverse - with a function returning a tuple" >> {\n    val (sum, text) = A.traverse(xs)(a => (a, List(a.toString + "Z")))\n    (sum, text.reverse) === (10, List("1Z", "2Z","3Z", "4Z"))\n  }\n  "traverse - with 2 functions and 2 traversals" >> {\n    val count   = (a: Int) => a\n    val collect = (a: Int) => List(a.toString+"Z")\n\n    val sum  = Sum.traverse(xs)(count)\n    val text = Concat.traverse(xs)(collect)\n\n    (sum, text.reverse) === (10, List("1Z", "2Z","3Z", "4Z"))\n  }\n  "traverse - with 2 functions and 1 fused traversal" >> {\n    val sum     = (a: Int) => a\n    val collect = (a: Int) => List(a.toString+"Z")\n\n    implicit def product[A, B, C](f: A => B): Product[A, B] = Product(f)\n    case class Product[A, B](f: A => B) {\n      def <#>[C](g: A => C) = (a: A) => (f(a), g(a))\n    }\n\n    val (total, text)  = A.traverse(xs)(sum <#> collect)\n    (total, text.reverse) === (10, List("1Z", "2Z","3Z", "4Z"))\n  }\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

我认为最后一个例子展示了你所追求的:2个独立定义的函数,可以组合起来只进行一次遍历。

\n