Search code examples
haskellioroutesjack

Haskell -- Concurrent I/O Routing


I am new to Haskell, and I'm not exactly sure how the concurrent I/O works. I'm exploring what can be accomplished with the JACK audio bindings. Basically, the following code is (almost) functional, but I need to press enter twice every time I input a value:

collectInput :: IORef Double -> IO ()
collectInput freq = forever $ do
        putStr ">> "
        hFlush stdout
        f <- getLine
        case readMaybe f of
            Just x -> do 
                putStrLn $ show x
                writeIORef freq x
            Nothing -> do
                 putStrLn "Nada"


main :: IO ()
main = do
    freq <- newIORef 440
    _ <- forkIO $ runJackStuff freq
    collectInput freq

To clarify the problem:

Input  |  Result            | Output
----------------------------------------

330    | Frequency changes  | ">> 330.0"
440    | Nothing happens    | ""
220.0  | Frequency changes  | ">> 220.0"
550.0  | Nothing happens    | ""
bleh   | Outputs "Nada"     | ">> Nada"
       | Nothing Happens    | ""
foo    | Outputs "Nada"     | ">> Nada"

I'm not sure, but it would seem that the IO stream is cycled through threads. Is there a way to make the program read every line of input, instead of every other line?


Solution

  • Implementation always matters. It turns out that runJack called waitForBreak in Sound.JACK, which has the definition:

     waitForBreak :: IO ()
     waitForBreak =
         let go = getLine >> go
         in  go
    

    Using collectInput in its place solved the problem.