2011-10-03 28 views
6

Tôi muốn sử dụng IO monad.Traverse_ của Scalaz với IO monad

Nhưng mã này không chạy với tệp lớn. Tôi nhận được một StackOverflowError. Tôi đã thử tùy chọn -DXss, nhưng nó ném cùng một lỗi.

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

Tôi làm cách nào?


Tôi đã viết Iteratee được xuất tất cả phần tử.

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 

Đây cũng là kết quả tương tự.

Tôi cho là do việc triển khai IO.

+1

câu hỏi thứ nhất là lý do tại sao */bao * là nó không chạy với một tập tin lớn bạn có nhận được một lỗi tràn ngăn xếp, lỗi hết bộ nhớ, hoặc cái gì khác? –

+1

Tôi đang nhận được một StackOverflowError. Tôi đã thử tùy chọn -DXss, nhưng ném cùng một lỗi. –

+0

Đồng ý, tôi nghĩ rằng đơn nguyên IO thêm một chút thách thức. – huynhjl

Trả lời

4

Điều này là do scalac không tối ưu hóa loop bên trong getReaderLines cho các cuộc gọi đuôi. loop là đệ quy đuôi nhưng tôi nghĩ cú pháp hàm ẩn danh case bị cản trở.

Chỉnh sửa: thực sự nó thậm chí không đệ quy đuôi (gói trong đơn nguyên IO) gây ra ít nhất một cuộc gọi sau cuộc gọi đệ quy. Khi tôi thử nghiệm ngày hôm qua, tôi đã sử dụng mã tương tự nhưng tôi đã bỏ đơn IO và sau đó nó có thể làm cho đuôi Iteratee đệ quy. Văn bản bên dưới, giả sử không có đơn nguyên IO ...

Tôi tình cờ phát hiện ra điều đó trong ngày hôm qua khi thử nghiệm với lặp lại. Tôi nghĩ rằng việc thay đổi chữ ký của loop này sẽ giúp (vì vậy trong thời gian này bạn có thể phải reimplement getFilesLinesgetReaderLines:

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

Có lẽ chúng ta nên báo cáo này cho dân gian scalaz (và có thể mở một vé tăng cường . cho scala)

điều này cho thấy những gì xảy ra (mã mơ hồ tương tự như 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

Hãy làm báo cáo để nó có thể được cải thiện! – AndreasScheinert