2

This is a follow-up to my previous question. Suppose I would like to make a Stream of all strings matching ^a+b+$ (one or more "a" and then one or more "b").

I am coding it as follows:

def interleave(s1:Stream[String], s2:Stream[String]): Stream[String] =
  if (s1.isEmpty) s2 else Stream.cons(s1.head, interleave(s2, s1.tail))

def generate(s1:Stream[String], s2:Stream[String]): Stream[String] =
  if (s1.isEmpty) s1 else interleave(s2.map(s1.head + _), generate(s1.tail, s2))

def as:Stream[String] = Stream.cons("a", as.map(_ + "a"))

def bs:Stream[String] = Stream.cons("b", bs.map(_ + "b"))

def solve = generate(as, bs)

Unfortunately solve fails with out of memory. However it works fine for finite streams: for instance solve(as take 10, bs take 10)

How would you fix the code above? Would you prefer another way to solve the problem?

Michael
  • 10,185
  • 12
  • 59
  • 110
  • Just a side remark: you say you want a series of a then b, but don't anchor your regex with `$`? Why is that? – fge Dec 17 '11 at 18:03
  • @fge you are right. I am fixing the regexp. – Michael Dec 17 '11 at 19:36
  • 1
    the `s2` param to `generate` should be `Stream[String]` i assume, not `Stream[Stream]`. also there is a missing closing brace. – Dave L. Dec 17 '11 at 20:40

2 Answers2

2

How about this one:

scala> val asbs = for(n <- Stream.from(2);k <- 1 until n) yield "a"*k + "b"*(n-k)
asbs: scala.collection.immutable.Stream[String] = Stream(ab, ?)

scala> asbs.take(10).toList
res0: List[String] = List(ab, abb, aab, abbb, aabb, aaab, abbbb, aabbb, aaabb, aaaab)

scala>
Eastsun
  • 18,526
  • 6
  • 57
  • 81
2

The problem is that, in order to be able to call interleave, generate must be computed:

def generate(s1:Stream[String], s2:Stream[String]): Stream[String] =
  if (s1.isEmpty) ... else interleave(..., generate(s1.tail, s2))

So generate will recursive call itself until s1.isEmpty, at which point it will finally call all the hanging interleave's. Since s1 is infinite, it will never be empty.

If you turn the second parameter of interleave into a by-name parameter, then the recursion can be deferred:

def interleave(s1:Stream[String], s2: => Stream[String]): Stream[String] =
Daniel C. Sobral
  • 295,120
  • 86
  • 501
  • 681