4

假设我们有两个列表:

val l1=List("a","b","c")
val l2 = List("1","2","3")

我想要的是:List("a1", "b2", "c3")也就是说,将 l1 的第 n 个元素与 l2 的第 n 个元素相加

实现它的一种方法是:

(l1 zip l2).map (c => {c._1+c._2})

我只是想知道是否可以通过 Applicative 实现它。我试过了 :

(l1 |@| l2) { _+ _ } 

但它提供了所有组合:

List(a1, a2, a3, b1, b2, b3, c1, c2, c3)

任何想法?

谢谢

贝努瓦

4

2 回答 2

5

您不能使用严格列表来做到这一点,因此请改用惰性列表,即流。您必须定义Applicative[Stream]实例,如下所示。(你可以在 Haskell 标准库中以 ZipList 为名找到它。)

scala> val s1 = Stream("a", "b", "c")
s1: scala.collection.immutable.Stream[java.lang.String] = Stream(a, ?)

scala> val s2 = Stream("1", "2", "3")
s2: scala.collection.immutable.Stream[java.lang.String] = Stream(1, ?)

scala> implicit object StreamApplicative extends Applicative[Stream] {
     |   def pure[A](a: => A) = Stream.continually(a)
     |   override def apply[A, B](f: Stream[A => B], xs: Stream[A]): Stream[B] = (f, xs).zipped.map(_ apply _)
     | }
defined module StreamApplicative

scala> (s1 |@| s2)(_ + _)
res101: scala.collection.immutable.Stream[java.lang.String] = Stream(a1, ?)

scala> .force
res102: scala.collection.immutable.Stream[java.lang.String] = Stream(a1, b2, c3)

这不能用严格的列表来完成的原因是因为不可能pure在它们上定义满足应用法则的 a。

顺便说一句,Scala 让您可以比您在 OP 中使用的代码更简洁地执行此操作:

scala> (l1, l2).zipped.map(_ + _)
res103: List[java.lang.String] = List(a1, b2, c3)
于 2012-02-06T20:50:47.310 回答
3

答案是,据我所知,您无法通过应用程序实现此目的。如您所见,列表的应用程序会将函数应用于所有组合。对于您想要的东西来说不是很好,但对于创建笛卡尔积之类的东西来说却很棒。

Tuple2W.foldscalaz可能会使用稍微不那么冗长的方法:

(l1 zip l2).map (_ fold (_ + _))
于 2012-02-06T20:45:38.803 回答