Reactive programming with WebSharper

Joel Bjornson

Joel Bjornson

Jun 17, 2010

Reading time:

5 mins

Share via:

In following post I'd like to highlight F# (and WebSharper) support for asynchronous and reactive programming.

Some of the things that make F#/WebSharper particularly suited for this domain includes:

  • Events as first class values
  • Provided event combinators - mapping, merging, filtering etc.
  • Nice syntax for asynchronous programming via work-flow builders.

To give a concrete example let's implement a small application polling the server for price information. First we assume a server side method that given a string value representing a country returns the current price:

[<Rpc>]
let CurrentPrice (country: string) : Async<int>=        
    async {
        let price = ...
        return price
    }

In order for the function to be non blocking the actual calculation of the price information is encapsulated within an asynchronous computation.

We are interested in keeping track of the highest price and showing the maximum value found so far by any call to the server method.

We also assume that the pricing information fluctuates frequently, why we need to poll the server repeatedly.

A sequence of prices may be modeled as an event stream. Here is a general helper function for creating a stream of values, given a function for fetching a new result and a delay time for specifying the sampling frequency:

[<JavaScript>]
let ValueStream (delay: int) (getValue : unit -> Async<'T>) : IEvent<'T> = 
    let resultEv = Event<'T>() 
    let rec work () = async {
        let! x = getValue ()
        resultEv.Trigger x
        do! Async.Sleep delay    
        do! work ()
    }                
    work ()
    |> Async.Start
    resultEv.Publish

First a new event (resultEv) is created. Then a function (work) producing an asynchronous value is defined. The resulting value is pushed into resultEv as a side effect.

Next, the Main function defines a list of value streams based on different ways to call the CurrentPrice method and creates a dynamically updated element displaying the latest price information:

[<JavaScript>]
let Main () =
    let bestPriceLabel =
        [
            ValueStream 3000 (fun () -> CurrentPrice "Hungary")
            ValueStream 2000 (fun () -> CurrentPrice "France")
            ValueStream 1000 (fun () -> CurrentPrice "USA")
        ]
        |> List.reduce Event.merge
        |> Event.scan max 0
        |> Event.pairwise
        |> Event.choose (fun (x,y) -> 
            if y > x then 
                Label [
                    Text ("Best Price: " + string y)
                ]
                |> Some
            else 
                None
        )
    Div []
    |>! OnAfterRender (fun el ->
        bestPriceLabel.Add (fun label ->
            el.Clear()
            el.Append label
         )       
    )

The list of events is merged into a single event stream. Event.scan is then used to accumulate the maximum price found so far. Since we are only interested in new values the pairwise and choose functions are utilized in order to only collect values larger than the previous one. The integer values are transformed into Html.Element objects, producing a stream of elements.

Finally to show the labels we subscribe to the bestPriceLabel event with a callback function for appending labels to a container element.

Any time a new (higher) price is encountered, the content of the outer container will be replaced with a new label displaying the price.

Read more from

Can’t find what you were looking for? Drop us a line.

Joel Bjornson
Found a typo?

This blog post is hosted on GitHub here. Feel free to file a ticket or send a PR.

Newsletter

We will not spam you or give your details to anyone.