Monday, February 25, 2008
Welcome to the eighth article in my series about why I look upon the F# language with the hormone-driven lust of a 16-year old boy. ([ed.] Dustin's trophy wife has indicated that the previous metaphor might be a little too vivid.)

If you're just joining us, below is the path that has brought us to this point.

  1. The Interactive Environment
  2. Type-safe Format Strings
  3. Tuples
  4. Breaking Up Tuples
  5. Result Tuples
  6. Functions, Functions, Functions!
  7. Pattern Matching

Today, we're taking a high-level look at F# option types. Option types are a simple example of a discriminated (or tagged) union1, although understanding that isn't necessary in order to use them. Simply put, an option type wraps a value with information indicating whether or not the value exists. For C# or VB programmers, it may be convenient to think of option types as a mutant cross between .NET 2.0 nullable types and the null object design pattern.

There are two constructors that instantiate option types. First, there's the Some constructor, which takes a value to be wrapped.

> let someValue = Some(42);;

val someValue : int option

And then, there's the None constructor, which doesn't take anything.

> let noValue = None;;

val noValue : 'a option
NeRd Note
Notice that, in the above code, F# infers the type of noValue as the generic, 'a option, rather than int option. That's because, unlike the declaration of someValue, no information indicates an int. If you really want to declare a None value as type int option, you'd declare it like so:
> let noValue : int option = None;;

val noValue : int option

One of the properties of option types that makes them so compelling is the ability to pattern match over them.

> let isFortyTwo opt =
-   match opt with
-   | Some(42) -> true
-   | Some(_) -> false
-   | None -> false;;

val isFortyTwo : int option -> bool

Now, we can call our isFortyTwo function to show that the pattern matching works as expected.

> isFortyTwo someValue;;

val it : bool = true

> isFortyTwo noValue;;

val it : bool = false

> isFortyTwo (Some(41));;

val it : bool = false

This is all well and good, but we need a practical example to sink our teeth into. Let's use the .NET Framework Stream.ReadByte function as a guinea pig. ([ed.] Dustin is not implying that you should sink your teeth into guinea pigs. That's disgusting. Shame on you.)

Stream.ReadByte has a pretty bad code smell. First of all, it returns an int instead of a byte. Initially, that should seem strange since the method specifically states that it's a byte generator. ReadByte returns -1 when the current position is at the end of the stream. Because -1 is not expressible as an unsigned byte, ReadByte returns an int. Of course, that's the second problem: extra non-obvious information is encoded into the result value of this function. However, unless you read the documentation, there's no way of knowing that.

By employing an option type, we can clarify the function and be a bit more honest about its result.

