Wednesday, October 21, 2009

Functional Programming in VB.NET

After a two-year streak programming in Java at work, I am back to doing some .NET (VB.NET 3.5 to be precise.)

I don't know if .NET has changed that much since I last used it (Version 2.0), but I've changed by being exposed to functional programming while dabbling in Scala and other languages.

I was pleasantly surprised then to find out about what are (for me at least) typical fp style collection functions like filter, any, etc.
Not only that, but anonymous functions too 8)

It's true that VB.NET is on the verbose side, but in the following example (taken from real code), the variable type is inferred at compile time (or even intellisense time).
I think the anonymous function syntax is quite readable.

'Test if no changes have been made to any option

Dim optionLines As List(Of OptionLine) = GetOptionLines()

If optionLines.All(Function(anOption) anOption.Change = SomeEnum.ChangeType.Nothing) Then
'Display message "No changes have been made"
End If

My option list is usually quite small, but I could use "Any" instead to optimize getting out of the test earlier when changes HAVE been made.

If Not optionLines.Any(Function(anOption) anOption.Change <> SomeEnum.ChangeType.Nothing) Then
'Display message "No changes have been made"
End If

The following is an example of filter, which is called FindAll for types List(Of T).
Notice that the "FindAll" function returns a collection of the right type, in that case List(Of ClientLine), without having to be cast.

'Gets the new clients to add to the database

Dim clientLines As List(Of ClientLine) = GetClientLinesFromForm()

Dim newClients As List(Of ClientLine) = clientLines.FindAll(Function(aClient) aClient.Selected AndAlso (Not aClient.ExistsInDatabase))

Hopefully these small snippets will intrigue my coworkers and nudge them towards a more functional programming style.

And for those of you who already knew that n00b stuff, spread the word 8)

Saturday, January 24, 2009

pairMap revisited

A while ago, I needed a list function similar to a fold, but I wanted to operate always with the current and previous element instead of accumulating a result to operate with the current element (and return a list of the results of each pair operation)

I originally wrote it more or less like this:

def pairMap[A,B](previous:A, aList:List[A], f: (A, A) => B): List[B] = aList match {
case Nil => Nil
case head :: tail => f(previous, head)::pairMap(head, tail, f)

I was using it in the context of getting a list of gaps between the numbers of a list:

def getGapList(aList: List[int]) = pairMap(aList.head, aList.tail, (a:Int, b:Int)=>(b - a))

Usage example:

val list = List(2, 5, 9)
list: List[Int] = List(2, 5, 9)

res1: List[Int] = List(3, 4)

The other day, reminiscing about the Fibonacci example in "A Gentle Introduction to Haskell Version 98", a different implementation occurred to me. Unsurprisingly, it involves zipping a list with itself 8)

Thinking about folds, I thought I might as well put an initial value.

def pairMapWithInitial[A,B](initial:A, aList:List[A], f: (Tuple2[A, A]) => B):List[B] = {
initial::aList zip aList map f

def getGapListWithInitial(initial:int, aList:List[int]) = pairMapWithInitial(initial, aList, (a:Tuple2[Int,Int])=>(a._2 - a._1))

Usage example:

getGapListWithInitial(list.head, list.tail)
res2: List[Int] = List(3, 4)

getGapListWithInitial(0, list)
res3: List[Int] = List(2, 3, 4)

Because it's clearer to me, I still prefer the first version with "match", but it was a nice exercise to explore the zip version.

Post update
A similar version can be written using the List.map2 function which is pretty similar to a zip and map except the function takes two arguments instead of a tuple.

def pairMapWithInitial[A,B](initial:A, aList:List[A], f: (A, A) => B): List[B] = {
List.map2(initial::aList, aList) (f)

def getGapListWithInitial(initial:int, aList:List[int]) = pairMapWithInitial(initial, aList, (a:Int, b:Int)=>(b - a))