Adventures in F# - F# 101 Part 8 (Mutables and Reference Cells)
Where We Are
Before we begin today, let's catch up to where we are today:
- Part 1 - Basic functional programming
- Part 2 - Currying and Tuples
- Part 3 - Scope, Recursion and Anonymous Functions
- Part 4 - History of F#, Operators and Lists
- Part 5 - Pattern Matching
- Part 6 - Lazy Evaluation
- Part 7 - Creating Types
Learning F# ala Ted Neward?
Ted Neward recently announced on DotNetRocks Episode 332 that he's in the process of creating a class for F# for Pluralsight. That should be interesting to those who are interested in this series, as well as F# in general. Right now the community is rather small, so efforts like this should be rather rewarding I would hope. Ted's a pretty brilliant guy, so I'd imagine only the best. I'm hoping more details come out soon.
Pattern Matching in C#
Part of this series is intended to bring such concepts as Pattern Matching, Currying and other Functional Programming concepts to the C# developer. After all, the more C# language evolves, the more it seems to fall into the Functional Programming category. In previous posts, I showed how to relate currying to C# and it was less elegant than F# to say the least.
But, let's look at Pattern Matching. Bart De Smet has been posting recently on his blog about bringing the beauty of pattern matching to C#. So far it's been a good six posts into it and I urge you to go ahead and take a look at this series.
- Pattern Matching in C# - Part 0
- Pattern Matching in C# - Part 1
- Pattern Matching in C# - Part 2
- Pattern Matching in C# - Part 3
- Pattern Matching in C# - Part 4
- Pattern Matching in C# - Part 5
- Pattern Matching in C# - Part 6
- Pattern Matching in C# - Part 7
Imperative Programming in F#
This section I'll lay out some of the basics of imperative style programming before I get into the full object oriented approach to programming. So, we'll cover just a few topics and then I'll feel comfortable moving onto the real parts of creating classes and such. We'll cover such things as void types and mutability in this section.
The unit Type
One of the first things I forgot to mention when describing F# functions and values in the unit type. Think of this as the void type in C# that you are used to. It's the type that doesn't accept or return a value. First, let's look at the typical C# program with the void type for Hello World.
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Hello World");
}
}
Now, let's go ahead and look at it from the F# perspective.
#light
let main() =
printfn "Hello World"
main()
As you will see when you hover over our code is that it is a unit type. That in itself isn't all that interesting. But, what we'll run into is problems when functions return a value, but we're not all that interested in them. What happens? Well, F# will complain that your return value isn't compatible with the unit type, which is essentially true. So, how do you get around that? Let's walk through a simple unit test of a Stack written in F# and unit testing with the xUnit.net framework.
#light
#R @"D:\Tools\xunit-build-1252\xunit.dll"
open System
open System.Collections.Generic
open Xunit
type Stack<'t> = class
val elements : LinkedList<'t>
new() = { elements = new LinkedList<'t>() }
member x.IsEmpty
with get() = x.elements.Count = 0
member x.Push element =
x.elements.AddFirst(element:'t)
member x.Top
with get() =
if x.elements.Count = 0 then
raise (InvalidOperationException("cannot top an empty stack"))
x.elements.First.Value
member x.Pop() =
let top = x.Top
x.elements.RemoveFirst()
top
end
[<Fact>]
let PopEmpty () =
let stack = new Stack<string>()
Assert.Throws<InvalidOperationException>(fun () -> stack.Pop() |> ignore )
The real interesting part you should pay attention to is the last line. As you can see, I am using the forward operator to indicate that I really don't care what the function returns, just that I'm interested in that it executes. This is most likely during such functions that have some sort of side effect to them. I could also use the ignore function instead of the forward operator such as this:
[<Fact>]
let PopEmpty () =
let stack = new Stack<string>()
Assert.Throws<InvalidOperationException>(fun () -> ignore(stack.Pop()) )
This is very helpful in these cases where we really don't care about the return value, instead want to mutate the state of our given object, such as removing a value from a collection and so on.
Mutables
As I said in many posts before, by default all "variables" by which I mean values in F# are immutable. This is a standard in functional programming and all in the ML family. You can easily redefine a value by using the let keyword, but not actually mutate its state. But, since F# is a multi-purpose language on the .NET platform, mutable state can be had. To take advantage of this, mark your value as mutable. Then to change the value, just use the <- operator to reassign the value. Below is a simple example of this:
#light
let mutable answer = 42
printfn "Answer is %i" answer
answer <- 8
printfn "Answer is %i" answer
A key difference from the reassignment is that you cannot change the value type. Whereas I can redefine answer by keep using the let keyword, I can only keep my answer in this above example of the int type.
This can also apply to record types as well where you can change the fields. In the last installment, we talked about record types. Well, by default there as well, the fields for the record type are immutable. But, as with before, that can be changed. I of course like to caution people that mutable state takes a lot of the value proposition away from the side effect free programming that you gain with F# by default. But, nevertheless, you can still do it as noted below:
#light
type Person = { FirstName : string; mutable LastName : string; mutable IsMarried : bool }
let friend = { FirstName = "Courtney"; LastName = "Cox"; IsMarried = false }
friend.LastName <- "Cox-Arquette"
friend.IsMarried <- true
What I was able to do was define a Person record and change a couple of fields while using the <- operator and defining the fields as mutable. Yes, I could have used some scientific calculation or something, but this was easy.
Reference Cells
The last thing I want to touch on in this post is reference cells. You can think of these much as pointers in other languages or reference types. These of course can be of any type. The idea behind using these is to make updating fields as easy as possible. As with mutable fields, you cannot change the type once it has been assigned. To use these, you need to remember three basic operators
- ref - Allocates a reference cell
- := - Mutates a reference cell
- ! - Reads the reference cell
#light
let x = ref 2
x := !x + 25
printfn "%i" !x
What the code example above lets me do is define a reference to the number 2. Then I can change that reference by reading the current x value and adding 25. Then I mutate the existing x value with the result.
Conclusion
This is just meant to be a brief overview to some imperative programming constructs that you might see in .NET, Java, C, C++ and so on. F# is a first class language all the way with constructs that support these things as well as your normal functional programming constructs. I hope we get to cover some of this at ALT.NET Open Spaces, Seattle at some point because I'm sure a lot of people will be interested. Until next time...