Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

Haskell does have lazy side effects(unsafeInterleaveIO and its derivatives), which is a major source of complaints about the haskell standard library(lazy IO). There is a huge library ecosystem(conduit, pipes, streaming, machines, what have you) to solve this problem.

For example, this code will fail because the file handle is closed prematurely by withFile as hGetContents returns immediately without actually reading the file, deferring that part until the data is forced.

    main = do
      contents <- withFile "foo.txt" ReadMode hGetContents
      putStrLn $ length contents


I'm assuming there is a more idiomatic (nay, correct?) way of doing this in Haskell?


One possible solution is to take a "beautiful fold" http://hackage.haskell.org/package/foldl-1.3.7/docs/Control-... and connect it to an effectful stream of bytes http://hackage.haskell.org/package/pipes-bytestring-2.1.6/do... inside the callback of "withFile".

Not unlike the Streams/Collectors framework in Java.


But... does that work? Doesn't that leave you open to having something evaluate the end of the "withFile" before you evaluated something in the callback?

That is, the only reason what you said is accurate, is because you said "effectful stream of bytes" meaning "eagerly effectful." Right? If you do all of that lazily, you can just as easily shoot yourself in the foot here.

(Please nobody take this as a damning criticism of Haskell. I'm not intending it that way.)


The streams/sinks work in the IO monad and that induces an ordering of the effects, yes. Within the callback, you can still do things like filtering or taking only a part of the stream.

Returning the stream itself from the "withFile" and trying to run it later still is still a bug.

I like this approach better that conventional Haskell lazy I/O, which I personally find quite confusing.


I guess it just surprises me that having to worry about the state of a stream is a thing I have to do. More, it sounds like I can't really use the typesystem to help here. At least, not from the sound of it.


In praxis a streaming library like pipes, streaming or conduit handles the file handles for you so application code is safe. Safe-ish in the case of streaming but that is a conscious tradeoff between convenience and safety.

You could argue that libraries shouldn't contain unsafe code either and go with a substructural type system, use indexed monads, fake regions or something similar. Whether the extra complexity is worth it is arguable, though.




Consider applying for YC's Winter 2026 batch! Applications are open till Nov 10

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: