I'm just exploring Haskell for fun, and to learn about the language. I thought the following behavior was interesting, and I can't find the reason why this happens.
This is an often quoted piece of Haskell code which keeps calculating pi until interrupted, slightly modified to give a concatenated list of chars 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+r-t<n*t
then n : g(10*q,10*(r-n*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 prelude, it starts concatenating a string resembling the digits of pi:
λ> putStrLn pi'
31415926535897932384626433832795028841971
...etc
Works as expected, it instantly starts spewing out digits.
Now this is a piece of code I just quickly wrote which has the same structure. It's completely useless from a mathematical point of view, I was just messing around to find out how Haskell works. The operations are much simpler, but it does have the same type, and so does the sub function (except for the 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 a a)
Same type of result from prelude:
λ> putStrLn func
1591317212529333741454953576165697377818589
...etc
Works as expected, although much faster than the pi function of course, because the calculations are less complex.
If I compile: ghc pi.hs
, and run my program: ./pi
, the output stays blank forever, until I send an interrupt signal. At that moment, the whole calculated string of pi is instantly displayed. It doesn't "stream" the output into stdout, like GHCI does. OK, I know they don't always behave in the same way.
But next I run: ghc func.hs
, and run my program: ./func
... and it immediately starts printing the list of characters.
Where does this difference come from? I thought it might be because my stupid useless little function is (eventually) repeating, so the compiler can "predict" the output better?
Or is there another fundamental difference between the way the functions work? Or am I doing something utterly stupid?
Provided by Thomas & Daniel below, I was:
So after rewriting the main function:
import System.IO
main :: IO ()
main = do hSetBuffering stdout NoBuffering
putStrLn pi'
It was fixed!
Provided by Thomas & Daniel in the comments, it turned out I was:
So after rewriting the main function:
import System.IO
main :: IO ()
main = do hSetBuffering stdout NoBuffering
putStrLn pi'
It was fixed!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With