F# First Class Events – Composing Events Until Others

After a comment on my last post in regards to First Class Events in F#, I thought I’d revisit them briefly before going back to the Reactive Framework series.  In particular, this comment was in regards to implementing the until combinator using F# First Class Events.  As part of my hacking during this series, I came across a rather identical solution to the one that was posted, so I thought it’d be worth exploring.

Implementing Until

The idea behind the until event combinator is to that we will return values from our event until any notification from the other event occurs.  In order to accomplish this, we must subscribe to the other event and if it has fired, then we reset a flag to not fire.  We then have to subscribe to the main event and only trigger when the flag is set to true.  Let’s look through how this code might look.

module Event =

 let until (other: IEvent<_,_>) (source: IEvent<_,_>) =
   let event = new Event<_>()
   let fire = ref true
   other .Add(fun _    -> fire := false)
   source.Add(fun args -> if !fire then event.Trigger args)
   event.Publish

In order for us to modify the fire flag, we must use a ref cell.  The reason being is that local mutables are always stack allocated which is why you cannot capture them inside a closure.  One comment that was made about this solution was that we added two subscriptions for creating this single event.  That indeed can be a problem as Tess Ferrandez points out about event handlers that made the memory balloon where you hook up to static event handlers that long outlive pages.  That’s not necessarily something we’ll address here, and it’s rare that we’ll run into this situation.

Now that we have this until defined, what can we do with it?  In my previous post, we used the WebClient to track the progress changed of a download until the download has completed.  We’ll use that same logic here using our F# first class events.

open System
open System.Net

type IDelegateEvent<'Del when 'Del :> Delegate > with
  member this.Subscribe(d) =
    this.AddHandler(d)
    { new IDisposable with
        member disp.Dispose() =
          this.RemoveHandler(d) }

let wc = new WebClient(Credentials = new NetworkCredential("foo","bar"))

let progSub =
  wc.DownloadProgressChanged
  |> Event.until wc.DownloadStringCompleted
  |> fun event -> 
       event.Subscribe(fun _ args -> printfn "%d%% Complete" args.ProgressPercentage)

let downloadSub =
  wc.DownloadStringCompleted.Subscribe (fun _ args -> printfn "%s" args.Result)   

Here, once again I’m using the extension method I created that allows us to dispose of our event handlers easily through an IDisposable interface.  This follows the design of the Reactive Framework, and quite frankly, makes a lot of sense.  What we’re able to do is create our DownloadProgressChanged subscription which listens until the DownloadStringCompleted event and then we output our percentage complete as it goes along.  The download subscription is much like before in that we subscribe to the event and can dispose at any time later in our program.

Adding Some Monadic Magic

Let’s add another wrinkle here to our solution.  What if we want to create our mouse drag event like we had from the previous post using the Reactive Framework?  Let’s review the code that was required in Rx to make this happen.

var mouseDrag = from md in this.GetMouseDown()
                from mm in this.GetMouseMove().Until(this.GetMouseUp())
                select mm;

I may have hinted in the previous post, that LINQ to Objects is an implementation of the list monad and the Reactive Framework is an implementation of the continuation monad.  As Erik points out in one of his recent Channel 9 episodes, indeed many of the interesting things we’re finding in programming are coming in monadic form.  We’ll cover exactly what that means in a later post, but what if we could apply the same kind of logic from the above and apply it to F# first class events as well? 

In order to make this happen, we need to implement a bind/collect combinator.  This bind function follows the basic pattern of:

val bind : M<'a> -> ('a -> M<'b>) -> M<'b>

Where the M is some monadic type.  In the case of LINQ to Objects, this is the SelectMany method and the M type is an IEnumerable<T>.  If we were to construct the collect combinator from scratch for an IEnumerable<T>, it might look like the following:

let collect f = Seq.map f >> Seq.concat

And our approach to doing this with events should be no different.  In this case, we also need to implement the concat combinator as well as that does not exist in the base libraries but pretty simple to create.  First, with the concat, we need to take in a IEvent of an IEvent and concatenate them together in a way that we get only an IEvent as a return.  In order to do so, we need to add a handle to our source, which in turn listens to the inner events and triggers our new event that we later publish.  Secondly, we’ll need to implement the collect combinator much like we had above, but this time for events.  Below is what the code might look like.

module Event =

 let concat (source: IEvent<IEvent<_,_>>) =
   let event = new Event<_>()
   source.Add (Event.listen event.Trigger)
   event.Publish

 let collect f =
   Event.map f >> concat

Now that we have a basis for binding together our events, let’s create a monadic builder so that we could write event expressions much as we would for sequence expressions.  In this case, we only need the bind and not the return for this instance.  A simple return wouldn’t make sense to yield a single value through an event.

