Haskelier
Haskelier

Reputation: 83

ThreadDelay Outside the Main Thread

I've been trying to write a function that prints out a string letter by letter, without quotes, and pauses for a little in between each letter. For example, if you give it "hello", it'll print h, then wait, the e, then wait, then l, then wait, then l, then wait, the o. But when i try to use threadDelay, it pauses in the main thread. So it'll pause, then print everything all at once. I tried to fork a new thread in the prints function, but it doesn't work. Help!

import Control.Concurrent as C

clean :: String -> String
clean s@[c]               = s
clean ('"':s)  
    | last s == '"'       = init s
    | otherwise           = s
clean ('\'':s) 
    | last s == '\''      = init s           
    | otherwise           = s
clean s                   = s

prints :: String -> IO()
prints [] = putStrLn " "
prints (x:xs) = do
    C.forkIO $ do
        putStr $ clean (show x)
        C.threadDelay $ 10000
        prints xs  

main :: IO()
main = do 
    prints "hello"

Upvotes: 2

Views: 122

Answers (1)

Ganesh Sittampalam
Ganesh Sittampalam

Reputation: 29120

Your code has a few problems.

Firstly, threadDelay takes an argument in microseconds, so the pause you are adding is too small to notice. Try 1000000.

Secondly, unless you turn off buffering on stdout, the IO library will buffer up your output so you won't see it with the expected delays. You can control this with System.IO:

import System.IO ( stdout, hSetBuffering, BufferMode(..) )

and then call hSetBuffering from main:

hSetBuffering stdout NoBuffering

Finally, forking off a thread is actually a step backwards, because the program doesn't wait for the forked threads to finish, so just remove that. If you really want it to be in the background, you'll need to use an MVar or similar to wait for it to finish if the program will otherwise naturally exit first.

Upvotes: 4

Related Questions