2013-03-30 2 views
0

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

def machine(n:Int) = if (n==0) List(0) else List(n/2,n/3,n/4) 
def greater(n:Int) = machine(n).sum > n 

val d: Stream[Int] = 2 #:: d.map(_+1).filterNot(greater) 

scala> d.take(11).toList 
res41: List[Int] = List(2,3,4,5,6,7,8,9,10,11) 

//12 is the first number for which greater will return true 
scala> d.take(12).toList 
//Returns a ton of scala.collection.immutable.Stream errors 

Не мог бы кто-нибудь объяснить мне, что именно здесь происходит неправильно? Благодарю.

ответ

2

Код работает рекурсивно. Когда у вас заканчиваются элементы в вашем потоке, рекурсия никуда не денется, и в конечном итоге у вас заканчивается пространство стека. (Что вы ожидаете, когда вы попросите больше предметов, чем может быть в вашем потоке, потому что вы отфильтровываете все крупные из них? Вы должны либо получить переполнение стека, либо не прекратить (повесить), верно?)

+0

Конечно, повешение - это правильное поведение здесь, но я бы не ожидал, что он будет потреблять линейный стек во время длительных прогонов фильтрованных элементов. –

+0

@MyseriousDan - ленивые структуры данных не всегда потребляют стек так, как вы ожидали, по крайней мере, если бы это было реализовано наивным образом. –

+0

Я понимаю, что (я родом из Haskell-land), но переполнение стека в библиотечной функции, используемой допустимым образом, кажется мне неправильным. Потребление линейного стека практически никогда не будет правильным. –

Смежные вопросы