Хвост-рекурсивный ограниченный поток пар целых чисел (Scala)?

Я новичок в Scala, так что простите мое невежество! Я пытаюсь перебрать пары целые числа, ограниченные максимальным значением. Например, если максимальное значение равно 5, то итерация должна возвращать:

(0, 0), (0, 1), ..., (0, 5), (1, 0), ..., (5, 5)

Я решил попытаться хвостовой рекурсией вернуть это как поток:

    @tailrec
    def _pairs(i: Int, j: Int, maximum: Int): Stream[(Int, Int)] = {
        if (i == maximum && j == maximum) Stream.empty
        else if (j == maximum) (i, j) #:: _pairs(i + 1, 0, maximum)
        else (i, j) #:: _pairs(i, j + 1, maximum)
    }

Без аннотации tailrec код работает:

scala> _pairs(0, 0, 5).take(11)
res16: scala.collection.immutable.Stream[(Int, Int)] = Stream((0,0), ?)

scala> _pairs(0, 0, 5).take(11).toList
res17: List[(Int, Int)] = List((0,0), (0,1), (0,2), (0,3), (0,4), (0,5), (1,0), (1,1), (1,2), (1,3), (1,4))

Но мне этого недостаточно, компилятор правильно указывает, что последняя строка _pairs не возвращает _pairs:

could not optimize @tailrec annotated method _pairs: it contains a recursive call not in tail position
    else (i, j) #:: _pairs(i, j + 1, maximum)
                ^

Итак, у меня есть несколько вопросов:

  • непосредственно к реализации выше, как хвост-рекурсивно вернуть Stream[(Int, Int)]?
  • Делая шаг назад, каков наиболее эффективный с точки зрения памяти способ перебора ограниченных последовательностей целых чисел? Я не хочу перебирать Диапазон, потому что Range расширяет IndexedSeq, и я не хочу, чтобы последовательность полностью существовала в памяти. Или я ошибаюсь? Если я перебираю Range.view, я избегаю его появления на память?

В Python (!), все, что я хочу, это:

In [6]: def _pairs(maximum):
   ...:     for i in xrange(maximum+1):
   ...:         for j in xrange(maximum+1):
   ...:             yield (i, j)
   ...:             

In [7]: p = _pairs(5)

In [8]: [p.next() for i in xrange(11)]
Out[8]: 
[(0, 0),
 (0, 1),
 (0, 2),
 (0, 3),
 (0, 4),
 (0, 5),
 (1, 0),
 (1, 1),
 (1, 2),
 (1, 3),
 (1, 4)]

Спасибо за вашу помощь! Если вы считаете, что мне нужно прочитать справочные материалы/документацию по API/что-нибудь еще, пожалуйста, скажите мне, потому что я очень хочу учиться.

14
задан Will Ness 26 October 2013 в 10:26
поделиться