2011-10-03 17 views
6

Chcę użyć IO Monad.Scalaz's traverse_ with IO monad

Ale ten kod nie działa z dużym plikiem. Otrzymuję komunikat StackOverflowError. Próbowałem opcji -DXss, ale powoduje to ten sam błąd.

val main = for { 
    l <- getFileLines(file)(collect[String, List]).map(_.run) 
    _ <- l.traverse_(putStrLn) 
} yield() 

Jak mogę to zrobić?


Napisałem Iteratee, który jest wyprowadzeniem wszystkich elementów.

def putStrLn[E: Show]: IterV[E, IO[Unit]] = { 
    import IterV._ 
    def step(i: IO[Unit])(input: Input[E]): IterV[E, IO[Unit]] = 
    input(el = e => Cont(step(i >|> effects.putStrLn(e.shows))), 
     empty = Cont(step(i)), 
      eof = Done(i, EOF[E])) 
    Cont(step(mzero[IO[Unit]])) 
} 
val main = for { 
    i <- getFileLines(file)(putStrLn).map(_.run) 
} yield i.unsafePerformIO 

Jest to również ten sam wynik.

Wydaje mi się, że przyczyną jest implementacja IO.

+1

pierwsze pytanie jest dlaczego */* jak prawda działa z dużym plikiem Czy otrzymujesz błąd przepełnienia stosu, błąd braku pamięci lub coś innego? –

+1

Otrzymuję komunikat StackOverflowError. Próbowałem opcji -DXss, ale wystąpił ten sam błąd. –

+0

Zgadzam się, myślę, że IO Monada dodaje trochę wyzwania. – huynhjl

Odpowiedz

4

To dlatego scalac nie optymalizuje loop wewnątrz getReaderLines dla połączeń ogona. loop jest rekursywny, ale myślę, że anonimowa funkcja składnia case staje na przeszkodzie.

Edit: Właściwie to nawet nie ogon rekurencyjnej (owijanie w IO monady) powoduje, że co najmniej jedno połączenie po rekurencyjnego wywołania. Kiedy wczoraj robiłem swoje testy, użyłem podobnego kodu, ale zrezygnowałem z monady IO i wtedy można było uczynić ogon Iteratee rekursywnym. Poniższy tekst nie zakłada żadnej monady IO ...

Zdarzyło mi się znaleźć to wczoraj podczas eksperymentów z iteratami. Myślę, że zmieniając podpis loop to pomoże (tak w chwili obecnej może być reimplement getFilesLines i getReaderLines:

@annotations.tailrec 
def loop(it: IterV[String, A]): IO[IterV[String, A]] = it match { 
    // ... 
} 

Prawdopodobnie powinniśmy zgłosić to do folku scalaz (i mogą być otwarte biletem wzmocnienie . do Scala)

to pokazuje, co się dzieje (kod niejasno podobny do getReaderLines.loop):

@annotation.tailrec 
def f(i: Int): Int = i match { 
    case 0 => 0 
    case x => f(x - 1) 
} 
// f: (i: Int)Int 

@annotation.tailrec 
def g: Int => Int = { 
    case 0 => 0 
    case x => g(x - 1) 
} 
/* error: could not optimize @tailrec annotated method g: 
it contains a recursive call not in tail position 
     def g: Int => Int = { 
         ^
*/ 
+0

Proszę złożyć raport, aby można go było poprawić! – AndreasScheinert