Timers in PureScript

Our first example demonstrates the use of timers in PureScript. Timers allow us to execute code at some point in the future or repeatedly at some interval. We’ll focus on timers in this example.

module Main where

import Prelude
import Effect (Effect)
import Effect.Console (log)
import Effect.Timer (Timer, setTimeout, clearTimeout)
import Effect.Aff (Aff, launchAff_, delay)
import Effect.Class (liftEffect)
import Data.Time.Duration (Milliseconds(..))

main :: Effect Unit
main = do
  -- Timers represent a single event in the future. You
  -- tell the timer how long you want to wait, and it
  -- will execute a callback after that time. This timer will wait 2 seconds.
  timer1 <- setTimeout 2000 (log "Timer 1 fired")

  -- We use `launchAff_` to run an asynchronous effect that waits for 2 seconds
  -- This is similar to blocking on a channel in the original example
  launchAff_ do
    delay (Milliseconds 2000.0)
    liftEffect $ log "Timer 1 fired"

  -- If you just wanted to wait, you could have used
  -- `delay`. One reason a timer may be useful is
  -- that you can cancel the timer before it fires.
  -- Here's an example of that.
  timer2 <- setTimeout 1000 (log "Timer 2 fired")

  -- We immediately stop timer2, so it should never fire
  clearTimeout timer2
  log "Timer 2 stopped"

  -- Give timer2 enough time to fire, if it ever
  -- was going to, to show it is in fact stopped.
  launchAff_ $ delay (Milliseconds 2000.0)

To run this program, you would typically compile it with the PureScript compiler and then execute the resulting JavaScript. The exact commands might vary depending on your project setup, but it could look something like this:

$ spago build
$ node -e "require('./output/Main').main()"
Timer 1 fired
Timer 2 stopped

The first timer will fire approximately 2 seconds after we start the program, but the second should be stopped before it has a chance to fire.

In this PureScript version, we use the Effect.Timer module to create and manage timers. The setTimeout function is used to create a timer, and clearTimeout is used to cancel it. We use launchAff_ and delay from the Effect.Aff module to handle asynchronous operations, which is similar to how channels are used in the original example for synchronization.

Note that PureScript, being a purely functional language, handles side effects and asynchronous operations differently from imperative languages. The use of Effect and Aff types helps manage these operations in a pure and composable way.