2011-03-11 19 views
6

tutaj jest to, co myślałem, że byłoby poprawne i przydatne definicja Nums Fibonacciego w Scala:Scalas (a, b) .zipped (lub Tuple2.zipped) pojęcie wykorzystujące strumienie/lists nieskończone

lazy val fibs:Stream[Int] = 0 #:: 1 #:: (fibs,fibs.tail).zipped.map(_+_) 

jednak Pojawia się następujący błąd:

fibs take 10 foreach println 
0 
1 
java.lang.StackOverflowError 
    at scala.collection.mutable.LazyBuilder.(LazyBuilder.scala:25) 
    at scala.collection.immutable.Stream$StreamBuilder.(Stream.scala:492) 
    at scala.collection.immutable.Stream$.newBuilder(Stream.scala:483) 
    at... 

Zgaduję, że zip nie działa poprawnie ze strumieniami? Wszelkie sugestie, jak to zrobić, czy dlaczego to robi (nie powinno?) Działa?

+0

Chciałem tylko zadać to _exact_ pytanie. Fajnie wiedzieć, że ktoś tu był przede mną. +1 – KChaloux

Odpowiedz

8

Poniższe działa poprawnie

val fibs:Stream[Int] = 0 #:: 1 #:: (fibs zip fibs.tail).map{ case (a,b) => a+b } 

Problem z Tuple2.zipped jest to, że zakłada, że ​​może uruchomić foreach na sekwencjach to skompresowanie. Jest to prawdopodobnie zgodne z projektem, ponieważ wykonanie pewnych czynności w sposób, w jaki implementuje to narzędzie, prawdopodobnie dałoby złą wydajność dla dowolnej skończonej długości Seq, która nie jest List lub . (Ponieważ większość struktur dane nie wspierają efektywną realizację tail.)


Stream.zip zasadniczo realizowane w następujący sposób (choć robi pewne rzeczy, aby typy bardziej ogólnie).

class Stream[A]{ 
    def zip(other:Stream[B]) = 
    (this.head, other.head) #:: (this.tail zip other.tail) 
} 
+0

Chociaż kwalifikator 'leniwego' w twoim pytaniu był niepotrzebny, zapewniam cię, że usunięcie go w mojej odpowiedzi nie było tym, co spowodowało tę pracę. –

+0

Dobra, to, co pokazałeś, jest bardzo miłe :) Myślę, że to tylko pokazuje, jak bardzo potrzebujemy "zipWith", który przyjmuje funkcję 2-arity jako argument, jak w haskell. Naprawdę nie rozumiem, dlaczego nie ma go w Scali? – Felix

+1

@Felix: Nie rozumiem, w jaki sposób 'zipWith' może pomóc. 'zipWith' na krotce nadal byłby implementowany jako' foreach', który przepełniłby się, gdy pierwsza lista byłaby nieskończonym strumieniem. –

3

Jest to bilet na ten temat w bazie danych Trac Scala: http://lampsvn.epfl.ch/trac/scala/ticket/2634

Bilet został zamknięty jako WONTFIX, ale należy pamiętać, Adriaan w „A my czegoś brakuje?” w komentarzach - może kiedyś się to powtórzy.