You cannot do this with strict lists, so use lazy lists instead, i.e. streams. You must define an instance of Applicative[Stream] as shown below. (You will find it in the Haskell standard library under the name 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)
The reason this cannot be done with strict lists is because it is impossible to define a pure on them that satisfies the application laws.
As an aside, Scala allows you to do this more concisely than the code you used in OP:
scala> (l1, l2).zipped.map(_ + _) res103: List[java.lang.String] = List(a1, b2, c3)
source share