Nice F# Syntax for Rx (Reactive Extensions)


Here’s a link to a nice F#-Rx sample showing how to get a very nice syntax for Reactive Extensions by using F# LINQ computation expressions. (If you know Rx users who haven’t yet discovered F#, this might get them interested!)

 

open System

open System.Linq

open System.Reactive.Linq

 

type rxBuilder() =    

    member this.Bind ((xs:’a IObservable), (f:’a -> ‘b IObservable)) =

        Observable.SelectMany (xs, f)

    member this.Delay f = Observable.Defer f

    member this.Return x = Observable.Return x

    member this.ReturnFrom xs = xs

    member this.Combine (xs:’a IObservable, ys: ‘a IObservable) =

        Observable.Concat (xs, ys)

    member this.For (xs : ‘a seq, f: ‘a -> ‘b IObservable) =

        Observable.For(xs, new Func<_, IObservable<_>>(f)) 

    member this.TryFinally (xs: ‘a IObservable, f : unit -> unit) =

        Observable.Finally(xs, new Action(f))

    member this.TryWith (xs: ‘a IObservable, f: exn -> ‘a IObservable) =

        Observable.Catch (xs, new Func<exn, ‘a IObservable>(f))

    member this.While (f, xs: ‘a IObservable) =

        Observable.While (new Func<bool>(f), xs)

    member this.Yield x = Observable.Return x

    member this.YieldFrom xs = xs

    member this.Zero () = Observable.Empty()

              

let rx = rxBuilder()

 

// Rx combinators

 

let repeat (xs:IObservable<_>) = xs.Repeat()

 

// Sample usages

 

let xs = rx { yield 42

              yield 43 }

 

let ys = rx { yield 42

              yield! xs }

 

let zs = rx { for i = 0 to 10 do yield i }

 

let redTime = rx { while (DateTime.Now.Second > 30) do

                      yield ConsoleColor.Red }

 

let blueTime = rx { while (DateTime.Now.Second < 30) do

                      yield ConsoleColor.Green }

 

letcoloredTime  = rx { yield! redTime 
                       yield! blueTime } |> repeat

Comments (2)

  1. Tomas Petricek says:

    This was also recently mentioned on StackOverflow. I think that the code samples are slightly misleading, because they suggest you can use the usual programming style used when working with F# sequences. However, there are quite a few tricky differences – using "let!" may execute the body of the sequence multiple times in parallel and writing an "infinite" recursive loop using "yield!" will eventually give stack overflow exception.

    Nevertheless, it is a nice example and it shows quite a few interesting things that can be written using the F# syntax and cannot be directly written using LINQ (e.g. multiple yields).

    [1] stackoverflow.com/…/how-do-i-change-the-rx-builder-implementation-to-fix-the-stack-overflow-exception

  2. HoloEd says:

    Hi, after blogging the RxBuilder  I discovered the issue with infinite sequences and I post it a question on StackOverflow and Reactive Extensions forum about this.

    social.msdn.microsoft.com/…/6cf59ad7-f7e6-4c2e-bf3b-da4f69f22379

    As Tomas suggested on StackOverflow in order to make this work we need a special Concat that doesnt blow the stack.

    I've been using Rx with C# a lot at work and I think the F# Computation Expression Syntax enables a level of expressiveness that you don't get that easily with C# LINQ.

    Since IObservable is the mathematical dual of IEnumerable (as Erik Meijer team discovered) I think it would make a lot of sense for the RxBuilder to be spiced up to provide the same level of power as seq<T>.

    Cheers,

    HoloEd