Sunday, 14. February 2010
Feb 14
Last week I released version 0.29 of my build automation tool “FAKE – F# Make”. The new version comes along with a couple of changes which I will now describe.
F# February 2010 CTP and .NET 4.0 RC
“FAKE – F# Make” should be completely compatible with both, the F# February 2010 CTP and the F# version which is included in Visual Studio 2010 RC.
FAKE self build and binaries on teamcity.codebetter.com
Since “FAKE – F# Make” is a build automation tool, it was always used for it’s own build process. Now this build process could be moved to an open CI server at teamcity.codebetter.com. If you login as a guest you can download the latest “FAKE – F# Make” binaries from there.
FAKE on build servers without F#
With the new F# CTP there is no longer a need for installing F# on the build agents. In fact FAKE itself was built on build agents which don’t have a F# installation.
If you want to create such build scripts you have to do the following:
- Download the standalone zip file of the F# CTP
- Put the bin subfolder into your project tree
- Modify the FSIPath value in the FAKE.exe.config file to match your FSharp bin folder
- If you copy the contents the F# bin folder into ./tools/FSharp/ it should just work.
If you have F# projects you also need to modify your .fsproj files like this:
<PropertyGroup>
….
<FscToolPath>..\..\..\tools\FSharp\</FscToolPath>
</PropertyGroup>
…
<Import Project="..\..\..\tools\FSharp\Microsoft.FSharp.Targets" />
This modifications should take care that MSBuild will use the F# compiler from your tools paths.
Generate your documentations with “docu”
“What’s a docu? A documentation generator for .Net that isn’t complicated, awkward, or difficult to use. Given an assembly and the XML that’s generated by Visual Studio, docu can produce an entire website of documentation with a single command.” [docu Homepage]
“FAKE – F# Make” 0.29 is bundled with this new documentation tool which can easily convert your xml-Documentation into some nice html pages. You can use the tool with the new Docu task like this:
Target? GenerateDocumentation <-
fun _ ->
Docu (fun p ->
{p with
ToolPath = @".\tools\FAKE\docu.exe"
TemplatesPath = @".\tools\FAKE\templates"
OutputPath = docDir })
(buildDir + "MyAssembly.dll")
You will also need the docu templates, which you can download from the product homepage. I’m planning to bundle some basic templates with the next version of FAKE.
What’s next?
At the moment I’m working on ILMerge task for FAKE. I hope to release this with the next version. There are also some open issues with the Mono support but since teamcity.codebetter.com is getting a mono build agent I hope to make some progress here too.
If you have any questions or ideas for new features please contact me.
Tags:
Continuous Integration,
F#,
F-sharp Make
Monday, 8. February 2010
Feb 08
The new version 0.27 of “FAKE – F# Make” comes with new syntactic sugar for build targets and build dependencies. Don’t be afraid the old version is still supported – all scripts should still work with the new version.
The problem
Consider the following target definition:
let buildDir = "./build/"
Target "Clean" (fun _ ->
CleanDir buildDir
)
Target "Default" (fun _ ->
trace "Hello World from FAKE"
)
"Default" <== ["Clean"]
run "Default"
As you can see we are having a lot of “magic strings” for the target names and the dependency definitions. This was always a small shortcoming in FAKE, since this doesn’t allow refactoring and may result in runtime errors.
One of my goals for “FAKE – F# Make” is to remove these strings in future versions. Unfortunately this is not that easy, because it causes a lot of internal issues. In particular logging to the build server is much harder if you don’t have a target name.
The first step
As posted in a bitbucket comment by cipher we could use the “dynamic lookup operator” to remove some of the magic strings without breaking any internal code.
As a result we can rewrite the above sample as:
let buildDir = "./build/"
Target? Clean <-
fun _ -> CleanDir buildDir
Target? Default <-
fun _ -> trace "Hello World from FAKE"
For? Default <- Dependency? Clean
Run? Default
All magic strings suddenly disappeared. I think this syntax looks really nice, but unfortunately the strings are not really gone, since the token Default is only checked at runtime.
The idea for future versions
Since the new syntax is really just syntactic sugar I’m always interested in a better solution. Currently I’m working on a syntax using monads. The result could look like this:
let buildDir = "./build/"
let Clean = target { CleanDir buildDir }
let Default =
target {
trace "Hello World from FAKE"
trace "Another line"
}
Default <== [Clean]
This way the magic string are really gone, but my current problem is retrieving the target name from the let-binding name. Please leave a comment if you have an idea to solve this issue.
Tags:
F#,
F-sharp Make,
Fake
Monday, 11. January 2010
Jan 11
Der Termin für meinen F#-Talk bei der .NET Usergroup Frankfurt hat sich auf nächste Woche Donnerstag (21.01.2010) 18:30 verschoben.
Veranstaltungsort ist die Geschäftsstelle von Microsoft in Bad Homburg, Siemensstrasse (Anfahrtsbeschreibung).
Bitte beachten Sie, dass für den Besuch dieses User Group Meetings eine Anmeldung auf der Web Seite der .NET User Group zwingend notwendig ist.
Abstract:
Funktionale Programmiersprachen nehmen seit geraumer Zeit einen hohen Stellenwert in der Wissenschaft ein. Demnächst könnte es eine dieser Sprachen sogar aus dem Forschungsbereich direkt in den Mainstream schaffen. Visual Studio 2010 wird neben C# und VB.NET die funktionale Programmiersprache F# als dritte Hauptsprache anbieten. Der Vortrag soll einen Einblick in funktionale Konzepte und deren Umsetzung in F# geben. Insbesondere soll auf “Funktionen höherer Ordnung”, Typinferenz, Currying, Pattern Matching, “Unveränderlichkeit” und parallele Programmierung eingegangen werden.
Tags:
.NET Usergroup Frankfurt,
F#,
Funktionale Programmierung
Monday, 21. December 2009
Dec 21
In one of my lasts posts I showed how we can transform some of the operators from the Reactive Framework for an easier use in F#. This time I will demonstrate how we can use this API and asynchronous workflows to download a couple of websites asynchronous and in parallel.
First of all we create a synchronous download function:
let SyncHttp (url:string) =
let request = WebRequest.Create url
let response = request.GetResponse()
use stream = response.GetResponseStream()
use reader = new StreamReader(stream)
let result = reader.ReadToEnd()
url,result
In F# we can easily make this function asynchronously:
let AsyncHttp (url:string) =
async { // using asynchronous workflows
let request = WebRequest.Create url
// async call of GetResponse
let! response = request.AsyncGetResponse()
use stream = response.GetResponseStream()
use reader = new StreamReader(stream)
// async call of ReadToEnd
let! result = reader.AsyncReadToEnd()
return url,result}
Now we use this AsyncHttp function to create a list of async downloads:
/// Async<string * string> list
let downloads =
["http://www.google.com";
"http://www.twitter.com";
"http://www.nytimes.com/";
"http://www.navision-blog.de/";
"http://www.nba.com/"]
|> List.map AsyncHttp
The next step is to convert the list of async calls into a list of observables and to merge this list into a single IObservable. The effect is that whenever one download is completed we will be notified about the result:
/// IObservable<string * string>
let observableDownloads =
downloads
|> Seq.map Observable.ofAsync
|> Observable.merge
observableDownloads
|> Observable.subscribe (fun (url,result) ->
printfn "%A: %d" url result.Length)
If you want to learn more about Observable.merge and see the marble diagram you should watch this video.
Tags:
F#,
Reactive Framework,
Reactive Programming
Saturday, 12. December 2009
Dec 12
Today I had way too much time on the train
, so I wrote a little functional christmas tree program:
let line width j =
List.init
width
(fun i -> if abs(width/2 – i) <= j then "*" else " ")
let tree n =
List.init (n/2) (line n) @ // treetop
List.init 2 (fun _ -> line n 0) // trunk
let printTree =
tree >> Seq.iter (Seq.fold (+) "" >> printfn "%s")
printTree 11
*
***
*****
*******
*********
*
*
Tags:
F#,
Functional Programming
Sunday, 8. November 2009
Nov 08
In my last article (Introducing NaturalSpec – A Domain-specific language (DSL) for testing) I used NaturalSpec in two small samples. This time I will show how we can set up a NaturalSpec environment to write our first automatically testable scenarios.
1. Choosing an IDE
The first step is to choose an integrated development environment for NaturalSpec. At the current project status you should be able to use NaturalSpec with Visual Studio 2008, Visual Studio 2010 beta 2, the freely available Visual Studio 2008 Shell or the free IDE SharpDevelop 3.0.
2. Installing the testing framework
As NaturalSpec uses NUnit as the underlying testing framework we have to install NUnit 2.5. I also recommend installing TestDriven.Net in order to get a Unit Test runner within Visual Studio.
3. Installing F#
NaturalSpec is completely written in F# and all specs will also be written in F#. This doesn’t imply you have to learn programming in F# but we need the F# compiler to get things working. You can download the F# October 2009 CTP from the Microsoft F# Developer Center.
4. Downloading the latest version of NaturalSpec
You can download a .zip with the latest NaturalSpec libraries from GoogleCode.
5. Creating a spec
This part is written for using Visual Studio 2008. If you use SharpDevelop or Visual Studio 2008 Shell this might differ in some detail.
Start Visual Studio 2008 and create a new F# class library.

