I just study Haskell for fun and learn about the language. I thought the following behavior was interesting, and I cannot find the reason why this is happening.
This is a frequently quoted piece of Haskell code that continues to calculate pi until it is interrupted, slightly modified to give a combined list of characters instead of a list of integers:
main :: IO () main = do putStrLn pi' pi' :: [Char] pi' = concat . map show $ g(1,0,1,1,3,3) where g(q,r,t,k,n,l) = if 4*q+rt<n*t then n : g(10*q,10*(rn*t),t,k,div(10*(3*q+r))t-10*n,l) else g(q*k,(2*q+r)*l,t*l,k+1,div(q*(7*k+2)+r*l)(t*l),l+2)
If I run it from the prelude, it will begin to concatenate a string similar to pi numbers:
Ξ»> putStrLn pi' 31415926535897932384626433832795028841971 ... etc.
Works as expected, instantly starting to spew numbers.
Now this is a piece of code that I just wrote that has the same structure. It is completely useless from a mathematical point of view, I just bothered to find out how Haskell works. The operations are much simpler, but it has the same type, as well as an auxiliary function (except for a smaller tuple).
main :: IO () main = do putStrLn func func :: [Char] func = concat . map show $ h(1,2,1) where h(a,b,c) = if a <= 1000 then a : h((div a 1)+2*b,b,1) else h(b,div (b-3) (-1),div aa)
The same result from the prelude:
Ξ»> putStrLn func 1591317212529333741454953576165697377818589 ... etc.
It works as expected, although much faster than the pi function, of course, because the calculations are less complicated.
Now for the part that bothers me:
If I compile: ghc pi.hs and run my program: ./pi , the output remains empty forever until I send an interrupt signal. At this point, the entire calculated string pi is displayed. This is not a "stream" of output in stdout, like GHCI. Well, I know that they do not always behave the same.
But then I run: ghc func.hs and run my program: ./func ... and immediately starts to print a list of characters.
Where does this difference come from? I thought it could be because my stupid useless little function (in the end) repeats, so can the compiler βpredictβ the output better?
Or is there another fundamental difference between how functions work? Or am I doing something completely stupid?
Solution / Answer
Provided by Thomas and Daniel below, I was:
- Impatient. Large chunks end up with the pi function, it is just a bit slow on my simple old coding machine.
- Do not handle buffering in any way.
So, after overwriting the main function:
import System.IO main :: IO () main = do hSetBuffering stdout NoBuffering putStrLn pi'
This has been fixed!