Sunday, September 4, 2011

A small correction: F# active patterns

In Professional F# 2.0, an example is given for using an active pattern to match against a struct. The example could be improved.

The original:

type Point(x : int, y : int) =
member pt.X = x
member pt.Y = y
override pt.ToString() =
System.String.Format("({0},{1})", x, y)

let newPoint = new Point(0,0)

let (|Point|) (x : int, y : int) (inPt : Point) =
inPt.X = x && inPt.Y = y

let message =
match newPoint with
| Point(0, 0) true -> "You're at the origin!"
| Point(12, 12) true -> "You're at 12,12!"
| _ -> "Who knows where you are?"

System.Console.WriteLine(message) // output: "You're at the origin!"

Here, the active recognizer Point takes two arguments: the desired x and desired y value. The output is a boolean, which is then matched against the pattern "true" in each case.

This would be slightly more succinct and far more flexible if the active recognizer didn't try to do comparisons, and simply broke down the Point into its components.

type Point( x : int, y: int) =
member pt.X = x
member pt.Y = y

let newPoint = Point(0,12)

let (|Point|) (inPt : Point) =
(inPt.X, inPt.Y)

let message = match newPoint with
| Point(0,0) -> "You are at the origin"
| Point(0,_) -> "You are on the y axis"
| Point(_,0) -> "You are on the x axis"
| Point(x,y) when x = y -> "You are on the line x = y"
| Point(x,y) -> "you are at (" + (string x) + "," + (string y) + ")"

printfn "%s" message // output: "You are on the y axis"

Here, the active recognizer has fewer arguments and returns the int*int tuple representation of a Point. This tuple is then matched against (0,0) or whatever location we care about.

This is more succinct because we don't have to put "true" at the end of each pattern. It is more flexible because we can use a wildcard (underscore) for either the X or Y property of the point. Even better, we can put a variable name in for either or both, and then that variable can be used in the guard clause ("when x = y") or the result expression.

For the record, I post this here at the suggestion of an author. Why submit an idea privately when people volunteer for public ridicule?

1 comment:

  1. The example is quoted from Chapter 7, page 119, section "Struts and Pattern Matching" in Professional F# 2.0.