Tuesday, September 25, 2007

Functional Programming Patterns

If you're new to functional programming (like me), you'll quickly find a number of useful patterns that you can apply to your everyday coding tasks. Take the following task as an example: we have a FeatureCursor and we would like to repeat a certain action for every Feature in the Cursor. In C#, it would look something like this:
IFeature feature = cursor.NextFeature();
while (feature != null)
{
// Do something with the feature
Console.WriteLine(feature.OID);
feature = cursor.NextFeature();
}


This is a common pattern in ArcObjects. How can we express this pattern in F# while allowing for flexibility in the action that we wish to perform?

let forAll (f : IFeature -> unit) (cursor : IFeatureCursor) =
let mutable feature = cursor.NextFeature()
while feature <> null do
// Do something with the feature
f feature
feature <- cursor.NextFeature()


We can pass any function that we want to so long as it takes an IFeature and returns unit:
forAll (fun feature -> Console.WriteLine(feature.OID)) cursor

You could write a ForAll function in C# but it just wouldn't feel as natural, would it?

2 comments:

Eric said...

An alternative approach is to build a sequence using the feature cursor, and then call Seq.iter or Seq.map to do what you want.

In code:

// One possible way to turn your IFeatureCursor into a sequence.
let seq_of_featurecursor (cursor : IFeatureCursor) =
let feature = ref (cursor.NextFeature())
seq { while (!feature) <> null do
yield feature
do feature := cursor.NextFeature() }

seq_of_featurecursor cursor
|> Seq.iter (fun feature -> Console.WriteLine (feature.OID))

The advantage of this is that your IFeatureCursor is now a seq, and you can use any function from the Seq module.

Ray Vernagus said...

That's very cool, eric, thanks!