LINQPad sponsors STL ALT.NET

LINQPadI remember when LINQ was the new hotness.  When developers realized that they could stop writing `for` and `foreach` loops to farm data from collections.  It was a magical time, full of unicorns and rainbows and such.  In this midst of this bliss Joseph Albahari, author of the excellent C# in a Nutshell, released a small program called LINQPad that functioned as both a pseudo-C# LINQ REPL and a light-weight frontend to SQL Server (via LINQ2SQL).  Using LINQPad was (and still is) a great way to explore the LINQ API without breaking actual production code.

Since those early days, LINQPad has grown to support all of the major LINQ technologies and other data providers, including:

  • Entity Framework
  • LINQ to XML
  • Parallel LINQ
  • OData
  • WCF Data Services
  • SQL Azure
  • and many more!

In addition, LINQPad can also serve as an F# REPL, for those of the functional persuasion who would like more flexibility than FSI provides.

LINQPad is also extensible.  When I worked with Josh Buedel, he created a plugin for LINQPad that queried an XML web service exposed by an online billing provider that we were using at the time.  Using LINQPad, we could write LINQ queries against the service endpoints as if they were object collections, which made debugging service issues and generating ad hoc reports a breeze.

While LINQPad has always been free, users who wanted auto-completion, Reflector integration, smart tags, code snippets, etc. paid a premium fee for the Pro version of LINQPad.  Mr. Albahari has generously donated two Pro licenses to STL ALT .NET, which will be raffled to members in the coming months.  Two lucky winners will walk away with great software that no .NET developer should be without!

Collection comprehension

F# (and Ruby, I am told) has a nice little syntactic feature called “comprehension” which allows developers to create lists of numbers or characters by specifying a range to be “expanded”, like this:

let numbers = [0 .. 9]
let alpha = ['A' .. 'Z']
let everyOtherNumber = [0 .. 2 .. 16]

printfn "%A" numbers // [0; 1; 2; 3; 4; 5; 6; 7; 8; 9]
printfn "%A" alpha // ['A'; 'B'; 'C'; ... 'X'; 'Y'; 'Z']
printfn "%A" everyOtherNumber // [0; 2; 4; 6; 8; 10; 12; 14; 16]

Today I’ve been working on an e-commerce project where I need to build a list of months, so I started looking for a comprehension equivalent in C# and found this less elegant but adequate (for my purposes) method on Enumerable that does something similar:

IEnumerable<Int32> months = Enumerable.Range(1, 12);

There are a few problems with Range, however:

  1. the signature is (int start, int count) instead of (int start, int end)
  2. Range only accepts and returns integers
  3. Range does not provide a means to “step” values

If anyone knows a better comprehension alternative in C#, please let me know!

Getting a Clue with F#

In an attempt to bolster my geek-fu and partially just out of curiosity, I’ve been learning the Microsoft functional programming language F#.  It has been simultaneously frustrating and fun, as I struggle to bend my mind around functional concepts that are alien in the imperative world from which I hail.

As a fun project, I decided to implement a guessing strategy for the popular board game Clue, as proposed by Wired magazine in a recent article about teen “mathletes”:

The Task: Dr. Black has been murdered. Detective Jill must determine the murderer, crime scene, and weapon. There are six possible murderers (numbered 1 through 6, Professor Plum to Mrs. Peacock), 10 locations (1 through 10, ballroom to cellar), and six weapons (1 through 6, lead pipe to spanner). Detective Jill tries to guess the correct combination (there are 360 possibilities). Each guess is a theory. She asks her assistant, Jack, to confirm or refute each theory. When Jack refutes a theory, he reports that one of the guesses—murderer, location, or weapon—is wrong. The contestants are tasked with implementing a procedure that plays the role of Detective Jill. A brute-force program that tests all 360 theories earns a mere 50 points. An efficient program that tests no more than 20 theories earns an additional 50.

While I’m sure that my program is far from efficient, it was a good exercise for assembling the things I’ve been learning from the trivial examples in books and on the web.

It isn’t the shortest solution, but it would have earned the bonus 50 points because for any given theory, the program will only need to guess a maximum of ten times.  The way I limit guesses is by walking through each combination of guesses in the form:

  • guess1: suspect1, weapon1, room1
  • guess2: suspect2, weapon2, room2 (we’ve identified the suspect)
  • guess3: suspect2, weapon3, room3 (we’ve identified the weapon)
  • guess4: suspect2, weapon3, room4
  • (etc.)

When the suspect, weapon, or room equals the suspect, weapon, or room of the theory, they “stick” and are used in each subsequent guess (see lines 38 and 25).  Since there are more rooms (10) than suspects (6) or weapons (6), the number of rooms becomes the limiting factor on possible guesses.

If you’re a functional programmer, I’d love to hear your comments, suggestions, and criticisms, or maybe an implementation example in your language of choice.

EDIT: Just for clarity, in the code below “theory” represents the actual correct answer (I misread the instructions), while “guess” represents the current combination the program is testing.  So when guess = theory, the program stops testing guesses.

module Clue
open System

//http://en.wikipedia.org/wiki/Cluedo

let guess theory =

    let suspects =
        [| "Miss Scarlett"; "Colonel Mustard"; "Mrs. White"; "The Reverend Green"; "Mrs. Peacock"; "Professor Plum" |]

    let weapons =
        [| "Dagger"; "Candlestick"; "Revolver"; "Rope"; "Lead Pipe"; "Spanner" |]

    let rooms =
        [| "Kitchen"; "Ballroom"; "Conservatory"; "Dining Room"; "Cellar"; "Billiard Room"; "Library"; "Lounge"; "Hall"; "Study" |]

    let indexOf anArray anElement =
        Array.findIndex (fun e -> e = anElement) anArray

    let indicesOf aTheory  =
        let (s, w, r) = aTheory
        ((indexOf suspects s), (indexOf weapons w), (indexOf rooms r))

    let next g t =
        if g <> t then g + 1 else t

    let show guess =
       let s, w, r = guess
       printfn "%s with the %s in the %s" suspects.[s] weapons.[w] rooms.[r]

    let rec test guess theory =
        show guess
        if guess = theory then
            printfn "correct"
        else
            let (gs, gw, gr) = guess
            let (ts, tw, tr) = theory
            let newGuess = ((next gs ts), (next gw tw), (next gr tr))
            test newGuess theory

    test (0, 0, 0) (indicesOf theory)

//end guess

let main =
    printfn "--------------------"

    let theory1 = ("Mrs. White", "Rope", "Kitchen")
    guess theory1

    printfn "--------------------"

    let theory2 = ("Professor Plum", "Candlestick", "Lounge");
    guess theory2

    printfn "--------------------"

    let theory3 = ("The Reverend Green", "Spanner", "Ballroom");
    guess theory3

    printfn "--------------------"

    Console.ReadKey(true) |> ignore

//end main

main