While exploring
F#, I've grown increasingly impressed by the libraries
that ship with it. One of the main purposes of the libraries is to provide underlying
support for the language itself. In addition, they contain important modules and
classes necessary for functional programming (e.g. immutable List and Map
types). However, the most practical aspect of these libraries to me is the rich
set of APIs that facilitate using the .NET Framework in a more
functional way. These APIs are often directly portable to C#. Let's look
at a simple example.
The following C# code is typical of how we might create an array containing
the natural numbers from 1 to 20:
int[] a = new int[20];
for (int x = 0; x < a.Length; x++)
a[x] = x + 1;
There's nothing special about that code. It's representative of the sort of
thing that we write all the time. However, it won't fly in the functional
world because it's written in an
imperative style. That is,
the code specifies the exact steps that should be taken to create and
initialize the array:
- Create a new int array of 20 elements.
- Initialize a new indexer variable, x, to 0.
- Check to see that x is less than the length of the array. If it isn't,
STOP.
- Assign the value of the array element at index x to the result of x + 1.
- Increment x.
- GO BACK to step 3. Repeat as necessary.
In contrast, the F# libraries provide a special module, Array, for
manipulating single-dimensional .NET arrays in a more
functional
style. (Array2
and Array3 are also available for manipulating two- and three-dimensional arrays
respectively.) Using the Array module, the C# code above could be translated to
F# like so:
let a = Array.init 20 (fun x -> x + 1)
Instead of a specific code recipe, this F# code says (in a more
declarative fashion), "create an array of 20 elements, and use this function to
initialize each element." An interesting feature of the F# version is that the
type of the array is never declared. Because the compiler can infer that the result
of the passed function (fun x -> x + 1) will be an int, "a" must be an int array.
To me, this code is beautiful. In addition, it is declarative instead of
imperative; it describes what should be done but doesn't dictate
exactly how it should be done. When I see such elegant code, I
immediately start trying to figure out which of its aspects could be used to improve the
code in my daily C# work. Here's how we might "borrow" the F# "Array.init" function in C#:
public static class ArrayEx
{
public delegate T CreateItem<T>(int index);
public static T[] Create<T>(int length, CreateItem<T> createItem)
{
if (length < 0)
throw new ArgumentOutOfRangeException("length");
if (length == 0)
return new T[0];
T[] result = new T[length];
if (createItem != null)
{
for (int i = 0; i < length; i++)
result[i] = createItem(i);
}
return result;
}
}
With this function defined, we can rewrite our array creation sample
declaratively using C# 3.0 syntax.
var a = ArrayEx.Create(20, x => x + 1);
Notice that this code takes advantage of the C# compiler's
type inference in the same
way that the F# sample does. Sweet!
Let's take a look at another example. Suppose we want to iterate through
all of the elements in our int array and output each element's value to the console. We have a
few of options available to us. First, there's the familiar for-loop approach:
for (int x = 0; x < a.Length; x++)
Console.WriteLine(a[x]);
Second, there's the more declarative foreach-loop:
foreach (int val in a)
Console.WriteLine(val);
Finally, the underused "Array.ForEach" BCL method
is also a possibility:
Array.ForEach(a, val => Console.WriteLine(val));
In addition, because "Console.WriteLine" has an overload which
accepts a single int parameter, we can rewrite the previous code without a lambda expression:
Array.ForEach(a, Console.WriteLine);
Now, for the monkey wrench. Suppose we want to print the index of each element in the array along
with the value. With this added requirement, the for-loop is our most attractive
choice
because the indexer variable is already built in. The other two options would require
awkwardly creating an indexer variable and explicitly incrementing it. This
additional code
looks especially ugly with the "Array.ForEach" option.
int x = 0;
Array.ForEach(a, val => Console.WriteLine("{0}: {1}", x++, val));
Nasty.
How might we handle this in F#? Simple. F# provides an API designed to
iterate an array with an index.
Array.iteri (fun x value -> printfn "%i: %i" x value) a
Like the BCL's "Array.ForEach" method, F#'s "Array.iteri" iterates
through an array and applies the given function
to each element. The difference is that the
function to be applied includes an additional parameter representing the
element's index in the array.
NeRd Note
Curious about why the
parameter ordering of the F# "Array.iteri" API places the function to be
applied before the array to be iterated? Isn't that backwards? Wouldn't
it make more sense to move the array parameter to the first position? Nope.
The
parameter ordering is intentional.
Unless specified, F# functions are implicitly
curried. Hence, parameters are
usually ordered to take advantage of
partial application. If the parameters
of "Array.iteri" were reordered, we could not easily use partial application to
build useful functions from it.
let print = Array.iteri (fun x value -> printfn "%i: %i" x value)
print a
Besides, if passing "a" as the last parameter
is awkward, we can always pass it with the F# pipeline operator.
a |> Array.iteri (fun x value -> printfn "%i: %i" x value)
Make sense? OK. Take a deep breath...
Using F#'s "Array.iteri" as a model, we can define an equivalent function in
C#.
public static class ArrayEx
{
public delegate void IndexedAction<T>(int index, T item);
public static void Iterate<T>(T[] array, IndexedAction<T> action)
{
if (array == null)
throw new ArgumentNullException("array");
if (action == null)
throw new ArgumentNullException("action");
if (array.Length <= 0)
return;
int lower = array.GetLowerBound(0);
int upper = array.GetUpperBound(0);
for (int i = lower; i <= upper; i++)
action(i, array[i]);
}
}
Now we can iterate our array and output the index and value of each element
to the console with one line of code!
ArrayEx.Iterate(a, (x, i) => Console.WriteLine("{0}: {1}", x, i));
Since we're using C# 3.0, we can declare "ArrayEx.Iterate"
as an extension method to make the client code more
readable.
a.Iterate((x, i) => Console.WriteLine("{0}: {1}", x, i));
In conclusion, using F# as a source of inspiration, it's easy to create APIs
that enable more declarative C# code to be written. Do you have a cool
declarative API that you've written for C# or VB? If so, I'd love to hear about
it. Feel free to post your creations in the comments or email me directly.