Does there exist or how much fuss would it be to implement a setTimeout function in Haskell?
The main idea is
setTimeout someFunction 1000 --someFunction will be called in 1000ms = 1s
I am new to Haskell and probably will not use this; I am learning Haskell for the kick of it.
A game's event loop usually requires you to
Managing time is a great deal (hence setTimeout) here to ensure constant FPS.
How would a pattern like this look on Haskell?
Does there exist or how much fuss would it be to implement a setTimeout function in Haskell?
JavaScript's setTimeout
and other similar methods like Qt's QTimer usually work within a single event loop in a single thread (not counting web workers or QThread
). Modelling that exact behaviour is a little bit hard, although not impossible, with Haskell, as GHC already provides an (internal) implementation.
If you don't care for the actual single-threaded behaviour (which also means that two functions with almost the same timeout can possibly execute at the same time), then you can simply fork a new thread and delay its action:
doLater :: Int -> IO () -> IO ThreadId
doLater ms io = forkIO $ threadDelay (ms * 1000) >> io
For any further thoughts, we would actually need to know more about your specific event loop.
How would a pattern like this look on Haskell?
Very, very generalised, you would need something like this:
mkGame :: World
-> (Input -> World -> World)
-> (TimeDiff -> World -> World)
-> (World -> GraphicalRepresentation)
-> IO ()
mkGame initialWorld handleInput handleProgression drawWorld = undefined
Note that you can probably throw other arguments in there, such as the maximum number of world updates per second.
How could we now model setTimeout? Assume that World
is something like:
data World = World {
getWorldData :: WorldData,
getCurrentTime :: TimePoint, -- would get updated by your loop
getTimeouts :: Queue TimePoint (World -> World)
}
where Queue
is any working priority queue (pick one, there are many, or build your own). Now you can simply set a timeout by using
setTimeout world delay action = world { getTimeouts = timeouts' }
where timeouts' = insert (getTimeouts world) t action
t = delay + getCurrentTime world
-- insert :: Queue p v -> p -> v -> Queue p v
If you want to be able to cancel timeouts, you also need a key on Queue
, have a look at GHC.Event.PSQ for inspiration.
Aside from that you can now check whether the time has passed and act accordingly in your game loop by simply going through the queue, and applying all your functions.
This is basically a very simple and crude foundation you can use to inspire your own work on. Depending on what you actually want to do, you might want to have a look at gloss
, which already implements a very similar concept, although without timeouts, but in this case you can still add the timeouts and the total time difference in to your world and simply use a fitting update function (the TimeDiff -> World -> World
part).
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