Я очень новичок в 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, потому что 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/все остальное, скажите мне, потому что я очень хочу учиться.