Объединение элементов 2 списков - PullRequest
4 голосов
/ 07 февраля 2012

Предположим, у нас есть два списка:

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

Что я хочу: List("a1", "b2", "c3"), то есть добавление n-го элемента l1 с n-м элементом l2

Способдостичь этого:

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

Мне просто интересно, можно ли достичь этого с помощью Applicative.Я попытался:

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

, но он дает все комбинации:

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

Есть идеи?

Спасибо

Бенуа

Ответы [ 2 ]

5 голосов
/ 07 февраля 2012

Вы не можете сделать это со строгими списками, поэтому вместо этого используйте ленивые списки, то есть потоки.Вы должны определить экземпляр 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 для них, удовлетворяющихПрикладные законы.

Кроме того, Scala позволяет вам сделать это более кратко, чем код, который вы использовали в OP:

scala> (l1, l2).zipped.map(_ + _)
res103: List[java.lang.String] = List(a1, b2, c3)
3 голосов
/ 07 февраля 2012

Ответ в том, что вы не можете достичь этого с помощью аппликатива, насколько я вижу.Аппликатив для списка будет применять функцию ко всем комбинациям, как вы узнали.Не очень хорошо для того, что вы хотите, но отлично подходит для таких вещей, как создание декартовых продуктов.

Немного менее подробный метод может использовать Tuple2W.fold, предоставленный scalaz:

(l1 zip l2).map (_ fold (_ + _))
...