type EventBuilder() =
  member this.Bind(m, f) = Event.collect f m
let event = new EventBuilder()

Now that we have this defined, F# gives us some syntactic sugar much like the do notation in Haskell.  Let’s now add an extension method to the WinForms Control class.

type System.Windows.Forms.Control with
  member this.MouseDrag = event {
    let! _ = this.MouseDown
    return! this.MouseMove |> Event.until this.MouseUp }

And there you have it!  We now have a mouse drag event exposed on our control class which tracks only when the mouse button is down and our mouse is moving.  To get an idea of what it’s doing behind the scenes, I’ll also include the non-syntactic sugar version.

type System.Windows.Forms.Control with
  member this.MouseDrag = 
    event.Bind(this.MouseDown, fun _ ->
      this.MouseMove |> Event.until this.MouseUp)

And now we can subscribe to this much like any other event and have it track our mouse.

Conclusion

Creating composable events using F# first class events is a pretty compelling story.  One of the driving ideas behind the Reactive Framework in terms of composable events does in fact come from F#.  Come .NET 4.0, it will be interesting on how Rx and F# First Class Events can co-exist and in fact compliment each other.  Now back to the Reactive Framework series.

This entry was posted in Event-based Porgramming, F#, Functional Programming, Reactive Framework. Bookmark the permalink. Follow any comments here with the RSS feed for this post.
  • http://codebetter.com/members/Paks/default.aspx Paks

    Hehehehe, you’re right. I got confused for a moment.
    :)

  • http://codebetter.com/members/Matthew.Podwysocki/default.aspx Matthew.Podwysocki

    @Paks

    Actually the code is correct. The (!) operator is not the “not” operator that it is from C#; instead it is to get the value of a ref cell. Leaving off this operator will make this code fail to compile as I cannot check the count of a ref. Run them through F# and you’ll find they work exactly as written.

    Matt

  • http://codebetter.com/members/Paks/default.aspx Paks

    takeWhile has the same issue as skipWhile. It would never fire.

    Cesar

  • http://codebetter.com/members/Paks/default.aspx Paks

    In looking at the code at http://gist.github.com/211922 I found a bug in skipWhile

    The error is in “if !ok then”. Change it to “if ok then”
    The way it is, it would never skip an event.

    let skipWhile predicate (sourceEvent:IEvent< 'del, 'a>) =
    let event = new Event<_>()
    let ok = ref true
    sourceEvent.Add(fun args ->
    if ok then
    ok := predicate args
    else
    event.Trigger args)
    event.Publish

    Cesar

  • http://codebetter.com/members/Matthew.Podwysocki/default.aspx Matthew.Podwysocki

    @Paks

    Yes, you could implement a whole set of combinators using that same approach including:

    – take
    – takeWhile
    – skip
    – skipWhile

    I have all of those included here:
    http://gist.github.com/211922

    Matt

  • http://codebetter.com/members/Matthew.Podwysocki/default.aspx Matthew.Podwysocki

    @Paks

    The reason for not using Event.create is that it may be deprecated in the future in favor of the more explicit implementation of new Event<_>().

    As for unsubscribing like the way that the Reactive Framework does it, no I haven’t. It’s not worth my effort when I could just as easily fold in Rx instead of F# First Class Events.

    Matt

  • http://codebetter.com/members/Paks/default.aspx Paks

    Using the same technique used for “until”, we can implement “take” like this:

    module Event =
    let take (count: int) (source: IEvent< 'del,'T>) =
    let remaining = ref count
    let fire,evt = Event.create()
    source |> Event.listen(fun args -> if !remaining > 0 then decr remaining; fire(args))
    evt

    Again not being able to unsubscribe from the source once the count reaches 0 is a drag :(

  • http://codebetter.com/members/Paks/default.aspx Paks

    I got the idea of using concat to implement bind after watching the presentation Erik Meijer and Wes Dyer did on Channel 9 about the Rx Framework. There Erik talke about the implementation of SelectMany and Why it was very easy to implement if you implemented concat first. That video is a must if you want to learn about the internals of the Rx Framework.

    Now, Erik also talks about two ways one can implement concat. One is like the one you implemented here. The other one forgets about older event streams once events for a new stream start to fire. Have you thought about how to implement that one on F#?

    Another question:
    I see that you prefer to use “new Event<>” instead of “Event.create”. Why is that?

    I know there is no difference since Event.create is implemented like this:
    let create< 'T>() =
    let ev = new Event< 'T>()
    ev.Trigger, ev.Publish

    But I still wonder why you chose to create the events explicitly.

    Nice post :)

    Note: I also expended some time trying to understand what Monadic “return” means for Events. My head spinned a lot thinking about that one. :)