> open System.IO
-
- let readByte (s : #Stream) =
-   match s.ReadByte() with
-   | i when i < 0 -> None
-   | i -> Some(Byte.of_int i);;

val readByte : #System.IO.Stream -> byte option

Now, the semantics of the function are better expressed thanks to the option type.

In addition, we can write a function that pattern matches over the result of our readByte function.

> let rec printStream s =
-   match readByte s with
-   | Some(b) ->
-       printfn "%d" (Byte.to_int b)
-       printStream s
-   | _ -> ();;

val printStream : #Stream -> unit

And here's the above printStream function in action:

> let bytes = [|1uy .. 10uy|];;

val bytes : byte array

> let memStream = new MemoryStream(bytes);;

val memStream : MemoryStream

> printStream memStream;;
1
2
3
4
5
6
7
8
9
10
val it : unit = ()

Option types provide an elegant way to attach a bit of extra boolean information to a value. It's important to become comfortable with them as they are used extensively throughout the F# libraries.

Have fun! Next we'll explore... well... I haven't decided yet. If you have any suggestions, feel free to email me at dustin AT diditwith.net.

1We'll explore discriminated unions in a future article.

posted on Monday, February 25, 2008 3:56:21 PM (Pacific Standard Time, UTC-08:00)  #    Comments [3]

kick it on DotNetKicks.com
 Thursday, February 21, 2008

Computer books

I don't know about you, but around my house, computer books have a habit of multiplying like rabbits. Sometimes it seems as if you can't put up your feet without resting them on a pile of old programming books. There are several reasons why these books proliferate so:

  • I like my shelves to reflect an intelligence that I don't actually possess.
  • I feel the need to own reference books that I never need to reference.
  • I purchase books on the latest and greatest technology before I realize that I'm not actually interested in said technology.
  • When I become interested in a topic, I tend to purchase every book ever written about it—even if a new book duplicates information I already have.
  • I buy classics that I have the best intentions of reading... but never do.
  • I acquire books for a specific project at work, and the project ends.

Because my shelves are bursting at the seams (and the Wife Acceptance Factor for them has become quite low), it's time for an early Spring cleaning. If you're interested in some reasonably-priced programming tomes, previously owned by a lesser-known blogger, feel free to browse my Amazon storefront.

(Quiz: How many of the books in above picture do you own?)

(Clarification: The books pictured above are not for sale. Those are keepers!)

posted on Thursday, February 21, 2008 12:44:48 PM (Pacific Standard Time, UTC-08:00)  #    Comments [17]

kick it on DotNetKicks.com
 Tuesday, February 19, 2008
Greetings fellow F#-philes! Today we're looking at another reason that I am completely infatuated with the F# language—pattern matching.

Pattern matching is a simple idea. Essentially, a pattern match takes an input and a set of rules. Each rule tests the input against a pattern and returns a result if they match.

The following naive implementation of the tired, old Fibonacci function shows simple pattern matching at work.

#light

let rec fib n =
  match n with
  | 0 -> 0
  | 1 -> 1
  | _ -> fib(n - 1) + fib(n - 2)

Pattern matching syntax is simple and clear. It should be readable by any programmer worth their salt. In fact, the above match .. with block is completely equivalent to the following C# switch statement:

static int Fib(int n)
{
  switch (n)
  {
    case 0:
      return 0;
    case 1:
      return 1;
    default:
      return Fib(n - 1) + Fib(n - 2);
  }
}

That's pretty unimpressive. I mean, if pattern matching were identical to standard switch statements, there really would be nothing exciting about them. Fortunately, there are some enormous differences that demote switch statements to a very distant cousin.

The first difference is subtle but profound: pattern matches return values. A pattern match is very much like a function that takes an argument and returns a value. Consider the following rewrite of our F# fib function:

#light

let rec fib n =
  let result = match n with
               | 0 -> 0
               | 1 -> 1
               | _ -> fib(n - 1) + fib(n - 2)
  result

The above example might be a bit contrived, but it illustrates the point. Simulating that with a switch statement is awkward.

static int Fib(int n)
{
  int result;
  switch (n)
  {
    case 0:
      result = 0;
      break;
    case 1:
      result = 1;
      break;
    default:
      result = Fib(n - 1) + Fib(n - 2);
      break;
  }
  return result;
}

Switch statements don't return values, so we can't assign a switch statement to a variable. Instead, we must use mutable state and pepper the cases with break statements. In essence, a pattern match is like a function while a switch statement is like a big GOTO.

In addition, pattern matching supports a wealth of features that truly set it apart from standard imperative switch statements.

Patterns can:

  1. Contain guard rules (e.g. match x but only when x is less than zero).
  2. Bind values to names.
  3. Decompose type structures.

Let's examine each of these in turn.

First, consider our original fib function with an additional pattern containing a guard rule:

#light

let rec fib n =
  match n with
  | _ when n < 0 -> failwith "value cannot be less than 0."
  | 0 -> 0
  | 1 -> 1
  | _ -> fib(n - 1) + fib(n - 2)

Now that's a bit more interesting! In C# or Visual Basic, we would have to introduce an if-statement at the beginning of the function to test for an invalid argument. In F#, the guard is inserted directly as a pattern rule.

Another indispensible feature of F# pattern matching is the ability to bind values to names.

So far, we've used the match .. with syntax to define pattern matches. This time, we'll use an alternative syntax that, although it is not required, easily demonstrates how values can be bound to names within pattern rules.

The alternative syntax can be used in the case where a function is defined with one argument and simply returns the result of a pattern match on that argument. In this syntax, the argument is not specified, and the keyword function is inserted. The match .. with statement needs to reference the argument name, but because the argument is unspecified, it has no name. Consequently, the match .. with statement must be removed, leaving us with a function that is defined entirely in terms of pattern matching rules. Because the argument is unnamed, values must be bound to names within the pattern rules.

A code sample is worth a thousand words.

#light

let rec fib = function
  | x when x < 0 -> failwith "value cannot be less than 0."
  | 0 | 1 as x -> x
  | x -> fib(x - 1) + fib(x - 2)

In the above code, we bind the name x in each pattern to make up for the fact that the argument is unspecified. In addition, the rules for 0 and 1 and have been combined using an "or" (or "union") pattern. Note that there are two different ways to bind a value to a name within a pattern rule. First, a name can simply be explicitly specified, substituted within the pattern. The other way is to use the as keyword. Both ways are demonstrated above.

The last feature of pattern matching that we'll look at is its capability to decompose type structures.

Recently, we saw that F# would automatically convert the result of Dictionary<TKey, TValue>.TryGetValue to a tuple if a variable isn't specified for the out parameter. In a comment to that article, Derek Slager presented a helper function that returns a default value if TryGetValue returns false. This helper function is an excellent practical example of a pattern match that decomposes a tuple value.

#light

open System.Collections.Generic

let getValueOrDefault (dict : #IDictionary<'a,'b>) key defaultValue =
  match dict.TryGetValue key with
  | true, value -> value
  | _ -> defaultValue

In addition to the tuple decomposition, the first rule elegantly binds the second part of the tuple to the name value. Sweet!

Because pattern matching is intrinsic to F# programming, we'll see more of it in upcoming articles. As features supporting pattern matching are introduced in this series, we'll build on the basics presented here.

Next up: the option type. See you then!

posted on Tuesday, February 19, 2008 7:39:00 AM (Pacific Standard Time, UTC-08:00)  #    Comments [5]

kick it on DotNetKicks.com
 Wednesday, January 30, 2008

Welcome back for another installment in my series on why I find Microsoft F# to be an exciting language for the .NET platform. If you're just joining us, below are links to the articles in the series so far.

  1. The Interactive Environment
  2. Type-safe Format Strings
  3. Tuples
  4. Breaking Up Tuples
  5. Result Tuples

I have around 15-20 more articles planned, but I'm always looking for suggestions. If you have a topic idea for the series, feel free to email me at dustin AT diditwith.net.

One of the main reasons that I find F# to be so provocative is that it fully embraces three programming paradigms: functional, imperative and object-oriented. Of these, functional programming is the most favored, mostly due to its OCaml heritage. Because of this, we can't move any further in this series without introducing what functional programming is all about: functions!

In F#, a function declaration consists of the fun keyword, an argument, the -> operator and finally, the function body.

fun arg -> body

In the F# interactive environment, we can declare a function that takes an argument x and returns its increment like so:

> fun x -> x + 1;;

val it : int -> int = <fun:clo@0>

If the -> operator looks strange to you, remember that it's just a divider that separates function arguments from function bodies.

The code above is somewhat equivalent to the following C# 3.0 lambda expression:

x => x + 1;

Or this VB 9.0 lambda expression:

Function(x) x + 1

The biggest difference is that the F# function does not need to be assigned to a .NET delegate (or expression tree) as the C# 3.0 and VB 9.0 lambda expressions do. This is an important point: F# functions are not delegates. They're something else entirely.

Another point of interest is F#'s type inference. We didn't specify a type for x in the function above, but F# determined that x is of type int and that the function returns an int. F# worked this out from the literal 1 that appears in the function body. 1 is an int. Therefore, x must be an int because it is being added together with 1. Finally, the function must return an int since its body returns the result of adding two ints, x and 1.

Because the literal that is added together with x is what triggers the type inference, changing the literal will change the type of the function. For example, changing 1 to 1.0 produces a function that increments floats.

> fun x -> x + 1.0;;

val it : float -> float = <fun:clo@0>

This really isn't anything to write home about. After all, C# 3.0 and VB 9.0 handle type inference similarly for their respective lambda expressions. However, F#'s type inference algorithm is extremely advanced. As this series progresses, you'll see functions without any type annotations that the compiler will successfully type infer, leaving you scratching your head.

At this point, we've successfully declared a function in F#. Unfortunately, we can't use our function yet because it doesn't have a name. We've declared an anonymous function. So, how do we give our function a name? Well, let's back up a little bit to examine some syntax from a previous article.

> let pair = 37, 5;;

val pair = int * int

The above example shows a variable, pair, being defined and assigned a value of (37, 5). The heart of this syntax is the keyword let.

Simply put, let binds a value to a name.

let name = value

In F#, functions are values. That's a small thing to say, but it has enormous implications. Functions are treated in the same way as any other value. That means that functions can be passed as arguments to other functions, returned by other functions, contained within data structures and bound by names as variables.

Because functions are values, we can give our function the name inc using let.

> let inc = (fun x -> x + 1);;

val inc : int -> int

And, we can call inc like so:

> inc 41;;

val it : int = 42

After learning to declare a function of one argument, the next logical step is to declare a function of two arguments. This is actually done with two functions. Consider the code below:

> let add = (fun x ->
-             (fun y -> x + y));;

val add : int -> int -> int

That might look a bit confusing at first. If so, look again carefully. We're declaring a function of one argument, x. This function's body is another function of one argument, y. The body of the inner function is x + y. To call our function, we pass the first argument. That returns the inner function to which we pass the second argument and finally receive the result of the calculation. In essence, calling add requires two function calls. Normally, this is done all at once, as below:

> add 37 5;;

val it : int = 42

add is an example of a curried function. The idea behind currying is simply transforming a function of multiple arguments into a series of functions that each take one argument. That's all it is. It's not hard. In fact, you can even torture .NET delegates to curry functions in C#. Currying is a simple concept, but it's hard to grasp if you've never encountered it before.

An interesting property of curried functions is the ability to partially apply them. For example, if we pass 1 to our add function above but don't pass the second argument, we are left with a function of one argument that increments by 1. That is, we can define our inc function in terms of add:

> let inc = add 1;;

val inc : (int -> int)

> inc 41;;

val it : int = 42

Cool!

The reality of our add definition above is that it is far too verbose. It's easy to imagine the nested functions quickly getting out of control when functions of more arguments are declared. For this reason, F# provides a more concise way to declare functions of multiple arguments.

> let add = (fun x y -> x + y);;

val add : int -> int -> int

> add 29 13;;

val it : int = 42

That's better. However, F# provides an even more concise syntax.

> let add x y = x + y;;

val add : int -> int -> int

> add 23 19;;

val it : int = 42

That's much better. Note that all three declarations of add are equivalent. Each syntax produces a curried function. In F#, we get currying for free. If you need to declare a function that isn't curried (e.g. to be called easily from C# or VB), you'd use a slightly different syntax. But, that's another article.

I should also point out that F# managed to infer the type of add as int -> int -> int even though there weren't any literals to trigger off of. In future articles, we'll see F#'s type inference algorithm work "miracles" like this over and over again. :-)

Next time, we'll be looking at pattern matching and how it fits into F#. See you then!

posted on Wednesday, January 30, 2008 7:16:05 AM (Pacific Standard Time, UTC-08:00)  #    Comments [2]

kick it on DotNetKicks.com
 Tuesday, January 29, 2008
As promised, today I'm demonstrating a compelling way in which F# uses tuples to make .NET programming more elegant.

A question that comes up early in F# demonstrations is, "Can I use F# to access code written in my favorite .NET language, <BLANK>?" The answer is an emphatic yes. F# is a first-class .NET citizen that compiles to the same IL as any other .NET language. Consider the following code:

> #light
- open System.Collections.Generic
-
- let d = new Dictionary<int, string>()
- d.Add(1, "My")
- d.Add(2, "F#")
- d.Add(3, "Dictionary");;

val d : Dictionary<int,string>

> d;;
val it : Dictionary<int,string> = dict [(1, "My"); (2, "F#"); (3, "Dictionary")]

The above code1 instantiates a new System.Collections.Generic.Dictionary<TKey, TValue> for int and string, and adds three key/value pairs to it. Note that Dictionary is not written in F#. It is part of the .NET base class library, written in C#.

Retrieving values from d is easy. We simply pass the value's key to the dictionary's indexer like so:

> d.[1];;

val it : string = "My"

> d.[3];;

val it : string = "Dictionary"

However, if we pass a key that isn't found in the dictionary, an exception is thrown.2

> d.[4];;

System.Collections.Generic.KeyNotFoundException: The given key was not present in the dictionary.
   at System.ThrowHelper.ThrowKeyNotFoundException()
   at System.Collections.Generic.Dictionary`2.get_Item(TKey key)
   at <StartupCode$FSI_0013>.FSI_0013._main()
stopped due to error

Fortunately, Dictionary provides a function that allows us to query using an invalid key without throwing an exception. This function, TryGetValue, has the following signature (shown in C#):

bool TryGetValue(TKey key, out TValue value)

The purpose of TryGetValue is obvious. If key is found, the function returns true and the value is returned in the output parameter3. If key is not found, the function returns false and value contains some throwaway data. The C# code below demonstrates how this function might be used.

using System;
using System.Collections.Generic;

class Program
{
  static void Main()
  {
    var d = new Dictionary<int, string>();
    d.Add(1, "My");
    d.Add(2, "C#");
    d.Add(3, "Dictionary");

    string v;
    if (d.TryGetValue(4, out v))
      Console.WriteLine(v);
  }
}

So, how can we use this function in F#? Well, there're a few ways.

The first approach is almost exactly the same as the C# version above. First, we declare a variable to pass as the output parameter. Note that this variable must be declared as mutable so TryGetValue can modify it.

> let mutable v = "";;

val mutable v : string

Now, we can call TryGetValue, passing v by reference.

> d.TryGetValue(1, &v);;

  d.TryGetValue(1, &v);;
  -----------------^^^

stdin(19,17): warning: FS0051: The address-of operator may result in non-verifiable code.
Use only when passing byrefs to functions that require them.

val it : bool = true

> v;;

val it : string = "My"

OK. That worked but displayed an ugly warning about non-verifiable code. Yikes! Fortunately, F# provides another way to declare variables which support mutation: reference cells.4

Declaring a variable as a reference cell is trivial:

> let v = ref "";;

val v : string ref

We can pass the reference cell into TryGetValue without receiving that nasty warning.

> d.TryGetValue(2, v);;

val it : bool = true

> !v;;

val it : string = "F#"

That's much better.

At this point, many of you are probably thinking, "Wait a minute! Wasn't this article supposed to be about tuples? What's all this mutable-variable-output-parameter stuff?" Don't worry. There's a method to my madness. Are you ready?

Consider what happens if we call TryGetValue without specifying a variable for the output parameter:

> let res = d.TryGetValue(3);;

val res : bool * string

> res;;

val it : bool * string = (true, "Dictionary")

Did you catch that? When calling a function containing output parameters in F#, you don't have to specify variables for them. The F# compiler will automatically consolidate the function's result and output parameters into a tuple (in this case, a pair). Awesome! If you were paying attention last time, you've probably already realized that we can bind the TryGetValue call to a pattern that extracts the values from the resulting pair.

> let res, v = d.TryGetValue(2);;

val res : bool
val v : string

> res;;

val it : bool = true

> v;;

val it : string = "F#"

Now, we can easily query our dictionary using an invalid key without an exception being thrown. Best of all, we don't have to declare an awkward mutable variable to store the value. What takes two lines of code in C# consumes just one in F#.

> let res, v = d.TryGetValue(4);;

val res : bool
val v : string

> res;;

val it : bool = false

It is the attention to detail that makes it a joy to code with F#. This is just one example of how F# can consume .NET framework classes in ways more elegant than even C#, the lingua franca of the .NET universe!

I haven't decided what the next article will cover yet. Are there any requests? Feel free to email them to dustin AT diditwith.net.

1The #light directive in the first line of the code sample enables the F# lightweight syntax. We'll look closer at this in a future article.
2This might be frustrating to users of the System.Collections.Hashtable class from .NET Framework 1.0. Unlike Dictionary, Hashtable returns null when a key isn't found rather than throwing an exception. The reason for this behavior difference is detailed here.
3Normally, I would consider the use of output parameters to be a code smell. However, TryGetValue is an example of a scenario where an output parameter is justified.
4We'll be looking more deeply into reference cells in a future article.

posted on Tuesday, January 29, 2008 11:30:29 AM (Pacific Standard Time, UTC-08:00)  #    Comments [3]

kick it on DotNetKicks.com
 Wednesday, January 23, 2008
Nate Hoellin has a great article on setting up an F# project for TDD with NUnit. Check it out:

Sample setup for Visual Studio 2008 for F# Unit Testing with NUnit


posted on Wednesday, January 23, 2008 12:36:03 PM (Pacific Standard Time, UTC-08:00)  #    Comments [2]

kick it on DotNetKicks.com
 Monday, January 21, 2008
Last time, I demonstrated the basics of tuple types in the F# language. However, I (intentionally) failed to answer a couple of important questions about tuples:
  1. Once values are bound together in a tuple, how can they be retrieved?
  2. How are tuples useful?

I'll leave the second question for next time. Today, we'll see how the values of a tuple can be extracted.

Here is the tuple that we began with last time:

> let pair = 37, 5;;

val pair = int * int

> pair;;

val it : int * int = (37, 5)

Extracting the values from this tuple is a simple matter of using the fst and snd functions (which F# held over from its ML heritage). These functions retrieve the first and second values, respectively, from a two-value tuple.

> fst pair;;

val it : int = 37

> snd pair;;

val it : int = 5

The results of these functions also can be assigned to variables.

> let x = fst pair;;

val x : int

> let y = snd pair;;

val y : int

> printfn "x = %d, y = %d" x y;;
x = 37, y = 5
val it : unit = ()

That's great, but what if we need to extract the values from a tuple whose length is greater than two?

> let triple = 2, 11, 29;;

val triple : int * int * int

Is there a thrd function we can use to get the last element out of the tuple above? Nope. In fact, the fst and snd functions that we used on pair won't even work with this tuple. The problem is that those functions are intended to be used only with tuples of two values. This becomes clear when their definitions are considered:

let fst (a,b) = a
let snd (a,b) = b

If we try to use either fst or snd with our triple tuple, a type mismatch error occurs.

> fst triple;;

  fst triple;;
  ----^^^^^^^

stdin(27,4): error: FS0001: Type mismatch. Expecting a
        'a * 'b
but given a
        int * int * int.
The tuples have different lengths
stopped due to error

Fortunately, F# provides a very natural syntax to extract the values from any tuple. The idea is to use a simple let statement. However, instead of binding to a single name, we bind to a pattern made up of several names. For example, we can extract the values from our triple tuple like so:

> let x, y, z = triple;;

val x : int
val y : int
val z : int

> printfn "x = %d, y = %d, z = %d" x y z;;
x = 2, y = 11, z = 29
val it : unit = ()

The obvious follow-up question is, what if we only want to retrieve one or two values from triple? Put another way, is it really necessary to bind each value of a tuple to a name even when we aren't interested in all of the values? The answer is, no, it isn't necessary to bind each value of a tuple of a name. F# provides an ultra-handy wildcard pattern that trivializes this problem. Wildcards allow us to bind only the information that we're interested in by adding "holes" to a pattern. In code, they are represented by an underscore (_) character.

> let x, _, z = triple;;

val x : int
val z : int

> printfn "x = %d, z = %d" x z;;
x = 2, z = 11
val it : unit = ()

Very cool. We'll see more uses of wildcards as this series progresses.

That should answer the first question above. Next time, we'll explore some important uses of tuples that make them very compelling—especially for .NET developers.

posted on Monday, January 21, 2008 7:41:25 AM (Pacific Standard Time, UTC-08:00)  #    Comments [3]

kick it on DotNetKicks.com
 Friday, January 18, 2008
A few months ago, I wrote about how there had been a big price break in the Ultimate Developer Rig presented by Jeff Atwood and Scott Hanselman. About a month later, I went ahead and built my own version of this glorious box.

Since the price had fallen so low ($1,503.88), I decided to increase the amount of ram from 4GB to 8GB. This was due in part to a conversation that I had with my good friend and DevExpress colleague, Oliver Sturm. We were discussing the well-known limits of ram in 32-bit Windows. Oliver made the point, "I'd rather have 4GB on 32-bit Windows than 4GB on 64-bit Windows." The thinking is that, while 32-bit Windows may not be able to fully access 4GB of ram, 4GB on a 64-bit machine might seem cramped since applications use more memory due to wider pointers. Besides, ram is cheap! There's no reason not to purchase a little more elbow room—especially since the price of the machine had already dropped by $400.

The final build that I settled on is below:

Component Price Paid Current
Antec P182 Gun Metal Black 0.8mm cold rolled steel ATX Mid Tower Computer Case - Retail $149.99 $139.99
MSI P6N SLI Platinum LGA 775 NVIDIA nForce 650i SLI ATX Intel Motherboard - Retail $139.99 $139.99
MSI NX8600GTS-T2D256E-OC GeForce 8600GTS 256MB 128-bit GDDR3 PCI Express x16 HDCP Ready SLI Supported Video Card - Retail (2) $299.98 $279.98
Western Digital Raptor WD1500ADFD 150GB 10,000 RPM Serial ATA150 Hard Drive - OEM $179.99 $169.99
Western Digital Caviar RE WD3200YS 320GB 7200 RPM SATA 3.0Gb/s Hard Drive - OEM $89.99 $89.99
Intel Core 2 Quad Q6600 Kentsfield 2.4GHz LGA 775 Quad-Core Processor Model HH80562PH0568M - OEM $260.00 $260.00
ZALMAN CNPS9500 AT 2 Ball CPU Cooling Fan/Heatsink - Retail $47.99 $44.99
CORSAIR CMPSU-520HX ATX12V v2.2 and EPS12V 2.91 520W Power Supply - Retail $124.99 $124.99
OCZ Gold 4GB(2 x 2GB) 240-Pin DDR2 SDRAM DDR2 800 (PC2 6400) Dual Channel Kit Desktop Memory Model OCZ2G8004GK - Retail (2) $319.98 $207.98
LITE-ON 20X DVD±R DVD Burner with 12X DVD-RAM write and LightScribe Technology Black E-IDE/ATAPI Model LH-20A1H-185 - OEM $28.99 $30.99
  $1,641.89 $1,488.89

As you can see, the price has dropped even further, and the cost of 8GB of ram is now around $200!

Full Disclosure: I had a negative experience with the MSI P6N SLI Platinum motherboard. It was dead on arrival. After installing the CPU, RAM and a video card, the motherboard refused to POST. Newegg's RMA service did a fantastic job of replacing the board. However, there's nothing worse than removing a CPU, cleaning off the thermal paste and hoping that it works the next time it's installed. Fortunately, the second motherboard worked fine and has been running well for nearly two months.

The time I've spent developing with this machine have been nothing short of pure joy. Builds are faster, multiple VMs don't drag me down, virus scans occur without my knowledge... it's complete bliss. I can even watch every episode of Buffy the Vampire Slayer, season 1 simultaneously without a hiccup.

Quad core in action

Quad core in action

I should also mention that my trophy wife, while OK with the initial purchase, is grumbling a bit after seeing the current component prices. ;-)

posted on Friday, January 18, 2008 12:42:44 PM (Pacific Standard Time, UTC-08:00)  #    Comments [3]

kick it on DotNetKicks.com
Another feature of the F# language that I crave desperately when writing C# or VB code is F#'s built-in support for tuples. What's a tuple? Simply put, a tuple is an ordered group of values. In one sense, a tuple is very similar to the anonymous types of C# 3.0. The chief difference is that the values in an F# tuple are not named like the properties of a C# anonymous type.
NeRd Note
Most pressing on your mind is likely the question of how one pronounces the word, "tuple." Well, my British friends emphatically point out that it's "too-pull," while my red-blooded, English-language-abusing American friends1 like to say "tuh-pull."2 However, when my British friends speak, they always sound intelligent. I think it has something to do with the accent. So, I'm going with "too-pull." I like to sound smart—especially when it's easy.

In F#, a tuple3 is concisely declared as a let statement with a single name and multiple values separated by commas.

> let pair = 37, 5;;

val pair = int * int

> pair;;

val it : int * int = (37, 5)

Notice that F# infers the type of pair to be int * int. The asterisk (*) doesn't actually mean multiplication in this case. Instead, it indicates that the two types on either side are bound together as one type.

Tuples can contain any number of values, and the values don't have to be of the same type.

> let triple = 0, "F# Rules!", 12.8;;

val triple : int * string * float

Tuples can be compared for equality.

> pair = (29, 13);;

val it : bool = false

> pair = (37, 5);;

val it : bool = true

> pair = (19, 23);;

val it : bool = false

And other comparisons are also legal.

> (1, 1) < (1, 2);;

val it : bool = true

> (2, 1) > (1, 2);;

val it : bool = true

However, tuples with different types cannot be compared. Trying to compare pair, which is of type int * int, with a tuple of type int * string results in an error:

> pair = (0, "F# Rules!");;

  pair = (0, "F# Rules!");;
  -----------^^^^^^^^^^^^

stdin(12,11): error: FS0001: This expression has type
        string
but is here used with type
        int
stopped due to error

In addition, tuples of different lengths cannot be compared.

> triple = (0, "F# Rules!");;

  triple = (0, "F# Rules!");;
  ----------^^^^^^^^^^^^^^^

stdin(13,10): error: FS0001: Type mismatch. Expecting a
        int * string * float
but given a
        'a * 'b.
The tuples have different lengths
stopped due to error

Interestingly, in the above code, the F# compiler doesn't bother inferring the types in the tuple, (0, "F# Rules!"). It is left generic: 'a * 'b. The F# compiler sees that the tuples have a different number of values and stops.

Next time we'll look at some cool ways to use tuples in F# programming.

1Please don't hurt me Keith!
2Usually while sucking down a can of Schlitz.
3too-pull

posted on Friday, January 18, 2008 10:14:39 AM (Pacific Standard Time, UTC-08:00)  #    Comments [5]

kick it on DotNetKicks.com