I'm trying to write a simple command line based reflex game which will prompt the user to hit enter after a random amount of time and then output the reaction time. I'm using reactimate based on this example: https://wiki.haskell.org/Yampa/reactimate My code works perfectly fine in the way I intend it to:
module Main where
import Control.Monad
import Data.IORef
import Data.Time.Clock
import System.Random
import FRP.Yampa
main :: IO ()
main = do
startTime <- getCurrentTime
startTimeRef <- newIORef startTime
randomTime <- randomRIO (0, 10)
reactimate helloMessage (sense startTimeRef) sayNow (randomTimePassed randomTime)
playerTime <- getCurrentTime
playerTimeRef <- newIORef playerTime
s <- getLine --programm will wait here
reactimate doNothing (sense playerTimeRef) endMessage (enterPressed s)
now <- getCurrentTime
let reactionTime = now `diffUTCTime` playerTime in putStr (show reactionTime)
helloMessage :: IO ()
helloMessage = putStrLn "Press Enter as quickly as possible when I say so..."
randomTimePassed :: Double -> SF () Bool
randomTimePassed r = time >>> arr (>r)
sayNow :: Bool -> Bool -> IO Bool
sayNow _ x = when x (putStrLn "NOW!") >> return x
doNothing :: IO ()
doNothing = return ()
enterPressed :: String -> SF () Bool --this is not how I want it to be
enterPressed s = arr (\_ -> s == "")
endMessage :: Bool -> Bool -> IO Bool
endMessage _ x = when x (putStr "You reacted in: ") >> return x
sense :: IORef UTCTime -> Bool -> IO (Double, Maybe ())
sense timeRef _ = do
now <- getCurrentTime
lastTime <- readIORef timeRef
writeIORef timeRef now
let dt = now `diffUTCTime` lastTime
return (realToFrac dt, Just ())
But it doesn't realy make use of FRP at all for the pressing enter part I marked in the code. As the programm just waits for getLine to terminate and then instantly ends the reactimate loop. So it's pretty much just using the IO Monad instead of FRP. Is there any way to refactor the signal function enterPressed
so that it works in a "FRPish" way? Or is this simply not possible when using reactimate?