Timers in F#

open System
open System.Threading
open System.Threading.Tasks

let main() = 
    // Timers represent a single event in the future. You
    // tell the timer how long you want to wait, and it
    // provides a Task that will complete at that time.
    // This timer will wait 2 seconds.
    let timer1 = Task.Delay(TimeSpan.FromSeconds(2.0))

    // The Await blocks until the task completes,
    // indicating that the timer fired.
    timer1.Wait()
    printfn "Timer 1 fired"

    // If you just wanted to wait, you could have used
    // Thread.Sleep. One reason a timer may be useful is
    // that you can cancel it before it fires.
    // Here's an example of that.
    let cts = new CancellationTokenSource()
    let timer2 = Task.Delay(TimeSpan.FromSeconds(1.0), cts.Token)

    // Start a task that will wait for the timer
    let timer2Task = Task.Run(fun () ->
        try
            timer2.Wait()
            printfn "Timer 2 fired"
        with
        | :? OperationCanceledException -> ()
    )

    // Cancel the timer
    cts.Cancel()
    if cts.IsCancellationRequested then
        printfn "Timer 2 stopped"

    // Give the timer2 enough time to fire, if it ever
    // was going to, to show it is in fact stopped.
    Thread.Sleep(TimeSpan.FromSeconds(2.0))

main()

This F# code demonstrates the use of timers, which are represented by Task.Delay in F#. Here’s a breakdown of the translation:

  1. We use Task.Delay to create a timer that will complete after a specified duration.

  2. The Wait() method is used to block until the timer completes.

  3. For the second timer, we use a CancellationTokenSource to allow cancellation.

  4. We start a separate task to wait for the second timer, wrapping it in a try-catch block to handle cancellation.

  5. We use Thread.Sleep at the end to give enough time for the second timer to fire if it wasn’t cancelled.

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

To run the program, save it as Timers.fsx and use the F# interpreter:

$ dotnet fsi Timers.fsx
Timer 1 fired
Timer 2 stopped

This example demonstrates basic timer functionality in F#, including creating timers, waiting for them to complete, and cancelling them before they fire.