Rename Module1.fs in ListSpec.fs and delete script.fsx from the project:

Create a folder “Lib” and unzip the NaturalSpec libraries into it.
Add NaturalSpec.dll and nunit.framework.dll as references to your project:

Copy the following code into ListSpec.fs:
module ListSpec
open NaturalSpec
[<Scenario>]
let When_removing_an_3_from_a_small_list_it_should_not_contain_3() =
Given [1;2;3;4;5]
|> When removing 3
|> It shouldn't contain 3
|> Verify
If you have TestDriven.Net installed you can run your spec via right click in the solution explorer:

If you don’t like the TestDriven.Net test runner you might want to use the NUnit GUI runner. The output should look like:

In addition the test runner should produce a Spec output file with the name “Spec.txt” within the same folder.
Summary
In a minimal environment you need SharpDevelop, the F# compiler, NUnit and the NaturalSpec libraries for using NaturalSpec.
In the next post I will show how you can use NaturalSpec to create a spec for C# projects.
Tags:
BDD,
F#,
NaturalSpec,
nunit,
TDD,
Visual Studio
Friday, 6. November 2009
Nov 06
I recently had the problem to register a global hotkey, but my “old” Win32-API calls didn’t work with WPF. I looked around the web and found the “Managed Windows API”, but I didn’t want to add another external dependency to my project, so I extracted the core functions for registering hotkeys and condensed the code to a new version.
As the original “Managed Windows API” is licensed by the GNU Lesser General Public License (LGPL) I want to provide my modifications here.
First we need a Window which can dispatch the window messages to our event handlers:
/// <summary>
/// A Win32 native window that delegates window messages to
/// handlers. So several
/// components can use the same native window to save
/// "USER resources". This class
/// is useful when writing your own components.
/// </summary>
public sealed class EventDispatchingNativeWindow : NativeWindow
{
private static readonly Object MyLock = new Object();
private static EventDispatchingNativeWindow _instance;
/// <summary>
/// Create your own event dispatching window.
/// </summary>
public EventDispatchingNativeWindow()
{
CreateHandle(new CreateParams());
}
/// <summary>
/// A global instance which can be used by components
/// that do not need their own window.
/// </summary>
public static EventDispatchingNativeWindow Instance
{
get
{
lock (MyLock)
{
return
_instance ??
(_instance =
new EventDispatchingNativeWindow());
}
}
}
/// <summary>
/// Attach your event handlers here.
/// </summary>
public event WndProcEventHandler EventHandler;
/// <summary>
/// Parse messages passed to this window and send
/// them to the event handlers.
/// </summary>
/// <param name="m">A System.Windows.Forms.Message
/// that is associated with the
/// current Windows message.</param>
protected override void WndProc(ref Message m)
{
bool handled = false;
if (EventHandler != null)
EventHandler(ref m, ref handled);
if (!handled)
base.WndProc(ref m);
}
}
Now we can write our global hotkey handler class:
/// <summary>
/// Specifies a class that creates a global keyboard hotkey.
/// </summary>
public class GlobalHotkey
{
private static readonly Object MyStaticLock = new Object();
private static int _hotkeyCounter = 0xA000;
private readonly int _hotkeyIndex;
private readonly IntPtr _hWnd;
/// <summary>
/// Initializes a new instance of this class.
/// </summary>
/// <param name="keys">The keys.</param>
/// <param name="ctrl">if <c>true</c> [CTRL].</param>
/// <param name="alt">if <c>true</c> [alt].</param>
/// <param name="shift">if <c>true</c> [shift].</param>
/// <param name="winKey">if <c>true</c> [win key].</param>
public GlobalHotkey(Keys keys, bool ctrl,
bool alt, bool shift, bool winKey)
{
KeyCode = keys;
Ctrl = ctrl;
Alt = alt;
Shift = shift;
WindowsKey = winKey;
EventDispatchingNativeWindow.Instance.EventHandler
+= NwEventHandler;
lock (MyStaticLock)
{
_hotkeyIndex = ++_hotkeyCounter;
}
_hWnd = EventDispatchingNativeWindow.Instance.Handle;
Enable();
}
/// <summary>
/// The key code of the hotkey.
/// </summary>
public Keys KeyCode { get; private set; }
/// <summary>
/// Whether the shortcut includes the Control modifier.
/// </summary>
public bool Ctrl { get; private set; }
/// <summary>
/// Whether this shortcut includes the Alt modifier.
/// </summary>
public bool Alt { get; private set; }
/// <summary>
/// Whether this shortcut includes the shift modifier.
/// </summary>
public bool Shift { get; private set; }
/// <summary>
/// Whether this shortcut includes the Windows key modifier.
/// </summary>
public bool WindowsKey { get; private set; }
~GlobalHotkey()
{
Disable();
EventDispatchingNativeWindow.Instance.EventHandler
-= NwEventHandler;
}
/// <summary>
/// Enables the hotkey. When the hotkey is enabled,
/// pressing it causes a
/// <c>HotkeyPressed</c> event instead of being
/// handled by the active application.
/// </summary>
private void Enable()
{
// register hotkey
int fsModifiers = 0;
if (Shift) fsModifiers += ModShift;
if (Ctrl) fsModifiers += ModControl;
if (Alt) fsModifiers += ModAlt;
if (WindowsKey) fsModifiers += ModWin;
bool success =
RegisterHotKey(_hWnd, _hotkeyIndex,
fsModifiers, (int) KeyCode);
if (!success)
throw new
Exception(
"Could not register hotkey (already in use).");
}
/// <summary>
/// Disables this instance.
/// </summary>
private void Disable()
{
// unregister hotkey
UnregisterHotKey(_hWnd, _hotkeyIndex);
}
/// <summary>
/// Occurs when the hotkey is pressed.
/// </summary>
public event EventHandler HotkeyPressed;
private void NwEventHandler(ref Message m, ref bool handled)
{
if (handled) return;
if (m.Msg != WmHotkey ||
m.WParam.ToInt32() != _hotkeyIndex)
return;
if (HotkeyPressed != null)
HotkeyPressed(this, EventArgs.Empty);
handled = true;
}
#region PInvoke Declarations
private const int ModAlt = 0×0001;
private const int ModControl = 0×0002;
private const int ModShift = 0×0004;
private const int ModWin = 0×0008;
private const int WmHotkey = 0×0312;
[DllImport("user32.dll", SetLastError = true)]
private static extern bool RegisterHotKey(IntPtr hWnd,
int id, int fsModifiers, int vlc);
[DllImport("user32.dll", SetLastError = true)]
private static extern bool UnregisterHotKey(IntPtr hWnd,
int id);
#endregion
}
Now we can easily register a global hotkey or use it as an observable in F#:
/// system-wide keyboard hook
let hotkey = new GlobalHotkey(Keys.Q,true,false,false,false)
let hookObserver =
hotkey.HotkeyPressed
|> Observable.subscribe (fun _ -> printfn "Hotkey pressed")
Tags:
C#,
F#,
Hotkey,
PInvoke,
win32
Friday, 23. October 2009
Oct 23
Currently I’m trying to implement some of the standard monads in F#. If you want to read about the theory behind monads and their implementation (in Haskell) it’s a good start to look into “All about Monads” on haskell.org.
In this blog post series I don’t care about mathematical details. Instead I will try to show how monads can help to simplify our code.
Motivation
We have a generic binary tree with some test data:
type Tree<’a> =
| Leaf of ‘a
| Branch of Tree<’a> * Tree<’a>
let tree =
Branch(
Leaf "Max",
Branch(
Leaf "Bernd",
Branch(
Branch(
Leaf "Holger",
Leaf "Ralf"),
Branch(
Leaf "Kerstin",
Leaf "Steffen"))))
If we want to print this tree we can use the following recursive function:
/// prints a binary tree
let printTree t =
let rec print t level =
let indent = new String(‘ ‘, level * 2)
match t with
| Leaf l -> printfn "%sLeaf: %A" indent l
| Branch (left,right) ->
printfn "%sBranch:" indent
print left (level+1)
print right (level+1)
print t 0
printfn "Unlabeled:"
printTree tree
And what we get is something like this:
Unlabeled:
Branch:
Leaf: "Max"
Branch:
Leaf: "Bernd"
Branch:
Branch:
Leaf: "Holger"
Leaf: "Ralf"
Branch:
Leaf: "Kerstin"
Leaf: "Steffen"
Labeling the tree with mutable state
Now we want to give every tree a unique label. This can be easily done by another recursive function:
let mutable label = -1
let rec labelTreeMS t =
match t with
| Leaf l ->
label <- label + 1 // changing the state
Leaf(l,label)
| Branch(oldL,oldR) ->
let newL = labelTreeMS oldL
let newR = labelTreeMS oldR
Branch(newL,newR)
let treeMS = labelTreeMS tree
printfn "Labeled (with global mutable state):"
printTree treeMS
And the output would look like this:
Labeled (with global mutable state):
Branch:
Leaf: ("Max", 0)
Branch:
Leaf: ("Bernd", 1)
Branch:
Branch:
Leaf: ("Holger", 2)
Leaf: ("Ralf", 3)
Branch:
Leaf: ("Kerstin", 4)
Leaf: ("Steffen", 5)
The only problem with labelTreeMS is that it uses global state, which is very bad because we can’t be sure if the mutable label variable is changed (from maybe another thread) or not.
Labeling the tree without global state
If we want to remove this side effect, we can pass the state directly into the function:
// non-monadic version
// passing the state around explicitly
let rec labelTreeNM t s =
match t with
| Leaf l -> s+1,Leaf(l,s) // changing the state
| Branch(oldL,oldR) ->
let stateL,newL =
labelTreeNM oldL s
let stateR,newR =
labelTreeNM oldR stateL // passing the state around
stateR,Branch(newL,newR)
let _,treeNM = labelTreeNM tree 0
printfn "Labeled (non-monadic):"
printTree treeNM
Labeling the tree by using the State Monad
With the help of the State Monad we get a very similar function:
/// labels a tree by using the state monad
/// (uses F#’s sugared syntax)
let rec labelTree t = state {
match t with
| Leaf l ->
let! s = getState
do! setState (s+1) // changing the state
return Leaf(l,s)
| Branch(oldL,oldR) ->
let! newL = labelTree oldL
let! newR = labelTree oldR
return Branch(newL,newR)}
printfn "Labeled (monadic):"
let treeM = Execute (labelTree tree) 0
printTree treeM
Thanks to the F# sugared syntax this labelTree and labelTreeMS are visually nearly the same. Every time we are dealing with state we use the exclamation mark. There is only one point (in the Leaf case) where have to use (and change) the state.
The nice thing is, that we can write the function like the first version, but we don’t have to perform the side effect on the shared state.
If we want to use the de-sugared version we have to write it like this:
/// labels a tree and uses de-sugared syntax
/// (implementation looks different to labelTreeNM)
let rec labelTreeDesugared t =
match t with
| Leaf l -> (fun s -> Leaf(l,s),(s+1))
| Branch(oldL,oldR) ->
labelTreeDesugared oldL >>=
(fun newL ->
labelTreeDesugared oldR >>=
(fun newR ->
Branch(newL,newR) |> returnS))
State monad implementation
In order to use the state monad, of course we have to implement it first. Here is my version, which allows to use the de-sugared and sugared version:
module StateMonad
let (>>=) x f =
(fun s0 ->
let a,s = x s0
f a s)
let returnS a = (fun s -> a, s)
type StateBuilder() =
member m.Bind(x, f) = x >>= f
member m.Return a = returnS a
let state = new StateBuilder()
let getState = (fun s -> s, s)
let setState s = (fun _ -> (),s)
let Execute m s = m s |> fst
If you want to learn more about the State Monad I recommend watching Brian Beckman’s Channel 9 video “The Zen of Stateless State – The State Monad".
Tags:
F#,
monad,
state monad
Thursday, 22. October 2009
Oct 22
In the last article I showed how to filter and combine events via the Reactive Framework and how to deal with errors. This time we will create our own observables.
I got the idea for this sample from a very good Expert to Expert video (“Reactive Framework (Rx) Under the Hood”) with Erik Meijer and Wes Dyer.
We want to implement an asynchronous dictionary lookup. Whenever sometimes types something into the Textbox, our application starts looking into a dictionary and searches for words starting with the given prefix.

