So, let's get caught up to where we are today and where we came from:
Dustin Campbell also has a series that I've linked before, but a few have come out recently that you may want to pay attention to. What's great about the F# community, although small, is very willing to help each other out in forums, emails, chats and so on. Check out hubFS for that kind of community. You might even find some product team members there. Anyhow, before shiny things came along, let's get back to Dustin here and his "Why I Love F#" series:
So, let's move onto the topics for today. Today we will cover the following areas:
- Scoping it Out
- Recursion, Recursion, Recursion
- Staying Anonymous
Scoping of variables is a common thing inside any programming language and really no different in F# at all. Remember that identifiers can be either values or functions themselves. The only thing to me that is interesting about F# is that you can redefine your identifiers. By default, your identifiers are immutable unless otherwise specified in functional programming languages. So, we're not going to change the value, but instead redefine. And what's more interesting, is that you can change the type on the fly as well with the redefine, so be careful!
let message =
let temp = "Foo"
let temp = 1
let temp = "Bar"
So, this one works and quite simply just by redefining what temp is. If we pop open Reflector, here's what it boils down to in C#:
public static void _main()
message@3 = "Bar";
As you can see from there, it refactored that code out that we didn't need at all. It was a pretty stupid example, but interesting nonetheless.
Recursion, Recursion, Recursion
Recursion is one of those computer science lessons that everyone should have learned back in their early CS days. This was taught in line with pointers, reference, hex/octal math, linked lists and so on. I certainly hope they still teach that stuff nowadays with Java and .NET now the mainstays in universities. Anyhow, if you didn't have that luxury, it's basically where you have a function that calls itself in order to return an answer. Some of the classic examples of this are computing factorials, Fibonacci sequences and so on. Of course recursive functions can have their downsides including blowing out the call stack if the recursion gets too deep or gets into an infinite loop, so it's always a good thing to test for these sorts of things.
F# treats recursive functions just a bit differently than regular functions. In fact, in order to make a function act recursive, you must mark it as such using the rec keyword. This allows you to call that function within that function, else it will give a syntax error. So, let's step through a few examples.
Let's start out with the classic Fibonacci sequence. To do this in traditional imperative programming, it looks something like this in C# 2.0:
static int Fib(int i)
if (i <= 1)
return Fib(i - 1) + Fib(i - 2);
Ok, so that's old school to me. Instead, since I mentioned that C# is going more towards a functional programming style, let's go ahead and do that again using anonymous functions (System.Func) instead.
Func<int, int> fib = null;
fib = i => i > 1 ? fib(i - 1) + fib(i - 2) : 1;
Ah, much cleaner. But, let's take this to F# and use pattern matching instead of just the normal if/else control structure, just to be on the wild side.
let rec fib n =
match n with
| 0 -> 1
| 1 -> 1
| n -> fib(n-2) + fib(n - 1)
let fib10 = fib 10
printfn "10th Fibonacci 10 %i" fib10
Ok, so let's throw a few more logs onto the fire with a couple more, one with recursing all files in a given directory (yes, I know you can do it with Directory.GetFiles, but this is more fun), and computing a factorial.
let rec recurseDirectories x =
let fileList = new ResizeArray<string>()
let subDirs = Directory.GetDirectories(x)
subDirs |> Seq.iter(fun x -> fileList.AddRange(recurseDirectories x))
let directories = recurseDirectories @"E:\Work"
directories.ForEach(fun x -> printfn "%s" x)
let rec fac n =
match n with
| 0 -> 1
| n -> n * fac (n - 1)
let fac10 = fac 10
printfn "Factorial of 10 %i" fac10
In the recurseDirectories function, I was being a little tricky and using a mutable structure. The ResizeArray<T> is actually just a rename of the List<T> generic from the regular CLR. As you can note, I'm not using any control functions for doing so such as foreach loops, etc. Instead, I'm using the Seq collection inside of F# proper and I'm sure I'll get to that later. And yes, there are probably more ways of doing these, but these are pretty good nonetheless.
As you saw from above, I used the keyword fun. What that is, is using an anonymous function. This is much like in C# using the System.Func structure but with different underlying base classes underneath. Some simple examples of creating anonymous functions are just that, for iterating over a block like above. We also can do something else like doing some simple examples such as below:
let a = (fun b c -> b * c) 12 13
printfn "%i" a
We can also use tuples with this as well. This means that you must specify all parameters up front. You can only do pattern matching when using this style. If you need to supply multiple arguments to this, go ahead and use Currying, which we talked about last time. Below is a simple example of the above code:
let a = (function (b, c) -> b * c) (12, 13)
let z = (function y -> function x -> y * x) 12 13
printfn "%i" z
printfn "%i" a
And this even can apply when using .NET classes such as the ResizeArray<T> such as this quick example:
let stringList =
let temp = new ResizeArray<string>();
temp.AddRange([|"Hello"; " "; "Cleveland"|])
stringList.ForEach(fun x -> print_string x)
Wrapping It Up
Well, I walked through just a few more pieces for your F# Adventure. I have plenty more to cover including defining types, operators and so on that make DSLs quite useful in the .NET world. So, subscribe if you haven't already and stay tuned. Until next time...