F# values, functions and a little bit of both

Judging from a few questions on stackoverflow and hubFS, programmers new to F# sometimes confuse value assignments with functions that don’t take arguments. This confusion is easily straightened out. In fact, it’s so easily straightened out, that it’s not really enough for a blog post. Thus, we spice things up a bit by letting the value assignment assign a function value, and throw in closures and something about the practical differences between stack and heap values for good measure.

Values

Let’s start with the typical source of confusion; a value assignment that has a body.

let foo =
    printfn "running foo"
    42

// intended main program
printfn "calling foo"
let bar = foo

Coming from an imperative language, you might expect too see an output of “calling foo” followed by “running foo”. However, this will not happen, as you don’t define a function named “foo” and call it on the last line. What you actually do, is assign “foo” a value (42) and print “running foo” in the body of the assignment. The line “let bar = foo” doesn’t call foo, since there’s no function to call. It merely takes foo’s already assigned value of 42 and assigns it to bar.

The thing that tricks imperative programmers here, is that a value assignment can have a body, making it look very similar to a function. The assignment body runs once, and once only, just like any other assignment (e.g. a one-liner, like “let foo = 42″) would.

Functions

What sets a function apart from a value assignment, is the presence of arguments. If none are needed, unit, written “()”, is used as an empty argument. Add () to the foo assignment in the above example, and presto – it’s a function.

let foo () =
    printfn "running foo"
    42

// intended main program
printfn "calling foo"
let bar = foo ()

Running this code, will of course give you the expected result of seeing “calling foo” followed by “running foo”. Now that we all agree on what’s a function and what’s not, let’s move on to more interesting stuff.

A little bit of both

What if the value that’s assigned to foo in our first example, is a function? This is aptly called a function value. Note the difference between the foo value assignment and bar function definition below.

let foo =
    printfn "running foo"
    (fun () -> 42)

let bar () =
    printfn "running bar"
    42

// intended main program
printfn "adding foo and bar"
let baz = foo () + bar ()

As you can deduct from our first experiments, the very first output from the above code will be “running foo”, just like in our first test. However, if you enter the code in VS2010’s F# Interactive window (or fsi), and have a look at the type signatures of foo and bar, do you expect to see any difference between them? Frankly I didn’t, but there is a slight one:

val foo : (unit -> int)
val bar : unit -> int

This difference only tells you that foo is a function value and bar is a function. In practice, they’re both called the same way, but remember that “foo ()” only calls the function that foo is assigned to, and not foo’s assignment body.

Assigning a function value gives us the possibility of creating functions with initialization behaviour and local values that are remembered between calls. This introduces states, which we’d rather avoid in functional programming, but we’ll try it anyway for the sake of exploring F#. Let’s experiment with how we can use this, by defining a simple timing function that tells us how long a program has been running for:

let runningTime =
    let progStart = System.DateTime.Now
    (fun () -> System.DateTime.Now - progStart)

[0..100000] |> ignore // waste some time
printfn "Running for %A" (runningTime())

The runningTime assignment body saves the program’s start time in progStart, which we take a closure of in the lambda expression returned: “(fun () -> System.DateTime.Now – progStart)”. This looks awfully imperative, but it will look even more so when we add a closure of mutable local data.

Closed-in mutable local values

From the previous example, it seems obvious that a closure of a mutable local value, will enable us to keep and modify data between calls to our function value. This would mimic the functionality of local static variables in C and C++ (Java and C# don’t have them). To try this, we’ll define a function that tells us how much time has passed since the last time it was called. Merely making a local value mutable and closing over it (=making a closure of it) won’t do of course. Local values are stack values, and as such, they are destroyed when they go out of scope. If we try using one anyway, the F# compiler will be kind enough to serve us an error message that tells us exactly what to do.

let runningTimeDelta =
    let mutable lastVisitTime = System.DateTime.Now
    (fun () ->
        let delta = System.DateTime.Now - lastVisitTime
        lastVisitTime <- System.DateTime.Now
        delta)

Trying the above, will render the message “error FS0407: The mutable variable ‘lastVisitTime’ is used in an invalid way. Mutable variables cannot be captured by closures. Consider eliminating this use of mutation or using a heap-allocated mutable reference cell via ‘ref’ and ‘!’.”

Before we follow the compiler’s advice, let’s make our own heap allocated type in order to get a better understanding of what’s going on. Since record types are reference types (so they are heap allocated), a simple record type will suffice:

type TimeType =
    { mutable tm : System.DateTime }

The runningTimeDelta assignment body is modified accordingly:

let runningTimeDelta =
    let lastVisitTime = { tm = System.DateTime.Now }
    (fun () ->
        let delta = System.DateTime.Now - lastVisitTime.tm
        lastVisitTime.tm <- System.DateTime.Now
        delta ) 

[0..100000] |> ignore // waste some time
printfn "Running for %A" (runningTimeDelta())
[0..100000] |> ignore // waste some more time
printfn "Running for an additional %A" (runningTimeDelta())

(BTW, just in case you missed that structures are value types, and thus stack allocated, you can try adding “[<Struct>]” before the TimeType record definition and check out the resulting error message.)

As you can see, the sole purpose of wrapping a single value ( tm ) in a record type (TimeType) in our example, is to make it into a reference type instead of a value type. The F# (or OCaml) designers have provided us with the generic record type “ref” to accomplish the same thing, and a few operators to streamline its’ use. This is the type that the compiler tipped us off about in the “error FS0407″ message. Its’ definition is:

type 'T ref = { mutable contents: 'T }
let (!) r = r.contents
let (:=) r v = r.contents <- v
let ref v = { contents = v }

Adjusting our sample code to use the ref type is trivial:

let runningTimeDelta =
    let lastVisitTime = ref System.DateTime.Now
    (fun () ->
        let delta = System.DateTime.Now - !lastVisitTime
        lastVisitTime := System.DateTime.Now
        delta )

Don’t use this at home

Creating mutable data that acts like C’s static variables, and hiding it inside function value assignments, takes us far from the ideal, side effect free world that functional programming is supposed to be all about. Therefore, I’d recommend avoiding it in most cases. However, I find that playing with and exploring patterns like these, deepens your understanding of a language, its’ possibilities and its’ limitations.

  1. No comments yet.

  1. No trackbacks yet.