Let’s start with generating this simple form:
open System.Windows.Forms
let form = new Form(Visible=true, Text="Async dict",
TopMost=true)
let textBox1 =
new TextBox(
Location = new System.Drawing.Point(12, 12),
Size = new System.Drawing.Size(260, 20))
form.Controls.Add textBox1
let resultsBox =
new ListBox(
Location = new System.Drawing.Point(13, 39),
Size = new System.Drawing.Size(259, 211))
form.Controls.Add resultsBox
// create a list with common words
// this might be very large
let data =
["hell"; "Hello"; "Halle"; "Html";
"Bonn"; "Bonjour"; "Steffen"]
// create observable for text changes
let textChanged =
textBox1.TextChanged
|> Observable.map (fun _ -> textBox1.Text)
Now we have to define a base class for observables. This class will help our dictionary lookup function to use the IObservable<T> interface:
module Observable
/// A Observable base class which notifies
/// all observers in parallel
type ‘a Observable() =
let mutable observers = []
/// Notifies all observers in parallel about the new value
let notifyObservers f =
observers
|> Seq.map (fun (observer:IObserver<’a>) –>
async { return f observer})
|> Async.Parallel
|> Async.RunSynchronously
|> ignore
interface IObservable<’a> with
member observable.Subscribe(observer) =
// subscribe observer
observers <- observer :: observers
// create Disposable to unsubscribe observer later
{new IDisposable with
member this.Dispose() =
observers <-
observers |> List.filter ((<>) observer)}
/// Notifies all observers in parallel about the new value
member observable.OnNext value =
notifyObservers (fun observer -> observer.OnNext value)
/// Notifies all observers in parallel about the error
/// and finishes all observations
member observable.OnError error =
notifyObservers (fun observer -> observer.OnError error)
observers <- []
/// Notifies all observers in parallel about the completion
/// and finishes all observations
member observable.Completed =
notifyObservers (fun observer -> observer.OnCompleted())
observers <- []
I hope there will be a similar base class in the .NET Framework 4.0 RTM.
Now we are able to use this class and to build our dictionary lookup observable:
let wordsObservable = new Observable.Observable<_>()
let findWords prefix =
if prefix <> "" then
let prefix’ = prefix.ToUpper()
for word in data do
if word.ToUpper().StartsWith(prefix’) then
wordsObservable.OnNext (prefix,word)
The last step is to create observers and subscribe them to the observables:
// create observers
let clean =
textChanged
|> Observable.subscribe (fun _ -> resultsBox.Items.Clear())
let searchForWords =
// Every time the text changes
// we start our wordsObservable to push words
textChanged
|> Observable.subscribe (fun text -> findWords text)
let wordFound =
// subscribe to the "word found"-event
wordsObservable
|> Observable.subscribe
(fun (_,word) -> resultsBox.Items.Add word |> ignore)
Tags:
F#,
IObservable,
Reactive Framework,
Reactive Programming
Tuesday, 20. October 2009
Oct 20
One of the nice new features in .NET 4.0 beta 2 is the IObservable<T>/IObserver<T> support from the Reactive Framework (“Rx Framework” or sometimes “LinqToEvents”). It is a really powerful way to use reactive programming in .NET and especially in F# developed by Erik Meijer and his team.
If you want to see some of the beautiful math behind the Reactive Framework you should definitely watch this Expert to Expert video on Channel 9. You can see Brian Beckman and Erik Meijer showing that IObservable<T> is the mathematical dual of IEnumerable<T>.
What can I do with the Rx Framework?
Consider this small sample (it is taken from Matthew Podwysocki’s blog): We want to get notified whenever a user clicks on our form and moves the mouse within a special area (XPos and YPos smaller than 100px).
First of all we define our observable by merging and filtering .NET events:
open System.Windows.Forms
let form = new Form(Visible=true, TopMost=true)
/// Creates two observables
/// – left is triggered when the left mouse button is down
and the mouse is in the area (x < 100 && y < 100)
/// – right is triggered when the right mouse button is down
and the mouse is in the area (x < 100 && y < 100)
let left,right =
form.MouseDown
|> Observable.merge form.MouseMove
|> Observable.filter (fun args ->
args.Button = MouseButtons.Left ||
args.Button = MouseButtons.Right)
|> Observable.map (fun args -> args.X, args.Y, args.Button)
|> Observable.filter (fun (x,y,b) -> x < 100 && y < 100)
|> Observable.partition (fun (_,_,button) -> button = MouseButtons.Left)
Now it’s easy to subscribe a function to this observable:
let leftSubscription =
left
|> Observable.subscribe
(fun (x,y,_) -> printfn "Left (%d,%d)" x y)
If we want to unsubscribe we only have to dispose the object:
// unsubscribe
leftSubscription.Dispose()
We couldn’t unsubscribe this way with “classic” .NET events. Remember the –= operator in C# doesn’t work with lambda expressions.
Exception handling
We have seen an easy way to subscribe and unsubscribe to complicated observables but what should we do if an error occurs? As far as I know this case is not implemented for F# at the moment, but we can easily add this functionality:
module Observable
/// Creates an observer with the given functions
let createObserver next error completed =
{new System.IObserver<_> with
member this.OnCompleted() = completed()
member this.OnError(e) = error e
member this.OnNext(args) = next args}
/// Subscribes an observer with the given functions
/// param1: OnNext (T -> unit)
/// param2: OnError (Exception -> unit)
/// param3: OnCompleted (unit -> unit)
/// param4: observable
let subscribeComplete next error completed (observable:System.IObservable<_>) =
createObserver next error completed
|> observable.Subscribe
Now we are able to create a complete IObserver<T> object and register the 3 functions:
let rightSubscription =
right
|> Observable.subscribeComplete
(fun (x,y,_) -> printfn "Right (%d,%d)" x y)
(fun error -> printfn "Error: %s" error.Message)
(fun () -> printfn "Ready.")
Tags:
F#,
Reactive Framework,
Reactive Programming