I'm getting some practice in Haskell, exploring some areas I'm not familiar with, but I've ben unable to understand the behavior I get while mixing System.Timeout and System.IO.Unsafe.
I'm lazyly read an stream, with getContents, filtering it with a pure function, and outputting the results. A typical filter would be like:
import Data.List(break)
import System.Timeout(timeout)
import System.IO.Unsafe(unsafePerformIO)
main = do
text <- getContents
putStr $ aFilter text
aFilter text = h ++ t where
(h, t) = getUntil "\n" text
getUntil separator text = break (\x -> (separator!!0) == x) text
And with a filter like that, the program reads all stdin, as expected, and outputs to stdout. But If I do something like:
aFilter text = result where
l = consumeWithTimeout (getUntil "\n" text)
result = case l of
Nothing -> "Timeout!\n"
Just (h, t) -> h ++ t
consumeWithTimeout (x, y) = unsafePerformIO $! timeout 6 $! deepseq x (return (x, y))
I'd expect my program to instantly timeout, print the "Timeout!" message, and close. Instead, it hangs there, waiting for input.
Am I wrong in thinking that the timeout function is evaluated at program launch? I expect it to be, because I immediately write part of its return value to stdout, and the software does react every time I input a line. Is unsafePerformIO inserting some kind of lazyness into my function? Or is it inserting lazyness into the internals of System.Timeout?
I would expect
to never trigger the timeout under normal workload. The code above does not force the evaluation of
xandy. Maybe usingevaluatewill help here.Further, using
unsafePerformIOfor this task looks rather overkill. UsingunsafePerformIOshould be done only as a last resort.