<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0"><channel><title>Chris Smith's completely unique view</title><link>http://blogs.msdn.com/chrsmith/default.aspx</link><description>Algorithms, functional programming, CLR 4.0, and of course, F#!</description><dc:language>en-US</dc:language><generator>CommunityServer 2.1 SP1 (Build: 61025.2)</generator><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" href="http://feeds.feedburner.com/ChrisSmithsCompletelyUniqueView" type="application/rss+xml" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com" /><item><title>F# Language Details (Gotchas)</title><link>http://feedproxy.google.com/~r/ChrisSmithsCompletelyUniqueView/~3/lROrME1WTBY/f-language-details-gotchas.aspx</link><pubDate>Tue, 10 Nov 2009 03:52:01 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9919958</guid><dc:creator>ChrSmith</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/chrsmith/comments/9919958.aspx</comments><wfw:commentRss>http://blogs.msdn.com/chrsmith/commentrss.aspx?PostID=9919958</wfw:commentRss><description>&lt;p&gt;The ‘F’ in F# stands for &lt;em&gt;fun&lt;/em&gt;. However, there are some details in F# that might lead to bugs, surprises, and/or un-fun. This post is to highlight a couple of random ‘gotchas’ when exploring some corners of the F# language.&lt;/p&gt;  &lt;p&gt;&lt;img alt="Unicorn Image #13260" src="http://www.cornify.com/cornified/image_1257619523542.jpg" width="428" height="159" /&gt;&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;h3&gt;Overriding Equals and Not Equals&lt;/h3&gt;  &lt;p&gt;F# allows you to overload operators so you can better map mathematical concepts to your code. For example, consider this simple vector type. Notice how it overrides the Equals operator to compare just the vector’s magnitudes, not their actual values. &lt;/p&gt;  &lt;pre class="code"&gt;&lt;span style="color: blue"&gt;type &lt;/span&gt;Vector =
    | Vector &lt;span style="color: blue"&gt;of &lt;/span&gt;float * float * float

    &lt;span style="color: blue"&gt;member &lt;/span&gt;this.Length =
        &lt;span style="color: green"&gt;// Extract values via ninja pattern match
        // hidden in a let binding
        &lt;/span&gt;&lt;span style="color: blue"&gt;let &lt;/span&gt;(Vector(x,y,z)) = this
        sqrt &amp;lt;| x * x + y * y + z * z

    &lt;span style="color: blue"&gt;static member &lt;/span&gt;(+) (lhs, rhs) =
        &lt;span style="color: blue"&gt;let &lt;/span&gt;(Vector(x1,y1,z1)) = lhs
        &lt;span style="color: blue"&gt;let &lt;/span&gt;(Vector(x2,y2,z2)) = rhs

        Vector(x1 + x2, y1 + y2, z1 + z2)
        
    &lt;span style="color: green"&gt;// Equals
    &lt;/span&gt;&lt;span style="color: blue"&gt;static member &lt;/span&gt;(==) (lhs : Vector, rhs : Vector) =
        lhs.Length = rhs.Length

    &lt;span style="color: green"&gt;// Not equals
    &lt;/span&gt;&lt;span style="color: blue"&gt;static member &lt;/span&gt;(!=) (lhs : Vector, rhs) =
        not (lhs == rhs)&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;When you run this code in FSI, it doesn’t work.&lt;/p&gt;

&lt;pre class="code"&gt;&amp;gt; // Bug?
let vec1 = Vector(10.0, 0.0, 0.0)
let vec2 = Vector(0.0, 0.0, 10.0);;

val vec1 : Vector = Vector (10.0,0.0,0.0)
val vec2 : Vector = Vector (0.0,0.0,10.0)

&amp;gt; vec1 = vec2;;
val it : bool = false
&amp;gt; vec1.Length = vec2.Length;;
val it : bool = true&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;The key here is to understanding a bit more about how operator overloading in F# and .NET works. When you override an operator such as (+) the compiler generates a method named op_Addition. So when a .NET compiler sees “x + y” it looks for a method with that name. Similarly it loops for op_Subtraction, op_BitwiseOr, etc.&lt;/p&gt;

&lt;p&gt;Since F# allows you to define symbolic operators (functions with symbols for names) you can overload operators that aren’t valid in C# or VB.NET, for example (==&amp;gt;):&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: green"&gt;// Rotate the vector about the X axis
&lt;/span&gt;&lt;span style="color: blue"&gt;static member &lt;/span&gt;(==&amp;gt;) (vec : Vector, rads : float) =
    &lt;span style="color: blue"&gt;let &lt;/span&gt;(Vector(x,y,z)) = vec
    
    &lt;span style="color: blue"&gt;let &lt;/span&gt;x' = x * cos rads - y * sin rads
    &lt;span style="color: blue"&gt;let &lt;/span&gt;y' = x * sin rads + y * cos rads
    &lt;span style="color: blue"&gt;let &lt;/span&gt;z' = z

    Vector(x', y', z)&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;pre class="code"&gt;&amp;gt; let v = Vector(10.0, 0.0, 0.0);;

val v : Vector = Vector (10.0,0.0,0.0)

&amp;gt; v ==&amp;gt; System.Math.PI;;
val it : Vector = Vector (-10.0,0.0,0.0)&lt;/pre&gt;

&lt;pre class="code"&gt;&amp;gt; v ==&amp;gt; (System.Math.PI / 2.0);;
val it : Vector = Vector (0.0,10.0,0.0)&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;While F# recognizes these symbolic operators, to call them from C# you need to use the ‘long name’ which in the previous example would be op_EqualsEqualsGreater.&lt;/p&gt;

&lt;p&gt;To override the equals operator in C# requires that you define (==), which in turn generate a method called op_Equality. However, defining (==) in F# generates a method called op_EqualsEquals.&lt;/p&gt;

&lt;p&gt;To properly overload the equals and not equals operators in F# you must use the F# operators for equality (=) and (&amp;lt;&amp;gt;).&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: green"&gt;// Equals
&lt;/span&gt;&lt;span style="color: blue"&gt;static member &lt;/span&gt;(=) (lhs, rhs) =
    lhs.Length = rhs.Length

&lt;span style="color: green"&gt;// Not equals
&lt;/span&gt;&lt;span style="color: blue"&gt;static member &lt;/span&gt;(&amp;lt;&amp;gt;) (lhs : Vector, rhs) =
    not (lhs == rhs)&lt;/pre&gt;

&lt;h3&gt;Improper use of Range Expressions&lt;/h3&gt;

&lt;p&gt;Consider the following two loops:&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;for &lt;/span&gt;i &lt;span style="color: blue"&gt;in &lt;/span&gt;[&lt;span style="color: brown"&gt;1 &lt;/span&gt;.. &lt;span style="color: brown"&gt;10000000&lt;/span&gt;] &lt;span style="color: blue"&gt;do
    ...&lt;/span&gt;

&lt;span style="color: blue"&gt;for &lt;/span&gt;i &lt;span style="color: blue"&gt;in &lt;/span&gt;&lt;span style="color: brown"&gt;1 &lt;/span&gt;.. &lt;span style="color: brown"&gt;10000000 &lt;/span&gt;&lt;span style="color: blue"&gt;do
    ...&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;They may not look that different, but they have dramatically different performance profiles. You can find these differences detailed in the recently updated &lt;a href="http://research.microsoft.com/en-us/um/cambridge/projects/fsharp/manual/spec.html"&gt;F# Language Specification&lt;/a&gt;. Both are examples of &lt;a href="http://research.microsoft.com/en-us/um/cambridge/projects/fsharp/manual/spec.html#_Toc245030821"&gt;range expression&lt;/a&gt;, which is a way to create a sequence between to indexes. However, the subtlety here is that the first generates a full list, while the second is just the raw sequence.&lt;/p&gt;

&lt;p&gt;So while one requires ten million memory allocations to generate the list, the second loop doesn’t. More importantly, the compiler can optimize the second loop into a standard for loop over a single integer. (And not need to do any memory allocation at all!)&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9919958" width="1" height="1"&gt;&lt;img src="http://feeds.feedburner.com/~r/ChrisSmithsCompletelyUniqueView/~4/lROrME1WTBY" height="1" width="1"/&gt;</description><feedburner:origLink>http://blogs.msdn.com/chrsmith/archive/2009/11/09/f-language-details-gotchas.aspx</feedburner:origLink></item><item><title>Awesome F# - Decision Trees – Part II</title><link>http://feedproxy.google.com/~r/ChrisSmithsCompletelyUniqueView/~3/b01VUUVDDu0/awesome-f-decision-trees-part-ii.aspx</link><pubDate>Tue, 03 Nov 2009 02:56:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9916536</guid><dc:creator>ChrSmith</dc:creator><slash:comments>2</slash:comments><comments>http://blogs.msdn.com/chrsmith/comments/9916536.aspx</comments><wfw:commentRss>http://blogs.msdn.com/chrsmith/commentrss.aspx?PostID=9916536</wfw:commentRss><description>&lt;p&gt;In my &lt;a href="http://blogs.msdn.com/chrsmith/"&gt;previous post&lt;/a&gt; I went over the theory behind the &lt;a href="http://en.wikipedia.org/wiki/ID3_algorithm"&gt;ID3 algorithm&lt;/a&gt;. Now that we got all that painful math out of the way, let’s write some code! Here is an implementation of the algorithm in F#. (It is also attached to this blog post, download it via the link at the bottom.) &lt;/p&gt;  &lt;pre class="code"&gt;&lt;span style="color: blue"&gt;open &lt;/span&gt;System

&lt;span style="color: blue"&gt;type &lt;/span&gt;Record = 
    {
        Outlook     : string
        Temperature : string
        Humidity    : string
        Wind        : string
        PlayTennis  : bool 
    }

    &lt;span style="color: green"&gt;/// Given an attribute name return its value
    &lt;/span&gt;&lt;span style="color: blue"&gt;member &lt;/span&gt;this.GetAttributeValue(attrName) =
        &lt;span style="color: blue"&gt;match &lt;/span&gt;attrName &lt;span style="color: blue"&gt;with
        &lt;/span&gt;| &lt;span style="color: maroon"&gt;&amp;quot;Outlook&amp;quot;     &lt;/span&gt;&lt;span style="color: blue"&gt;-&amp;gt; &lt;/span&gt;this.Outlook
        | &lt;span style="color: maroon"&gt;&amp;quot;Temperature&amp;quot; &lt;/span&gt;&lt;span style="color: blue"&gt;-&amp;gt; &lt;/span&gt;this.Temperature
        | &lt;span style="color: maroon"&gt;&amp;quot;Humidity&amp;quot;    &lt;/span&gt;&lt;span style="color: blue"&gt;-&amp;gt; &lt;/span&gt;this.Humidity
        | &lt;span style="color: maroon"&gt;&amp;quot;Wind&amp;quot;        &lt;/span&gt;&lt;span style="color: blue"&gt;-&amp;gt; &lt;/span&gt;this.Wind
        | _ &lt;span style="color: blue"&gt;-&amp;gt; &lt;/span&gt;failwithf &lt;span style="color: maroon"&gt;&amp;quot;Invalid attribute name '%s'&amp;quot; &lt;/span&gt;attrName

    &lt;span style="color: green"&gt;/// Make the %o format specifier look all pretty like
    &lt;/span&gt;&lt;span style="color: blue"&gt;override &lt;/span&gt;this.ToString() =
        sprintf
            &lt;span style="color: maroon"&gt;&amp;quot;{Outlook = %s, Temp = %s, Humidity = %s, Wind = %s, PlayTennis = %b}&amp;quot; 
            &lt;/span&gt;this.Outlook
            this.Temperature 
            this.Humidity
            this.Wind
            this.PlayTennis

&lt;span style="color: blue"&gt;type &lt;/span&gt;DecisionTreeNode =
    &lt;span style="color: green"&gt;// Attribute name and value / child node list    
    &lt;/span&gt;| DecisionNode &lt;span style="color: blue"&gt;of &lt;/span&gt;string * (string * DecisionTreeNode) seq
    &lt;span style="color: green"&gt;// Decision and corresponding evidence
    &lt;/span&gt;| Leaf         &lt;span style="color: blue"&gt;of &lt;/span&gt;bool * Record seq

&lt;span style="color: green"&gt;// ----------------------------------------------------------------------------

/// Return the total true, total false, and total count for a set of Records
&lt;/span&gt;&lt;span style="color: blue"&gt;let &lt;/span&gt;countClassifications data = 
    Seq.fold 
        (&lt;span style="color: blue"&gt;fun &lt;/span&gt;(t,f,c) item &lt;span style="color: blue"&gt;-&amp;gt; 
            match &lt;/span&gt;item.PlayTennis &lt;span style="color: blue"&gt;with
            &lt;/span&gt;| &lt;span style="color: blue"&gt;true  -&amp;gt; &lt;/span&gt;(t + &lt;span style="color: brown"&gt;1&lt;/span&gt;, f, c + &lt;span style="color: brown"&gt;1&lt;/span&gt;)
            | &lt;span style="color: blue"&gt;false -&amp;gt; &lt;/span&gt;(t, f + &lt;span style="color: brown"&gt;1&lt;/span&gt;, c + &lt;span style="color: brown"&gt;1&lt;/span&gt;))
        (&lt;span style="color: brown"&gt;0&lt;/span&gt;, &lt;span style="color: brown"&gt;0&lt;/span&gt;, &lt;span style="color: brown"&gt;0&lt;/span&gt;)
        data

&lt;span style="color: green"&gt;// ----------------------------------------------------------------------------

/// Return the theoretical number of bits required to classify the information.
/// If a 50/50 mix, returns 1, if 100% true or false returns 0.
&lt;/span&gt;&lt;span style="color: blue"&gt;let &lt;/span&gt;entropy data = 
    &lt;span style="color: blue"&gt;let &lt;/span&gt;(trueValues, falseValues, totalCount) = countClassifications data        

    &lt;span style="color: blue"&gt;let &lt;/span&gt;probTrue  = (float trueValues)  / (float totalCount)
    &lt;span style="color: blue"&gt;let &lt;/span&gt;probFalse = (float falseValues) / (float totalCount)

    &lt;span style="color: green"&gt;// Log2(1.0) = infinity, short circuiting this part
    &lt;/span&gt;&lt;span style="color: blue"&gt;if &lt;/span&gt;trueValues = totalCount || falseValues = totalCount &lt;span style="color: blue"&gt;then
        &lt;/span&gt;&lt;span style="color: brown"&gt;0.0
    &lt;/span&gt;&lt;span style="color: blue"&gt;else
        &lt;/span&gt;-probTrue * Math.Log(probTrue, &lt;span style="color: brown"&gt;2.0&lt;/span&gt;) + -probFalse * Math.Log(probFalse, &lt;span style="color: brown"&gt;2.0&lt;/span&gt;)

&lt;span style="color: green"&gt;/// Given a set of data, how many bits do you save if you know the provided attribute.
&lt;/span&gt;&lt;span style="color: blue"&gt;let &lt;/span&gt;informationGain (data : Record seq) attr =
    
    &lt;span style="color: green"&gt;// Partition the data into new sets based on each unique value of the given attribute
    // e.g. [ where Outlook = rainy ], [ where Outlook = overcast], [ ... ]
    &lt;/span&gt;&lt;span style="color: blue"&gt;let &lt;/span&gt;divisionsByAttribute = 
        data 
        |&amp;gt; Seq.groupBy(&lt;span style="color: blue"&gt;fun &lt;/span&gt;item &lt;span style="color: blue"&gt;-&amp;gt; &lt;/span&gt;item.GetAttributeValue(attr))

    &lt;span style="color: blue"&gt;let &lt;/span&gt;totalEntropy = entropy data
    &lt;span style="color: blue"&gt;let &lt;/span&gt;entropyBasedOnSplit =
        divisionsByAttribute
        |&amp;gt; Seq.map(&lt;span style="color: blue"&gt;fun &lt;/span&gt;(attributeValue, rowsWithThatValue) &lt;span style="color: blue"&gt;-&amp;gt; 
                        let &lt;/span&gt;ent = entropy rowsWithThatValue
                        &lt;span style="color: blue"&gt;let &lt;/span&gt;percentageOfTotalRows = (float &amp;lt;| Seq.length rowsWithThatValue) / (float &amp;lt;| Seq.length data)
                        -&lt;span style="color: brown"&gt;1.0 &lt;/span&gt;* percentageOfTotalRows * ent)
        |&amp;gt; Seq.sum

    totalEntropy + entropyBasedOnSplit
    
&lt;span style="color: green"&gt;// ----------------------------------------------------------------------------

/// Give a list of attributes left to branch on and training data,
/// construct a decision tree node.
&lt;/span&gt;&lt;span style="color: blue"&gt;let rec &lt;/span&gt;createTreeNode data attributesLeft =
    
    &lt;span style="color: blue"&gt;let &lt;/span&gt;(totalTrue, totalFalse, totalCount) = countClassifications data

    &lt;span style="color: green"&gt;// If we have tested all attributes, then label this node with the 
    // most often occuring instance; likewise if everything has the same value.
    &lt;/span&gt;&lt;span style="color: blue"&gt;if &lt;/span&gt;List.length attributesLeft = &lt;span style="color: brown"&gt;0 &lt;/span&gt;|| totalTrue = &lt;span style="color: brown"&gt;0 &lt;/span&gt;|| totalFalse = &lt;span style="color: brown"&gt;0 &lt;/span&gt;&lt;span style="color: blue"&gt;then
        let &lt;/span&gt;mostOftenOccuring = 
            &lt;span style="color: blue"&gt;if &lt;/span&gt;totalTrue &amp;gt; totalFalse &lt;span style="color: blue"&gt;then true
            else                           false
        &lt;/span&gt;Leaf(mostOftenOccuring, data)
    
    &lt;span style="color: green"&gt;// Otherwise, create a proper decision tree node and branch accordingly
    &lt;/span&gt;&lt;span style="color: blue"&gt;else
        let &lt;/span&gt;attributeWithMostInformationGain =
            attributesLeft 
            |&amp;gt; List.map(&lt;span style="color: blue"&gt;fun &lt;/span&gt;attrName &lt;span style="color: blue"&gt;-&amp;gt; &lt;/span&gt;attrName, (informationGain data attrName))
            |&amp;gt; List.maxBy(&lt;span style="color: blue"&gt;fun &lt;/span&gt;(attrName, infoGain) &lt;span style="color: blue"&gt;-&amp;gt; &lt;/span&gt;infoGain)
            |&amp;gt; fst
        
        &lt;span style="color: blue"&gt;let &lt;/span&gt;remainingAttributes =
            attributesLeft |&amp;gt; List.filter ((&amp;lt;&amp;gt;) attributeWithMostInformationGain)

        &lt;span style="color: green"&gt;// Partition that data base on the attribute's values
        &lt;/span&gt;&lt;span style="color: blue"&gt;let &lt;/span&gt;partitionedData = 
            Seq.groupBy
                (&lt;span style="color: blue"&gt;fun &lt;/span&gt;(r : Record) &lt;span style="color: blue"&gt;-&amp;gt; &lt;/span&gt;r.GetAttributeValue(attributeWithMostInformationGain))
                data

        &lt;span style="color: green"&gt;// Create child nodes
        &lt;/span&gt;&lt;span style="color: blue"&gt;let &lt;/span&gt;childNodes =
            partitionedData
            |&amp;gt; Seq.map (&lt;span style="color: blue"&gt;fun &lt;/span&gt;(attrValue, subData) &lt;span style="color: blue"&gt;-&amp;gt; &lt;/span&gt;attrValue, (createTreeNode subData remainingAttributes))

        DecisionNode(attributeWithMostInformationGain, childNodes)&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;The entropy and informationGain functions were covered in my last post, so let’s walk through how the actual decision tree gets constructed. There’s a little work to calculating the optimal decision tree split, but with F# you can express it quite beautifully.&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;let &lt;/span&gt;attributeWithMostInformationGain =
    attributesLeft 
    |&amp;gt; List.map(&lt;span style="color: blue"&gt;fun &lt;/span&gt;attrName &lt;span style="color: blue"&gt;-&amp;gt; &lt;/span&gt;attrName, (informationGain data attrName))
    |&amp;gt; List.maxBy(&lt;span style="color: blue"&gt;fun &lt;/span&gt;(attrName, infoGain) &lt;span style="color: blue"&gt;-&amp;gt; &lt;/span&gt;infoGain)
    |&amp;gt; fst&lt;/pre&gt;

&lt;p&gt;First, it takes all the potential attributes left to split on…&lt;/p&gt;

&lt;pre class="code"&gt;attributesLeft &lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;… and then maps that attribute name to a new attribute name / information gain tuple …&lt;/p&gt;

&lt;pre class="code"&gt;|&amp;gt; List.map(&lt;span style="color: blue"&gt;fun &lt;/span&gt;attrName &lt;span style="color: blue"&gt;-&amp;gt; &lt;/span&gt;attrName, (informationGain data attrName))&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;… then from the newly generated list, pick out the tuple with the highest information gain …&lt;/p&gt;

&lt;pre class="code"&gt;|&amp;gt; List.maxBy(&lt;span style="color: blue"&gt;fun &lt;/span&gt;(attrName, infoGain) &lt;span style="color: blue"&gt;-&amp;gt; &lt;/span&gt;infoGain)&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;…finally returning the first element of that tuple, which is the attribute with the highest information gain.&lt;/p&gt;

&lt;pre class="code"&gt;|&amp;gt; fst&lt;/pre&gt;

&lt;p&gt;Once you can construct a decision tree in memory, how do get it out? The simplest way is to print it to the console.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/AwesomeFDecisionTreesPartII_84F5/image_2.png"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="image" border="0" alt="image" src="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/AwesomeFDecisionTreesPartII_84F5/image_thumb.png" width="551" height="293" /&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;The code is very straight forward. Note the use of ‘padding parameter’, so that recursive calls get indented more and more. This is a very helpful technique when printing tree-like data structures to the console.&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: green"&gt;/// Print the decision tree to the console
&lt;/span&gt;&lt;span style="color: blue"&gt;let rec &lt;/span&gt;printID3Result indent node =
    &lt;span style="color: blue"&gt;let &lt;/span&gt;padding = &lt;span style="color: blue"&gt;new &lt;/span&gt;System.String(&lt;span style="color: maroon"&gt;' '&lt;/span&gt;, indent)

    &lt;span style="color: blue"&gt;match &lt;/span&gt;node &lt;span style="color: blue"&gt;with
    &lt;/span&gt;| Leaf(classification, data) &lt;span style="color: blue"&gt;-&amp;gt;
        &lt;/span&gt;printfn &lt;span style="color: maroon"&gt;&amp;quot;\tClassification = %b&amp;quot; &lt;/span&gt;classification
        &lt;span style="color: green"&gt;// data |&amp;gt; Seq.iter (fun item -&amp;gt; printfn &amp;quot;%s-&amp;gt;%s&amp;quot; padding &amp;lt;| item.ToString())

    &lt;/span&gt;| DecisionNode(attribute, childNodes) &lt;span style="color: blue"&gt;-&amp;gt;
        &lt;/span&gt;printfn &lt;span style="color: maroon"&gt;&amp;quot;&amp;quot; &lt;/span&gt;&lt;span style="color: green"&gt;// Finish previous line
        &lt;/span&gt;printfn &lt;span style="color: maroon"&gt;&amp;quot;%sBranching on attribute [%s]&amp;quot; &lt;/span&gt;padding attribute
        
        childNodes
        |&amp;gt; Seq.iter (&lt;span style="color: blue"&gt;fun &lt;/span&gt;(attrValue, childNode) &lt;span style="color: blue"&gt;-&amp;gt;
                        &lt;/span&gt;printf &lt;span style="color: maroon"&gt;&amp;quot;%s-&amp;gt;With value [%s]...&amp;quot; &lt;/span&gt;padding attrValue
                        printID3Result (indent + &lt;span style="color: brown"&gt;4&lt;/span&gt;) childNode)&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;However, it’s almost the year 2010. So in lieu of flying cars perhaps we can at least do better than printing data to the console. Ideally, we want to generate some sexy image like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/AwesomeFDecisionTreesPartII_84F5/image_4.png"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="image" border="0" alt="image" src="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/AwesomeFDecisionTreesPartII_84F5/image_thumb_1.png" width="403" height="295" /&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;You &lt;em&gt;could &lt;/em&gt;painstakingly construct the decision tree using &lt;a href="http://office.microsoft.com/en-us/visio/FX100487861033.aspx"&gt;Microsoft Visio&lt;/a&gt; but fortunately there are tools to do this for you. AT&amp;amp;T Research has produced a great tool called &lt;a href="http://www.graphviz.org/"&gt;GraphViz&lt;/a&gt;. While the end result doesn’t quite have &lt;em&gt;sizzle&lt;/em&gt;, it’s very easy enough to get going.&lt;/p&gt;

&lt;p&gt;The following function dumps the decision tree into a format that GraphViz can plot. (Just copy the printed text into the tool and plot it using the default settings.)&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: green"&gt;/// Prints the tree in a format amenable to GraphViz
/// See http://www.graphviz.org/ for more format
&lt;/span&gt;&lt;span style="color: blue"&gt;let &lt;/span&gt;printInGraphVizFormat node =

    &lt;span style="color: blue"&gt;let rec &lt;/span&gt;printNode parentName name node = 
        &lt;span style="color: blue"&gt;match &lt;/span&gt;node &lt;span style="color: blue"&gt;with
        &lt;/span&gt;| DecisionNode(attribute, childNodes) &lt;span style="color: blue"&gt;-&amp;gt;

            &lt;/span&gt;&lt;span style="color: green"&gt;// Print the decision node
            &lt;/span&gt;printfn &lt;span style="color: maroon"&gt;&amp;quot;\&amp;quot;%s\&amp;quot; [ label = \&amp;quot;%s\&amp;quot; ];&amp;quot; &lt;/span&gt;(parentName + name) attribute

            &lt;span style="color: green"&gt;// Print link from parent to this node (unless it's the root)
            &lt;/span&gt;&lt;span style="color: blue"&gt;if &lt;/span&gt;parentName &amp;lt;&amp;gt; &lt;span style="color: maroon"&gt;&amp;quot;&amp;quot; &lt;/span&gt;&lt;span style="color: blue"&gt;then
                &lt;/span&gt;printfn &lt;span style="color: maroon"&gt;&amp;quot;\&amp;quot;%s\&amp;quot; -&amp;gt; \&amp;quot;%s\&amp;quot; [ label = \&amp;quot;%s\&amp;quot; ];&amp;quot; &lt;/span&gt;parentName (parentName + name) name

            childNodes 
            |&amp;gt; Seq.iter(&lt;span style="color: blue"&gt;fun &lt;/span&gt;(attrValue, childNode) &lt;span style="color: blue"&gt;-&amp;gt; 
                    &lt;/span&gt;printNode (parentName + name) attrValue childNode)

        | Leaf(classification, _) &lt;span style="color: blue"&gt;-&amp;gt;
            let &lt;/span&gt;label =
                &lt;span style="color: blue"&gt;match &lt;/span&gt;classification &lt;span style="color: blue"&gt;with
                &lt;/span&gt;| &lt;span style="color: blue"&gt;true  -&amp;gt; &lt;/span&gt;&lt;span style="color: maroon"&gt;&amp;quot;Yes&amp;quot;
                &lt;/span&gt;| &lt;span style="color: blue"&gt;false -&amp;gt; &lt;/span&gt;&lt;span style="color: maroon"&gt;&amp;quot;No&amp;quot;
            
            &lt;/span&gt;&lt;span style="color: green"&gt;// Print the decision node
            &lt;/span&gt;printfn &lt;span style="color: maroon"&gt;&amp;quot;\&amp;quot;%s\&amp;quot; [ label = \&amp;quot;%s\&amp;quot; ];&amp;quot; &lt;/span&gt;(parentName + name) label

            &lt;span style="color: green"&gt;// Print link from parent to this node
            &lt;/span&gt;printfn &lt;span style="color: maroon"&gt;&amp;quot;\&amp;quot;%s\&amp;quot; -&amp;gt; \&amp;quot;%s\&amp;quot; [ label = \&amp;quot;%s\&amp;quot; ];&amp;quot; &lt;/span&gt;parentName (parentName + name) name

    printfn &lt;span style="color: maroon"&gt;&amp;quot;digraph g {&amp;quot;
    &lt;/span&gt;printNode &lt;span style="color: maroon"&gt;&amp;quot;&amp;quot; &amp;quot;root&amp;quot; &lt;/span&gt;node
    printfn &lt;span style="color: maroon"&gt;&amp;quot;}&amp;quot;&lt;/span&gt;&lt;/pre&gt;

&lt;p&gt;So there you have it, ID3 in F#. With a little bit of mathematics and some clever output you can construct decision trees for all your machine learning needs. Think of the ID3 algorithm in the future the next time you want to mine customer transactions, analyze server logs, or program your killer robot to find Sarah Conner.&lt;/p&gt;

&lt;p&gt;&amp;lt;TotallyShamelessPlug&amp;gt; If you would like to learn more about F#, check out &lt;a href="http://www.amazon.com/Programming-Animal-Guide-Chris-Smith/dp/0596153643"&gt;Programming F#&lt;/a&gt; by O’Reilly. Available on &lt;a href="http://www.amazon.com/Programming-Animal-Guide-Chris-Smith/dp/0596153643"&gt;Amazon&lt;/a&gt; and at other fine retailers. &amp;lt;/TotallyShamelessPlug&amp;gt;&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9916536" width="1" height="1"&gt;&lt;img src="http://feeds.feedburner.com/~r/ChrisSmithsCompletelyUniqueView/~4/b01VUUVDDu0" height="1" width="1"/&gt;</description><category domain="http://blogs.msdn.com/chrsmith/archive/tags/F_2300_/default.aspx">F#</category><category domain="http://blogs.msdn.com/chrsmith/archive/tags/Math/default.aspx">Math</category><category domain="http://blogs.msdn.com/chrsmith/archive/tags/Awesome+F_2300_/default.aspx">Awesome F#</category><feedburner:origLink>http://blogs.msdn.com/chrsmith/archive/2009/11/02/awesome-f-decision-trees-part-ii.aspx</feedburner:origLink><enclosure url="http://feedproxy.google.com/~r/ChrisSmithsCompletelyUniqueView/~5/qpV3q6GOLB8/9916536.ashx" length="8544" type="application/fsharp-script" /><feedburner:origEnclosureLink>http://blogs.msdn.com/chrsmith/attachment/9916536.ashx</feedburner:origEnclosureLink></item><item><title>Awesome F# - Decision Trees – Part I</title><link>http://feedproxy.google.com/~r/ChrisSmithsCompletelyUniqueView/~3/ijDQm2lb3qU/awesome-f-decision-trees-part-i.aspx</link><pubDate>Sat, 31 Oct 2009 22:01:20 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9915736</guid><dc:creator>ChrSmith</dc:creator><slash:comments>5</slash:comments><comments>http://blogs.msdn.com/chrsmith/comments/9915736.aspx</comments><wfw:commentRss>http://blogs.msdn.com/chrsmith/commentrss.aspx?PostID=9915736</wfw:commentRss><description>&lt;p&gt;&lt;a href="http://www.amazon.com/Programming-Animal-Guide-Chris-Smith/dp/0596153643"&gt;Programming F#&lt;/a&gt; is out! Meaning you can, and should, go to the store and pick up a copy today. &lt;/p&gt;  &lt;p&gt;&lt;img src="http://t0.gstatic.com/images?q=tbn:jBwkMzLaDw2U-M:http://covers.oreilly.com/images/9780596153656/lrg.jpg" /&gt;&lt;/p&gt;  &lt;p&gt;With&lt;em&gt; Programming F#&lt;/em&gt; serving as a solid guide for the F# Language, I’d like to start posting less about &lt;a href="http://blogs.msdn.com/chrsmith/archive/2008/02/21/Introduction-to-F_2300_-Active-Patterns.aspx"&gt;language&lt;/a&gt; &lt;a href="http://blogs.msdn.com/chrsmith/archive/2009/04/08/f-and-the-pfx-round-1.aspx"&gt;features&lt;/a&gt; and more about applications. That is, what can you &lt;em&gt;do&lt;/em&gt; with this awesome language.&lt;/p&gt;  &lt;p&gt;This is the first blog post in a series titled &lt;strong&gt;Awesome F#&lt;/strong&gt;. These posts will provide advanced, real-world applications of the F# language to do awesome things. This post is about Decision Trees and the &lt;a href="http://en.wikipedia.org/wiki/ID3_algorithm"&gt;ID3 algorithm&lt;/a&gt;, motivated by &lt;a href="http://stackoverflow.com/questions/1418829/help-needed-creating-a-binary-tree-given-truth-table"&gt;this question&lt;/a&gt; on &lt;a href="http://stackoverflow.com"&gt;StackOverflow.com&lt;/a&gt;. &lt;/p&gt;  &lt;p&gt;If you want to learn more about data mining and machine learning &lt;strong&gt;THE BOOK&lt;/strong&gt; you need to get is &lt;a href="http://www.amazon.com/Machine-Learning-Tom-M-Mitchell/dp/0070428077"&gt;&lt;em&gt;Machine Learning&lt;/em&gt; by Tom Mitchell&lt;/a&gt;. I’ll give a warning however, it is the most academically rigorous and dense book I’ve ever read. Seriously, not for the faint of heart!&lt;/p&gt;  &lt;p&gt;&lt;img alt="cover" src="http://www.cs.cmu.edu/~tom/mlbook.gif" width="130" height="194" /&gt;&lt;/p&gt;  &lt;h3&gt;Defining the Problem&lt;/h3&gt;  &lt;p&gt;So what does the ID3 algorithm do? It is a technique for creating decision trees much like the following used for determining whether or not to play tennis. Starting at the topmost node, if the outlook is overcast then you should play tennis. If it is rainy however, you should play tennis only if the wind is weak.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/AwesomeFDecisionTreesPartI_131F5/image_3.png"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="image" border="0" alt="image" src="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/AwesomeFDecisionTreesPartI_131F5/image_thumb.png" width="379" height="281" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;In addition to helping plan your sports activities, decision trees are an easy way to gather &lt;a href="http://en.wikipedia.org/wiki/Business_intelligence"&gt;&lt;strong&gt;&lt;em&gt;business intelligence&lt;/em&gt;&lt;/strong&gt;&lt;/a&gt;. Imagine you run mid-sized paper company in Scranton, Pennsylvania. You have a database filled with IP addresses of people who have visited your site, special deals you’ve offered them on your products, and whether or not they ended up purchasing some paper. &lt;/p&gt;  &lt;p&gt;This is a situation where you want to apply &lt;em&gt;&lt;a href="http://en.wikipedia.org/wiki/Data_mining"&gt;&lt;strong&gt;data mining&lt;/strong&gt;&lt;/a&gt;&lt;strong&gt; &lt;/strong&gt;&lt;/em&gt;to extract meaning from the data. In this case, how to optimize your sales. &lt;/p&gt;  &lt;p&gt;There are many different data mining algorithms based on the type of data you have and what you are looking for. In this blog post I will be covering &lt;a href="http://en.wikipedia.org/wiki/Decision_tree_learning"&gt;&lt;em&gt;&lt;strong&gt;decision trees&lt;/strong&gt;&lt;/em&gt;&lt;/a&gt;, which is a machine learning technique for predicting a &lt;strong&gt;&lt;em&gt;concept &lt;/em&gt;&lt;/strong&gt;based on data. (For example, given a browser session predict if the user will purchase something.)&lt;/p&gt;  &lt;p&gt;More formally: given a set of instances represented as name/value pairs - where the values are discrete - create a decision tree to most accurately classify any new instances. In the example above the name value pairs were Outlook : {Sunny, Rainy, Overcast} and the classification was ‘should you plan tennis’.&lt;/p&gt;  &lt;h3&gt;The Approach&lt;/h3&gt;  &lt;p&gt;The simplest way to do this is to generate tree branches greedily. Given your training data, find the best branch first and then moving on with more specific subsets of rules on reduced data sets. For example, if trying to determine if someone will purchase a product from your website whether or not they are a returning customer is probably the most significant piece of information.&lt;/p&gt;  &lt;p&gt;To find the ‘best split’ we will use an approach known as &lt;em&gt;&lt;strong&gt;&lt;a href="http://www.cs.cmu.edu/afs/cs/Web/People/awm/tutorials/infogain11.pdf"&gt;information again&lt;/a&gt;&lt;/strong&gt;&lt;/em&gt;. But first, let’s look at a concept from information theory called &lt;a href="http://en.wikipedia.org/wiki/Information_entropy"&gt;&lt;em&gt;&lt;strong&gt;entropy&lt;/strong&gt;&lt;/em&gt;&lt;/a&gt;. Imagine you want to create a decision tree to determine if someone is an evil genius. Each datum may contain information such as gender and whether or not they had a Ph.D.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/AwesomeFDecisionTreesPartI_131F5/image_6.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/AwesomeFDecisionTreesPartI_131F5/image_thumb_2.png" width="240" height="270" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;Entropy and information gain are metrics for calculating how much you &lt;em&gt;learned&lt;/em&gt; from taking a given branch. If exactly 50% of evil geniuses are men, then you have learned nothing by branching on gender. (Since the same number of evil geniuses will be on the left side of the tree as the right side of the tree.) However, for determining evil geniuses education is likely very important – since we can assume the majority of evil geniuses have a Ph.D. in malevolence. In that case the decision tree branch is very effective at whittling down the data into a homogenous group: evil genius or not.&lt;/p&gt;  &lt;h3&gt;Enter the Mathematics&lt;/h3&gt;  &lt;p&gt;While information gain and entropy are simple concepts, the math is a bit intimidating. Let’s carry on with the ‘is an evil genius’ predictor using the following data:&lt;/p&gt;  &lt;table border="0" cellspacing="0" cellpadding="0"&gt;&lt;tbody&gt;     &lt;tr&gt;       &lt;td width="68"&gt;&lt;strong&gt;Gender&lt;/strong&gt;&lt;/td&gt;        &lt;td width="83"&gt;&lt;strong&gt;Education&lt;/strong&gt;&lt;/td&gt;        &lt;td width="110"&gt;&lt;strong&gt;Is Evil Genius?&lt;/strong&gt;&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td&gt;Female&lt;/td&gt;        &lt;td&gt;No Ph.D.&lt;/td&gt;        &lt;td&gt;No&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td&gt;Male&lt;/td&gt;        &lt;td&gt;No Ph.D.&lt;/td&gt;        &lt;td&gt;No&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td&gt;Male&lt;/td&gt;        &lt;td&gt;No Ph.D.&lt;/td&gt;        &lt;td&gt;No&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td&gt;Female&lt;/td&gt;        &lt;td&gt;No Ph.D.&lt;/td&gt;        &lt;td&gt;No&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td&gt;Female&lt;/td&gt;        &lt;td&gt;No Ph.D.&lt;/td&gt;        &lt;td&gt;No&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td&gt;Male&lt;/td&gt;        &lt;td&gt;No Ph.D.&lt;/td&gt;        &lt;td&gt;No&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td&gt;Male&lt;/td&gt;        &lt;td&gt;No Ph.D.&lt;/td&gt;        &lt;td&gt;No&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td&gt;Female&lt;/td&gt;        &lt;td&gt;No Ph.D.&lt;/td&gt;        &lt;td&gt;No&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td&gt;Female&lt;/td&gt;        &lt;td&gt;No Ph.D.&lt;/td&gt;        &lt;td&gt;No&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td&gt;&lt;em&gt;Male&lt;/em&gt;&lt;/td&gt;        &lt;td&gt;&lt;em&gt;No Ph.D.&lt;/em&gt;&lt;/td&gt;        &lt;td&gt;&lt;em&gt;Yes&lt;/em&gt;&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td&gt;&lt;em&gt;Male&lt;/em&gt;&lt;/td&gt;        &lt;td&gt;&lt;em&gt;No Ph.D.&lt;/em&gt;&lt;/td&gt;        &lt;td&gt;&lt;em&gt;Yes&lt;/em&gt;&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td&gt;Female&lt;/td&gt;        &lt;td&gt;No Ph.D.&lt;/td&gt;        &lt;td&gt;No&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td&gt;Female&lt;/td&gt;        &lt;td&gt;No Ph.D.&lt;/td&gt;        &lt;td&gt;No&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td&gt;Male&lt;/td&gt;        &lt;td&gt;No Ph.D.&lt;/td&gt;        &lt;td&gt;No&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td&gt;Male&lt;/td&gt;        &lt;td&gt;No Ph.D.&lt;/td&gt;        &lt;td&gt;No&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td&gt;Female&lt;/td&gt;        &lt;td&gt;No Ph.D.&lt;/td&gt;        &lt;td&gt;No&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td&gt;Female&lt;/td&gt;        &lt;td&gt;No Ph.D.&lt;/td&gt;        &lt;td&gt;No&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td&gt;Male&lt;/td&gt;        &lt;td&gt;No Ph.D.&lt;/td&gt;        &lt;td&gt;No&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td&gt;Male&lt;/td&gt;        &lt;td&gt;No Ph.D.&lt;/td&gt;        &lt;td&gt;No&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td&gt;Female&lt;/td&gt;        &lt;td&gt;No Ph.D.&lt;/td&gt;        &lt;td&gt;No&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td&gt;Female&lt;/td&gt;        &lt;td&gt;No Ph.D.&lt;/td&gt;        &lt;td&gt;No&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td&gt;Male&lt;/td&gt;        &lt;td&gt;No Ph.D.&lt;/td&gt;        &lt;td&gt;No&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td&gt;Male&lt;/td&gt;        &lt;td&gt;No Ph.D.&lt;/td&gt;        &lt;td&gt;No&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td&gt;Female&lt;/td&gt;        &lt;td&gt;No Ph.D.&lt;/td&gt;        &lt;td&gt;No&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td&gt;Female&lt;/td&gt;        &lt;td&gt;No Ph.D.&lt;/td&gt;        &lt;td&gt;No&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td&gt;&lt;em&gt;Male&lt;/em&gt;&lt;/td&gt;        &lt;td&gt;&lt;em&gt;Ph.D.&lt;/em&gt;&lt;/td&gt;        &lt;td&gt;&lt;em&gt;Yes&lt;/em&gt;&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td&gt;&lt;em&gt;Male&lt;/em&gt;&lt;/td&gt;        &lt;td&gt;&lt;em&gt;Ph.D.&lt;/em&gt;&lt;/td&gt;        &lt;td&gt;&lt;em&gt;Yes&lt;/em&gt;&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td&gt;&lt;em&gt;Female&lt;/em&gt;&lt;/td&gt;        &lt;td&gt;&lt;em&gt;Ph.D.&lt;/em&gt;&lt;/td&gt;        &lt;td&gt;&lt;em&gt;Yes&lt;/em&gt;&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td&gt;&lt;em&gt;Female&lt;/em&gt;&lt;/td&gt;        &lt;td&gt;&lt;em&gt;Ph.D.&lt;/em&gt;&lt;/td&gt;        &lt;td&gt;&lt;em&gt;Yes&lt;/em&gt;&lt;/td&gt;     &lt;/tr&gt;      &lt;tr&gt;       &lt;td&gt;Male&lt;/td&gt;        &lt;td&gt;Ph.D.&lt;/td&gt;        &lt;td&gt;No&lt;/td&gt;     &lt;/tr&gt;   &lt;/tbody&gt;&lt;/table&gt;  &lt;h4&gt;Entropy&lt;/h4&gt;  &lt;p&gt;Given a set of data, S, which can be divided c ways with the probability of each division being p the entropy of that set is given by:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/AwesomeFDecisionTreesPartI_131F5/clip_image002_2.gif"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="clip_image002" border="0" alt="clip_image002" src="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/AwesomeFDecisionTreesPartI_131F5/clip_image002_thumb.gif" width="186" height="51" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;For example, if out of a set of six evil geniuses only four are men what is the entropy of that set?&lt;/p&gt;  &lt;p&gt;&lt;a href="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/AwesomeFDecisionTreesPartI_131F5/clip_image002%5B16%5D.gif"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="clip_image002[16]" border="0" alt="clip_image002[16]" src="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/AwesomeFDecisionTreesPartI_131F5/clip_image002%5B16%5D_thumb.gif" width="200" height="36" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Or 0.9182. Now, if out of that set of five people with Ph.D.s, four were evil geniuses. What is the entropy there?&lt;/p&gt;  &lt;p&gt;&lt;a href="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/AwesomeFDecisionTreesPartI_131F5/clip_image002%5B18%5D.gif"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="clip_image002[18]" border="0" alt="clip_image002[18]" src="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/AwesomeFDecisionTreesPartI_131F5/clip_image002%5B18%5D_thumb.gif" width="200" height="36" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;Or 0.6883. That lower number means that it requires less information to encode that the evil geniuses of the log have a Ph.D. If you run the math for entropy, it will be zero when everything in a set has the same type and exactly 1 when its a 50/50 split. Looking something like this:&lt;/p&gt;  &lt;p&gt;&lt;img src="http://www2.wolframalpha.com/Calculate/MSP/MSP23851982e45a932e00f500004864hbh23hb56gf3?MSPStoreType=image/gif&amp;amp;s=9" /&gt;&lt;/p&gt;  &lt;p&gt;(Image generated from &lt;a href="http://www.wolframalpha.com/input/?i=graph+y%3D-x+*+log(2,+x)+%2B+-(1-x)+*+log(2,+(1-x))+from+0+to+1"&gt;Wolfram Alpha&lt;/a&gt;.)&lt;/p&gt;  &lt;p&gt;So the entropy for a homogenous set is lower than that of a mixed set. This is important because in our decision tree we want to narrow the data into more specific values – so we can make predictions more accurately.&lt;/p&gt;  &lt;h4&gt;Information Gain&lt;/h4&gt;  &lt;p&gt;Now that we know how to measure how homogenous a set of data is, how do we go about deciding the best attribute to branch on? That is, do we branch on gender, has a Ph.D., or some other attribute? To calculate this we can use the &lt;em&gt;&lt;strong&gt;information gain &lt;/strong&gt;&lt;/em&gt;function defined as:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/AwesomeFDecisionTreesPartI_131F5/clip_image002%5B12%5D.gif"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="clip_image002[12]" border="0" alt="clip_image002[12]" src="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/AwesomeFDecisionTreesPartI_131F5/clip_image002%5B12%5D_thumb.gif" width="364" height="49" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Given a set of values, S, and an attribute of each datum in that set, A, determine how much information has been gained by branching on that attribute. Note that Sv is the subset of values S where each element has attribute value v.&lt;/p&gt;  &lt;p&gt;So what is the information gained by putting our root branch at ‘has a Ph.D'.’ or not?&lt;/p&gt;  &lt;p&gt;&lt;a href="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/AwesomeFDecisionTreesPartI_131F5/clip_image002%5B1%5D.gif"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="clip_image002[1]" border="0" alt="clip_image002[1]" src="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/AwesomeFDecisionTreesPartI_131F5/clip_image002%5B1%5D_thumb.gif" width="633" height="43" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&lt;a href="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/AwesomeFDecisionTreesPartI_131F5/clip_image002%5B3%5D.gif"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="clip_image002[3]" border="0" alt="clip_image002[3]" src="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/AwesomeFDecisionTreesPartI_131F5/clip_image002%5B3%5D_thumb.gif" width="271" height="34" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Or 0.2002. If we calculated the information gain from branching on gender, the result is –0.0513. So the math backs up our assertion that Ph.D. is a more significant factor in determining evil genius than gender. (Which makes sense since 4/5ths of the Ph.D.s are evil, whereas only 2/25ths of the non Ph.D.s are evil.)&lt;/p&gt;  &lt;p&gt;Putting it Together&lt;/p&gt;  &lt;p&gt;In Part II we’ll implement the ID3 algorithm in F#, which generally goes through the following process:&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;Find the attribute that leads to the most information gain.&lt;/li&gt;    &lt;li&gt;Add a branch for that attribute.&lt;/li&gt;    &lt;li&gt;For each child node, repeat until all the data have the same classification.&lt;/li&gt; &lt;/ol&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9915736" width="1" height="1"&gt;&lt;img src="http://feeds.feedburner.com/~r/ChrisSmithsCompletelyUniqueView/~4/ijDQm2lb3qU" height="1" width="1"/&gt;</description><category domain="http://blogs.msdn.com/chrsmith/archive/tags/Machine+Learning/default.aspx">Machine Learning</category><category domain="http://blogs.msdn.com/chrsmith/archive/tags/Awesome+F_2300_/default.aspx">Awesome F#</category><feedburner:origLink>http://blogs.msdn.com/chrsmith/archive/2009/10/31/awesome-f-decision-trees-part-i.aspx</feedburner:origLink></item><item><title>Upcoming F# Talks</title><link>http://feedproxy.google.com/~r/ChrisSmithsCompletelyUniqueView/~3/e-2sJiUgcro/upcoming-f-talks.aspx</link><pubDate>Thu, 15 Oct 2009 23:05:37 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9907882</guid><dc:creator>ChrSmith</dc:creator><slash:comments>2</slash:comments><comments>http://blogs.msdn.com/chrsmith/comments/9907882.aspx</comments><wfw:commentRss>http://blogs.msdn.com/chrsmith/commentrss.aspx?PostID=9907882</wfw:commentRss><description>&lt;p&gt;Recently legendary Cambridge research Don Syme presented an &lt;a href="http://blogs.msdn.com/dsyme/archive/2009/10/10/f-tutorial-code-and-slides-jaoo-2009-edition.aspx"&gt;Introduction to F#&lt;/a&gt; at &lt;a href="http://jaoo.dk/aarhus-2009/"&gt;JAOO Aarhus&lt;/a&gt; in Denmark. From what I’ve heard the talk went really well, and the slide deck is a great way to pick up the F# language (or give an intro-level presentation yourself). I figured I’d point out some other upcoming F# talks I’ll be giving as well:&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Nov 17-19, &lt;/strong&gt;&lt;a href="http://microsoftpdc.com/"&gt;&lt;strong&gt;Platform Developers Conference (PDC)&lt;/strong&gt;&lt;/a&gt;&lt;strong&gt;, Los Angeles&lt;/strong&gt;&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;I’ll be at PDC this year, but unfortunately I won’t be giving any talks. You’ll find me manning the Visual Studio 2010 booth talking about what’s going on in the languages space: talking about &lt;a href="http://channel9.msdn.com/posts/mike+ormond/C-40-New-Features-COM-Interop-Enhancements/"&gt;new features in C#&lt;/a&gt;, &lt;a href="http://msdn.microsoft.com/en-us/library/we86c8x2(VS.100).aspx"&gt;Visual Basic.NET&lt;/a&gt;, and &lt;a href="http://fsharp.net/"&gt;what to expect in F#&lt;/a&gt;, in addition to plugging &lt;a href="http://www.ironruby.net/About"&gt;Iron Ruby&lt;/a&gt; and &lt;a href="http://www.codeplex.com/IronPython"&gt;Iron Python&lt;/a&gt;. &lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;&lt;strong&gt;Nov 21-22, &lt;/strong&gt;&lt;a href="http://www.socalcodecamp.com/default.aspx"&gt;&lt;strong&gt;SoCal Code Camp&lt;/strong&gt;&lt;/a&gt;&lt;strong&gt;, Los Angeles&lt;/strong&gt;&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;The weekend after PDC I’ll be giving the same &lt;a href="http://blogs.msdn.com/chrsmith/archive/2009/08/20/f-for-architects-hitting-the-sweet-spot.aspx"&gt;F# for Architects&lt;/a&gt; talk, though with some updated slides and 50% more &lt;em&gt;sizzle&lt;/em&gt;. If you are in the LA area I’d encourage you to stop by.&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;&lt;strong&gt;Jan 13-15, &lt;/strong&gt;&lt;a href="http://codemash.org/"&gt;&lt;strong&gt;CodeMash&lt;/strong&gt;&lt;/a&gt;&lt;strong&gt;, Sandusky Ohio&lt;/strong&gt;&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;My talk &lt;a href="http://codemash.org/Sessions#Being+an+Evil+Genius+with+F%23+and+.NET"&gt;Being an Evil Genius with F# and .NET&lt;/a&gt; was accepted and as you can tell from the abstract, I am super excited about giving the presentation. CodeMash is an awesome conference, and indoors at the Kalahari resort in Sandusky is absolutely where you want to be on a cold week in January.&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;In other news, the F# team is still plugging away trying to finish up Visual Studio 2010. We’ll have some announcements coming soon, but in the mean time the latest release of F# can is &lt;a href="http://www.microsoft.com/downloads/details.aspx?FamilyID=7bb32f32-9fac-4f34-ad56-b0bda130cf00&amp;amp;displaylang=en"&gt;May 2009 CTP&lt;/a&gt; or &lt;a href="http://msdn.microsoft.com/en-us/vstudio/dd582936.aspx"&gt;Visual Studio 2010 Beta1&lt;/a&gt;. And, perhaps more importantly ;) &lt;a href="http://oreilly.com/catalog/9780596153656"&gt;Programming F#&lt;/a&gt; is finally out! It’s so out that I have a copy of the book on my desk in front of me right now. I’d love to start a book tour, so if any of you know how to get me 10 minutes on the &lt;a href="http://today.msnbc.msn.com/"&gt;Today Show&lt;/a&gt; let me know.&lt;/p&gt;  &lt;p&gt;Cheers!&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9907882" width="1" height="1"&gt;&lt;img src="http://feeds.feedburner.com/~r/ChrisSmithsCompletelyUniqueView/~4/e-2sJiUgcro" height="1" width="1"/&gt;</description><category domain="http://blogs.msdn.com/chrsmith/archive/tags/F_2300_/default.aspx">F#</category><category domain="http://blogs.msdn.com/chrsmith/archive/tags/Shameless+Plugs/default.aspx">Shameless Plugs</category><category domain="http://blogs.msdn.com/chrsmith/archive/tags/Community/default.aspx">Community</category><feedburner:origLink>http://blogs.msdn.com/chrsmith/archive/2009/10/15/upcoming-f-talks.aspx</feedburner:origLink></item><item><title>Grotesque F# Code - I</title><link>http://feedproxy.google.com/~r/ChrisSmithsCompletelyUniqueView/~3/FTDRnqqrEbc/grotesque-f-code-i.aspx</link><pubDate>Mon, 14 Sep 2009 07:12:03 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9894809</guid><dc:creator>ChrSmith</dc:creator><slash:comments>8</slash:comments><comments>http://blogs.msdn.com/chrsmith/comments/9894809.aspx</comments><wfw:commentRss>http://blogs.msdn.com/chrsmith/commentrss.aspx?PostID=9894809</wfw:commentRss><description>&lt;p&gt;Recently a friend came to me in a mild panic about some massive refactoring he needed to do to an F# code base. The code he had was very complicated and maintenance was a pain. After only a few seconds scanning through the code I certainly could see that the code was more complicated than it needed to be, in fact I would even go so far as to say it was &lt;a href="http://dictionary.reference.com/browse/grotesque"&gt;grotesque&lt;/a&gt;.&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;Odd or unnatural in shape, appearance, or character; fantastically ugly or absurd; bizarre.&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;Note that I didn’t say terrible or wrong. The code he showed me did exactly what it was supposed to do. But it was non-idomatic; so any seasoned F# developer would probably cringe when looking at it. The point of this blog post isn’t to criticize any F# code out in the wild, but rather just show how using functional programming can simplify your code.&lt;/p&gt;  &lt;p&gt;Here is one of the most grievous sections of the code he showed me. Essentially it takes a list of data and produces a new list after ‘processing’ each element. (Obviously with the method names and parameters renamed.)&lt;/p&gt;  &lt;pre class="code"&gt;&lt;span style="color: green"&gt;// The original code
&lt;/span&gt;&lt;span style="color: blue"&gt;let &lt;/span&gt;computeStuff x y z = &lt;span style="color: green"&gt;(* ... *) &lt;/span&gt;()

&lt;span style="color: blue"&gt;let rec &lt;/span&gt;analyzeStuff paramX paramY listOfData =
    &lt;span style="color: blue"&gt;match &lt;/span&gt;listOfData &lt;span style="color: blue"&gt;with
    &lt;/span&gt;| [] 
        &lt;span style="color: blue"&gt;-&amp;gt; &lt;/span&gt;[]
    | hd :: tl 
        &lt;span style="color: blue"&gt;-&amp;gt; 
            &lt;/span&gt;[ 
                computeStuff paramX paramY hd 
            ] @ analyzeStuff paramX paramY tl&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Eliminating Unnecessary Parameters&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The first thing to point out is that the function’s parameters paramX and paramY are being passed directly to the computeStuff function and otherwise aren’t even used by this function. So why keep them around? Having additional function parameters only makes it a little more confusing. Using &lt;a href="http://blogs.msdn.com/ericlippert/archive/2009/06/25/mmm-curry.aspx"&gt;function currying&lt;/a&gt; you can eliminate those parameters by simply passing in a function that only accepts one argument. (And currying the rest as necessary.)&lt;/p&gt;

&lt;p&gt;You can rewrite the analyzeStuff method like follows. The analyzeStuff2 function only takes two parameters now, f – the function for processing – and the list of data.&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: green"&gt;// Eliminating unnecessary parameters
&lt;/span&gt;&lt;span style="color: blue"&gt;let rec &lt;/span&gt;analyzeStuff2 f listOfData =
    &lt;span style="color: blue"&gt;match &lt;/span&gt;listOfData &lt;span style="color: blue"&gt;with
    &lt;/span&gt;| [] 
        &lt;span style="color: blue"&gt;-&amp;gt; &lt;/span&gt;[]
    | hd :: tl 
        &lt;span style="color: blue"&gt;-&amp;gt; 
            &lt;/span&gt;[ 
                f hd 
            ] @ analyzeStuff2 f tl&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;And then, simply pass in a curried version of computeStuff. This allows you to reuse the analyzeStuff method and perhaps operate on different functions (rather than hard coding it to call computeStuff).&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: green"&gt;// Pass in a curried function
&lt;/span&gt;analyzeStuff2 (computeStuff paramX paramY)&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;The fact that there were unnecessary parameters to the function isn’t what, in my mind, made the code so bad. There were a couple of other idiomatic F# things that stuck out…&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Prefer Cons instead of Append&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;As I’ve mentioned in a previous post, &lt;a href="http://blogs.msdn.com/chrsmith/archive/2008/07/10/mastering-f-lists.aspx"&gt;cons (::) is fast and append (@) is slow&lt;/a&gt;. I mean, if Dustin Campbell has &lt;a href="http://diditwith.net/2008/03/03/WhyILoveFListsTheBasics.aspx"&gt;posted&lt;/a&gt; about it is common knowledge, right? ;)&lt;/p&gt;

&lt;p&gt;Think for a moment about what the following code actually does:&lt;/p&gt;

&lt;pre class="code"&gt;[ f hd ] @ analyzeStuff2 f tl&lt;/pre&gt;

&lt;p&gt;If your answer was ‘more than it needs to’ you would be correct.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Create a new, one element list via ‘[ f hd ]’ &lt;/li&gt;

  &lt;li&gt;Make a copy of that entire list via ‘ @ ‘ &lt;/li&gt;

  &lt;li&gt;Set the last element’s next pointer to the result of ‘analyzeStuff2 f tl’ (via the rest of the append) &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The problem lies in bullet number 2. You create a list only to create a second, identical list so you can use append on it. If you want to put exactly one element in the front of the rest of the list use cons. Which brings us to the following code snippet, which is slightly more performant than analyzeStuff2.&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: green"&gt;// Eliminating unnecessary append
&lt;/span&gt;&lt;span style="color: blue"&gt;let rec &lt;/span&gt;analyzeStuff3 f listOfData =
    &lt;span style="color: blue"&gt;match &lt;/span&gt;listOfData &lt;span style="color: blue"&gt;with
    &lt;/span&gt;| [] 
        &lt;span style="color: blue"&gt;-&amp;gt; &lt;/span&gt;[]
    | hd :: tl 
        &lt;span style="color: blue"&gt;-&amp;gt; &lt;/span&gt;(f hd) :: analyzeStuff3 f tl&lt;/pre&gt;

&lt;p&gt;So while we have trimmed off a few characters and eliminated a few unnecessary memory allocations, there is still one final, significant problem with this code.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Using the F# Library Where Possible&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Remember the whole purpose of the analyzeStuff method? It was to take a list of data and produce a new list of data after ‘processing’ each element. In other words, mapping a function to each element of the input list. This function may sound familiar – it is already built into the F# library and is called List.map. So we can remove the analyzeStuff function entirely, in lieu of just using what is already baked into the F# library.&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: green"&gt;// Final code
&lt;/span&gt;&lt;span style="color: blue"&gt;let &lt;/span&gt;results = List.map (computeStuff paramX paramY) listOfData&lt;/pre&gt;

&lt;p&gt;The moral of the story is that if your code seems more complicated than it needs to be, then it probably is. However, once &lt;a href="http://www.amazon.com/Programming-Animal-Guide-Chris-Smith/dp/0596153643"&gt;my book&lt;/a&gt; comes out there will be no excuse for writing grotesque F# code in the future ;)&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9894809" width="1" height="1"&gt;&lt;img src="http://feeds.feedburner.com/~r/ChrisSmithsCompletelyUniqueView/~4/FTDRnqqrEbc" height="1" width="1"/&gt;</description><category domain="http://blogs.msdn.com/chrsmith/archive/tags/F_2300_/default.aspx">F#</category><category domain="http://blogs.msdn.com/chrsmith/archive/tags/F_2300_+Design/default.aspx">F# Design</category><category domain="http://blogs.msdn.com/chrsmith/archive/tags/Grotesque+F_2300_/default.aspx">Grotesque F#</category><feedburner:origLink>http://blogs.msdn.com/chrsmith/archive/2009/09/13/grotesque-f-code-i.aspx</feedburner:origLink></item><item><title>F# for Architects: Hitting the sweet spot</title><link>http://feedproxy.google.com/~r/ChrisSmithsCompletelyUniqueView/~3/_jNFcsdVq8w/f-for-architects-hitting-the-sweet-spot.aspx</link><pubDate>Fri, 21 Aug 2009 06:07:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9878185</guid><dc:creator>ChrSmith</dc:creator><slash:comments>4</slash:comments><comments>http://blogs.msdn.com/chrsmith/comments/9878185.aspx</comments><wfw:commentRss>http://blogs.msdn.com/chrsmith/commentrss.aspx?PostID=9878185</wfw:commentRss><description>&lt;P mce_keep="true"&gt;When I was at &lt;A href="http://www.devlink.net/Default.aspx" mce_href="http://www.devlink.net/Default.aspx"&gt;DevLink&lt;/A&gt; last week I gave a talk designed to specifically identify why and when you should use F#. I was going to post the slides, but then I realized that they are in the form of a ‘presentation deck’ rather than a ‘reading deck’. So rather than having a few vague slogans and images in a .pptx file, I’ve transcribed my talking points. So imagine a deep and sexy voice narrating this blog post aloud. I’ve indicated where I ‘break character’ in the transcription.&lt;/P&gt;
&lt;P&gt;---------------------------------------------&lt;/P&gt;
&lt;P&gt;&lt;A href="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/FforArchitectsHittingthesweetspot_138C8/Slide1.png" mce_href="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/FforArchitectsHittingthesweetspot_138C8/Slide1.png"&gt;&lt;IMG style="BORDER-RIGHT-WIDTH: 0px; DISPLAY: inline; BORDER-TOP-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px" title=Slide1 border=0 alt=Slide1 src="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/FforArchitectsHittingthesweetspot_138C8/Slide1_thumb.png" width=334 height=252 mce_src="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/FforArchitectsHittingthesweetspot_138C8/Slide1_thumb.png"&gt;&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;Hello, my name is Chris Smith and I work at Microsoft on the F# team.&lt;/P&gt;
&lt;P&gt;&lt;A href="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/FforArchitectsHittingthesweetspot_138C8/Slide2.png" mce_href="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/FforArchitectsHittingthesweetspot_138C8/Slide2.png"&gt;&lt;IMG style="BORDER-RIGHT-WIDTH: 0px; DISPLAY: inline; BORDER-TOP-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px" title=Slide2 border=0 alt=Slide2 src="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/FforArchitectsHittingthesweetspot_138C8/Slide2_thumb.png" width=334 height=252 mce_src="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/FforArchitectsHittingthesweetspot_138C8/Slide2_thumb.png"&gt;&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;&lt;I&gt;[Ed. I wish every talk started with a slide like this.]&lt;/I&gt;&lt;/P&gt;
&lt;P&gt;Of all the talks I’m giving at DevLink, this is the one I am looking forward to the most. This talk is really the one people should be giving at conferences. There certainly is a lot of excitement surrounding F#, but the question on most people’s minds is &lt;I&gt;does it matter to &lt;B&gt;me&lt;/B&gt;&lt;/I&gt;? I think we can assume that F# has to be good at &lt;I&gt;something&lt;/I&gt;, because it if it wasn’t why would Microsoft be spending so much time and energy putting it into Visual Studio 2010?&lt;/P&gt;
&lt;P&gt;So this talk is about removing some of the excitement associated with your typical F# talk and just deal in facts. My goal isn’t to convince you to start programming in F#, but instead articulate what the language is good at so you can decide for yourself if F# is worth looking into.&lt;/P&gt;
&lt;P&gt;If you’re super-happy writing C# or VB.NET code then you really have no reason to learn F#. Just keep on being happy ;) But if you find yourself struggling to write your .NET code, then perhaps F# is what you’ve been waiting for.&lt;/P&gt;
&lt;P&gt;&lt;A href="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/FforArchitectsHittingthesweetspot_138C8/Slide3.png" mce_href="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/FforArchitectsHittingthesweetspot_138C8/Slide3.png"&gt;&lt;IMG style="BORDER-RIGHT-WIDTH: 0px; DISPLAY: inline; BORDER-TOP-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px" title=Slide3 border=0 alt=Slide3 src="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/FforArchitectsHittingthesweetspot_138C8/Slide3_thumb.png" width=334 height=252 mce_src="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/FforArchitectsHittingthesweetspot_138C8/Slide3_thumb.png"&gt;&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;Let’s begin with some &lt;A href="http://meta.stackoverflow.com/questions/9134/jon-skeet-facts" mce_href="http://meta.stackoverflow.com/questions/9134/jon-skeet-facts"&gt;F# Facts&lt;/A&gt;:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;&lt;B&gt;False&lt;/B&gt;. F# isn’t going to replace C# or VB, ever. F# is just different, so it makes some things easier and some things harder. But the point is that with F# you have a choice – and this talk is about highlighting some of the situations where F# may make more sense than C#. &lt;/LI&gt;
&lt;LI&gt;&lt;B&gt;False&lt;/B&gt;. While F# (and other functional languages) make it easier to parallelize your code, it doesn’t do it for free. In fact, you can write the same deadlocks and race conditions in F# than you can in C#. Just in F# is that you have to point the gun at your foot first. &lt;/LI&gt;
&lt;LI&gt;&lt;B&gt;False&lt;/B&gt;. Functional programming is enjoying a lot of attention these days with new languages like Erlang, Scala, Nemerle, Haskell, etc. However the core ideas of functional programming have been around for quite some time without ever ‘making it big’. I don’t see functional programming becoming the &lt;I&gt;one true paradigm&lt;/I&gt; that everyone will switch to. Rather, I see it as a great way for solving a specific class of problems.&amp;nbsp; F# is a hybrid language, so it allows you to write code in the paradigm that makes the most sense for the problem at hand.&lt;/LI&gt;
&lt;LI&gt;&lt;B&gt;True&lt;/B&gt;. Absolutely. &lt;/LI&gt;
&lt;LI&gt;&lt;B&gt;False&lt;/B&gt;. In the keynote at DevLink &lt;A href="http://www.joshholmes.com/" mce_href="http://www.joshholmes.com/"&gt;Josh Holmes&lt;/A&gt; specifically called this out as being a bad idea. Not to say that F# + ASP.NET isn’t a good idea, but that using new technologies for the sake of using new technologies makes things harder than they have to be. &lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;Bottom line is this: you should learn what F# is about, and if you’ll be more productive using it then do so. Otherwise, go with what you know.&lt;/P&gt;
&lt;P&gt;&lt;A href="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/FforArchitectsHittingthesweetspot_138C8/Slide4.png" mce_href="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/FforArchitectsHittingthesweetspot_138C8/Slide4.png"&gt;&lt;IMG style="BORDER-RIGHT-WIDTH: 0px; DISPLAY: inline; BORDER-TOP-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px" title=Slide4 border=0 alt=Slide4 src="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/FforArchitectsHittingthesweetspot_138C8/Slide4_thumb.png" width=334 height=252 mce_src="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/FforArchitectsHittingthesweetspot_138C8/Slide4_thumb.png"&gt;&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;&lt;I&gt;[Ed. This slide’s pretty self-explanatory.]&lt;/I&gt;&lt;/P&gt;
&lt;P&gt;&lt;A href="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/FforArchitectsHittingthesweetspot_138C8/Slide5.png" mce_href="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/FforArchitectsHittingthesweetspot_138C8/Slide5.png"&gt;&lt;IMG style="BORDER-RIGHT-WIDTH: 0px; DISPLAY: inline; BORDER-TOP-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px" title=Slide5 border=0 alt=Slide5 src="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/FforArchitectsHittingthesweetspot_138C8/Slide5_thumb.png" width=334 height=252 mce_src="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/FforArchitectsHittingthesweetspot_138C8/Slide5_thumb.png"&gt;&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;&lt;B&gt;Language&lt;/B&gt;&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;As I mentioned before, F# is a multi-paradigm language. You can write functional, imperative, and object-oriented code in it. This allows you to be pragmatic instead of trying to constrain every problem you see into classes and interfaces.&lt;/LI&gt;
&lt;LI&gt;F# is a type inferred language, leading to succinct programs. Think of how much time you spend adding type signatures, semicolons, and curly braces to your favorite programming language. All that information is just a crutch for making it easier to write the compiler. Why not write just the code you want and let the compiler figure out the rest? You’ll see later why I think F#’s succinctness is it’s greatest strength.&lt;/LI&gt;
&lt;LI&gt;F# is a .NET programming language. It compiles down to IL and the same runtime as C# and VB. So F# will ‘just work’ with your existing .NET code and have the same performance profile as C#.&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;&lt;B&gt;Tools&lt;/B&gt;&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;F# will be ‘in the box’ for Visual Studio 2010,but is also available now as an add-in for Visual Studio 2008. &lt;/LI&gt;
&lt;LI&gt;It features a REPL like Ruby and Python, called the F# Interactive window -&amp;nbsp; you’ll see that in action shortly. &lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;It’s easy to get overwhelmed with all the details of a new programming language. The one thing I want you to remember about F# as a whole is that it is &lt;B&gt;&lt;I&gt;fun&lt;/I&gt;&lt;/B&gt;. F# eliminates a lot of the hassles associated with programming allows you to focus on just writing the code you care about. &lt;/P&gt;
&lt;P&gt;&lt;A href="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/FforArchitectsHittingthesweetspot_138C8/Slide6.png" mce_href="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/FforArchitectsHittingthesweetspot_138C8/Slide6.png"&gt;&lt;IMG style="BORDER-RIGHT-WIDTH: 0px; DISPLAY: inline; BORDER-TOP-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px" title=Slide6 border=0 alt=Slide6 src="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/FforArchitectsHittingthesweetspot_138C8/Slide6_thumb.png" width=334 height=252 mce_src="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/FforArchitectsHittingthesweetspot_138C8/Slide6_thumb.png"&gt;&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;&lt;I&gt;[Ed. This is the part where I give a quick demo of F# in Visual Studio. The main features are:&lt;/I&gt;&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;&lt;I&gt;Creating new projects &lt;/I&gt;&lt;/LI&gt;
&lt;LI&gt;&lt;I&gt;The F# Intellisense experience &lt;/I&gt;&lt;/LI&gt;
&lt;UL&gt;
&lt;LI&gt;&lt;I&gt;Hovering over a local value shows its type information&lt;/I&gt;&lt;/LI&gt;&lt;/UL&gt;
&lt;LI&gt;&lt;I&gt;The F# Interactive window &lt;/I&gt;&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;&lt;I&gt;]&lt;/I&gt;&lt;/P&gt;
&lt;P&gt;&lt;A href="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/FforArchitectsHittingthesweetspot_138C8/Slide7.png" mce_href="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/FforArchitectsHittingthesweetspot_138C8/Slide7.png"&gt;&lt;IMG style="BORDER-RIGHT-WIDTH: 0px; DISPLAY: inline; BORDER-TOP-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px" title=Slide7 border=0 alt=Slide7 src="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/FforArchitectsHittingthesweetspot_138C8/Slide7_thumb.png" width=334 height=252 mce_src="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/FforArchitectsHittingthesweetspot_138C8/Slide7_thumb.png"&gt;&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;It is important to note that F# supports nearly every feature that C# does. So when you use F# it isn’t an all-or-nothing type of proposition. You don’t have to throw away your existing code and move everything over to F#. In fact, we expect F# code to primarily be used as a class library integrated into a larger software package. Perhaps some backend server component is written in F# while the rest of your code remains in C#/PHP/Smoke Signals/whatever.&lt;/P&gt;
&lt;P&gt;&lt;A href="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/FforArchitectsHittingthesweetspot_138C8/Slide8.png" mce_href="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/FforArchitectsHittingthesweetspot_138C8/Slide8.png"&gt;&lt;IMG style="BORDER-RIGHT-WIDTH: 0px; DISPLAY: inline; BORDER-TOP-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px" title=Slide8 border=0 alt=Slide8 src="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/FforArchitectsHittingthesweetspot_138C8/Slide8_thumb.png" width=334 height=252 mce_src="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/FforArchitectsHittingthesweetspot_138C8/Slide8_thumb.png"&gt;&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;Being able to seamlessly interoperate with .NET opens up a lot of possibilities for F#. Not only can you take advantage of existing tools like the Visual Studio debugger, but also other .NET platforms such as using XNA to run F# code on the X-Box or Silverlight to run F# code on the web. This synergy is perhaps the main reason why F# get’s much more attention than earlier functional programming languages like OCaml. OCaml’s great, but does it come with a world-class debugger, visualization libraries, and 3rd party ecosystem?&lt;/P&gt;
&lt;P&gt;&lt;A href="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/FforArchitectsHittingthesweetspot_138C8/Slide9.png" mce_href="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/FforArchitectsHittingthesweetspot_138C8/Slide9.png"&gt;&lt;IMG style="BORDER-RIGHT-WIDTH: 0px; DISPLAY: inline; BORDER-TOP-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px" title=Slide9 border=0 alt=Slide9 src="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/FforArchitectsHittingthesweetspot_138C8/Slide9_thumb.png" width=334 height=252 mce_src="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/FforArchitectsHittingthesweetspot_138C8/Slide9_thumb.png"&gt;&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;So I’ve been talking up F# a bit – bla bla .NET interop – bla bla F# makes programming fun. But why should bother learning a new language? &lt;/P&gt;
&lt;P&gt;&lt;A href="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/FforArchitectsHittingthesweetspot_138C8/Slide10.png" mce_href="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/FforArchitectsHittingthesweetspot_138C8/Slide10.png"&gt;&lt;IMG style="BORDER-RIGHT-WIDTH: 0px; DISPLAY: inline; BORDER-TOP-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px" title=Slide10 border=0 alt=Slide10 src="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/FforArchitectsHittingthesweetspot_138C8/Slide10_thumb.png" width=334 height=252 mce_src="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/FforArchitectsHittingthesweetspot_138C8/Slide10_thumb.png"&gt;&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;Let’s start by looking at some of the buzzwords associated with F#.&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;&lt;B&gt;Statically typed. &lt;/B&gt;F# is a statically typed language, in contrast with Ruby which is dynamically typed. This means that type information is known at compile time. So while you can’t do things like monkey patching in F#, code executes much faster and you’ll know about most errors at compile time. &lt;/LI&gt;
&lt;LI&gt;&lt;B&gt;Succinct&lt;/B&gt;. In addition to being type inferred, F# is also whitespace significant. So if you tab a few lines of code under an if-statement, the compiler will treat that as the body of the if-statement. This saves you the burden of littering your code with curly braces as well as saves you vertical whitespace. Less code on the screen means you can see more of your program at a time, meaning you do less context switching while you look through code. It may not sound like much, but this will be a large boon for your productivity.&amp;nbsp; &lt;/LI&gt;
&lt;LI&gt;&lt;B&gt;Scalable&lt;/B&gt;. This isn’t talking about data centers or web servers, but just that if you apply solid software engineering principles to F# code you can write enterprise level applications. (Which is a fancy way to say that F# is not a ‘write-once’ language.) &lt;/LI&gt;
&lt;LI&gt;&lt;B&gt;Explorative.&lt;/B&gt; In F# you don’t need to commit to a design in order to see how things work. You can rapidly prototype solutions in F# as well as experiment with algorithms and approaches in the F# Interactive window. Building on F#’s succinct nature, you don’t need to make a lot of code investment to experiment with your programs.&lt;/LI&gt;
&lt;LI&gt;&lt;B&gt;Libraries&lt;/B&gt;. F# comes with its own library for writing functional code and more. &lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;&lt;A href="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/FforArchitectsHittingthesweetspot_138C8/Slide11.png" mce_href="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/FforArchitectsHittingthesweetspot_138C8/Slide11.png"&gt;&lt;IMG style="BORDER-RIGHT-WIDTH: 0px; DISPLAY: inline; BORDER-TOP-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px" title=Slide11 border=0 alt=Slide11 src="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/FforArchitectsHittingthesweetspot_138C8/Slide11_thumb.png" width=334 height=252 mce_src="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/FforArchitectsHittingthesweetspot_138C8/Slide11_thumb.png"&gt;&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;Functional programming has been around since the 1950’s (LISP) – so why is functional programming so important now? A lot of people will say things like how immutability helps in writing parallel programs, which IMHO isn’t that big of a deal. Because if you wanted to get serious about parallel programming there are programming languages designed to do that and only that exceptionally well.&lt;/P&gt;
&lt;P&gt;The benefit of functional programming lies in what is referred to as &lt;I&gt;programming in the small&lt;/I&gt;.&lt;/P&gt;
&lt;P&gt;Think about the current state of the art when it comes to writing software: object-oriented programming. The main way we approach the ask of converting an algorithm into code is by breaking it into objects, effectively modeling the domain through classes and behaviors. That’s programming in the large. This process of abstraction works great for modeling large systems and breaking it down into smaller and smaller layers, but eventually you run into a wall.&lt;/P&gt;
&lt;P&gt;What about the method bodies? The actual code that goes inside those classes? That’s programming in the small. The problem with object-oriented programming is that when you are writing algorithmic type code, it doesn’t make sense to create classes and interfaces. When you are programming in the small all you really care about is data transformation and raw computation. &lt;/P&gt;
&lt;P&gt;Think of object-oriented programming as a baseball mitt, it’s great for a catching pop fly but certainly isn’t that useful for catching a football. To do that you need a little more finger dexterity. Functional programming is all about programming in the small. It emphasizes the manipulating data that needs to be preformed without all the overhead of classes and an arbitrary type hierarchy.&lt;/P&gt;
&lt;P&gt;&lt;I&gt;[Ed. For more information about this concept check out &lt;/I&gt;&lt;A href="http://en.wikipedia.org/wiki/Programming_in_the_large_and_programming_in_the_small" mce_href="http://en.wikipedia.org/wiki/Programming_in_the_large_and_programming_in_the_small"&gt;&lt;I&gt;this&lt;/I&gt;&lt;/A&gt;&lt;I&gt; and &lt;/I&gt;&lt;A href="http://lorgonblog.spaces.live.com/blog/cns!701679AD17B6D310!511.entry" mce_href="http://lorgonblog.spaces.live.com/blog/cns!701679AD17B6D310!511.entry"&gt;&lt;I&gt;this&lt;/I&gt;&lt;/A&gt;&lt;I&gt;.]&lt;/I&gt;&lt;/P&gt;
&lt;P&gt;&lt;A href="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/FforArchitectsHittingthesweetspot_138C8/Slide12.png" mce_href="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/FforArchitectsHittingthesweetspot_138C8/Slide12.png"&gt;&lt;IMG style="BORDER-RIGHT-WIDTH: 0px; DISPLAY: inline; BORDER-TOP-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px" title=Slide12 border=0 alt=Slide12 src="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/FforArchitectsHittingthesweetspot_138C8/Slide12_thumb.png" width=334 height=252 mce_src="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/FforArchitectsHittingthesweetspot_138C8/Slide12_thumb.png"&gt;&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;&lt;I&gt;[Ed. This animated slide doesn’t look nearly as awesome when you print it out :-/]&lt;/I&gt;&lt;/P&gt;
&lt;P&gt;The first area that F# really excels in is technical and quantitative computing. AKA number crunching.&lt;/P&gt;
&lt;P&gt;&lt;B&gt;Simulation&lt;/B&gt;&lt;/P&gt;
&lt;P&gt;Simulation is one area that F# would we well suited for – imagine you are writing some sort of physics simulator, or trying to model some real-world situation. In F# you can write the functions you want cleanly without needing to force a code-based abstraction onto the real-world processes.&lt;/P&gt;
&lt;P&gt;Another aspect of simulations which makes F# a good fit is a feature called &lt;A href="http://blogs.msdn.com/andrewkennedy/archive/2008/08/20/units-of-measure-in-f-part-one-introducing-units.aspx" mce_href="http://blogs.msdn.com/andrewkennedy/archive/2008/08/20/units-of-measure-in-f-part-one-introducing-units.aspx"&gt;units of measure&lt;/A&gt;, which allow you to encode units such as ‘feet’ or ‘meters per second’ into the actual F# type system. So you’ll get a compiler warning if you try to add acceleration to a velocity. This allows you to eliminate an entire class of bugs.&lt;/P&gt;
&lt;P&gt;&lt;B&gt;Computational Finance&lt;/B&gt;&lt;/P&gt;
&lt;P&gt;Some F# early adopters are in the computational finance business. These firms have large codebases for automated stock trading, calculating risk, and so on. (Exactly the sort of computerized finance that caused the current global economic PITA ;) F# allows these investment banks not only a way to express their financial models in a simpler and more declarative way, but also integrate with the rest of their software stack through .NET interop. (For example, farming out intensive computations to multiple machines through a COM-service or the like.)&lt;/P&gt;
&lt;P&gt;&lt;B&gt;Large Scale Data Processing&lt;/B&gt;&lt;/P&gt;
&lt;P&gt;Finally, F# does a good job at data-exploration type problems. For example, imagine you were trying to mine some customer data to identify trends. In F# you can simply play around with your data in the F# Interactive window, no need to litter your machine with dozens of throw away projects. Also, using F#’s succinct programming model the cost of failure – refactoring or rethinking your approach – is much lower. &lt;/P&gt;
&lt;P&gt;&lt;A href="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/FforArchitectsHittingthesweetspot_138C8/Slide13.png" mce_href="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/FforArchitectsHittingthesweetspot_138C8/Slide13.png"&gt;&lt;IMG style="BORDER-RIGHT-WIDTH: 0px; DISPLAY: inline; BORDER-TOP-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px" title=Slide13 border=0 alt=Slide13 src="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/FforArchitectsHittingthesweetspot_138C8/Slide13_thumb.png" width=334 height=252 mce_src="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/FforArchitectsHittingthesweetspot_138C8/Slide13_thumb.png"&gt;&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;Next up is &lt;A href="http://blogs.msdn.com/chrsmith/archive/2008/05/30/language-oriented-programming-in-f.aspx" mce_href="http://blogs.msdn.com/chrsmith/archive/2008/05/30/language-oriented-programming-in-f.aspx"&gt;language oriented programming&lt;/A&gt;. Which generally means blurring the line between a programming language and natural language.&lt;/P&gt;
&lt;P&gt;&lt;B&gt;Writing Parsers&lt;/B&gt;&lt;/P&gt;
&lt;P&gt;If you wanted to be all hardcore about creating domain specific languages, why not go ahead and write your own parser? Built into the F# PowerPack library are FSLex and FSYacc, two great tools for &lt;A href="http://blogs.msdn.com/chrsmith/archive/2008/01/18/fslex-Sample.aspx" mce_href="http://blogs.msdn.com/chrsmith/archive/2008/01/18/fslex-Sample.aspx"&gt;creating custom parsers&lt;/A&gt;. In fact, the F# compiler’s parser is built using FSLex and FSYacc.&lt;/P&gt;
&lt;P&gt;&lt;B&gt;Augmenting F# Code&lt;/B&gt;&lt;/P&gt;
&lt;P&gt;Another great example of language oriented programming is the use of F# computation expressions. This is a high-powered language feature that allows you to write normal F# code and customize how it gets executed. For example, let’s say you wanted to write some F# code to interact with a robot on Mars. Rather than writing a ton of boilerplate code to retry every command you send to the rover – in the case of cosmic interference or Martian uprising - why not write an F# computation expression (AKA F# workflow) to automatically retry any F# code several times until it times out or succeeds. &lt;/P&gt;
&lt;P&gt;&lt;I&gt;[Ed. This is a pretty advanced topic that I’ll need to devote an entire series of blog posts to later.]&lt;/I&gt;&lt;/P&gt;
&lt;P&gt;&lt;B&gt;Creating New Languages&lt;/B&gt;&lt;/P&gt;
&lt;P&gt;Another area F# excels in is creating internal domain specific languages (mini programming languages embedded in your F# code). F#’s discriminated union types makes declaring ASTs (or any other tree-like data structure) very simple.&lt;/P&gt;
&lt;P&gt;&lt;B&gt;Quotations (Expression Trees)&lt;/B&gt;&lt;/P&gt;
&lt;P&gt;Finally, F# has the same Expression Trees feature found in C# and VB.NET. This allows you to get ‘compiler generated’ form of F# code, which with the right libraries, can allow you to defer the execution of that F# code to other platforms. For example, on a SQL server or on your video card’s GPU.&lt;/P&gt;
&lt;P&gt;&lt;A href="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/FforArchitectsHittingthesweetspot_138C8/Slide14.png" mce_href="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/FforArchitectsHittingthesweetspot_138C8/Slide14.png"&gt;&lt;IMG style="BORDER-RIGHT-WIDTH: 0px; DISPLAY: inline; BORDER-TOP-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px" title=Slide14 border=0 alt=Slide14 src="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/FforArchitectsHittingthesweetspot_138C8/Slide14_thumb.png" width=334 height=252 mce_src="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/FforArchitectsHittingthesweetspot_138C8/Slide14_thumb.png"&gt;&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;F# is also good at parallel programming, which to be pedantic is referring to the: parallel, asynchronous, concurrent, and reactive programming domains. F# doesn’t automatically parallelize your code, nor have any built-in support for parallel primitives. Instead, it has a couple of features that make parallel programming easier – but none of them are a silver bullet.&lt;/P&gt;
&lt;P&gt;&lt;B&gt;Immutable by Default&lt;/B&gt;&lt;/P&gt;
&lt;P&gt;In F#, like most other functional programming language, data is immutable by default. So if you program in the purely functional paradigm you don’t have to worry about race conditions when executing multiple threads because there is no shared, mutable state for two threads to fight over. &lt;/P&gt;
&lt;P&gt;&lt;B&gt;Parallel Extensions to .NET&lt;/B&gt;&lt;/P&gt;
&lt;P&gt;This isn’t an F#-specific feature per-say but will go a long way towards making it easier to write parallel programs and that is the Parallel Extensions (PFX) to .NET found in CLR 4.0. While the PFX adds a lot of great capabilities to the .NET platform, there are two parts in particular I am super-excited about.&lt;/P&gt;
&lt;P&gt;The Task Parallel Library (TPL) is a set of classes for abstracting the process of spawning ‘tasks’ of work. With the TPL there is no longer any need to spawn or manage threads manually. Instead, you can trust the TPL ‘goo’ to deal with that for you as well as modulate how many threads are currently asking for CPU time to make sure you aren’t overwhelming your system with parallel tasks.&lt;/P&gt;
&lt;P&gt;The other, and perhaps even more exciting, part of the PFX is the set of new Concurrent Data Structures. These are a new set of collection types that are built specifically with high-performance parallel applications in mind. So rather than sweating all the details of sharing mutable state, you can just have two threads writing to one of these concurrent data structures and all the messy locking and unlocking of data is taken care of for you.&lt;/P&gt;
&lt;P&gt;&lt;B&gt;Asynchronous Workflowws&lt;/B&gt;&lt;/P&gt;
&lt;P&gt;You may have heard somewhere before that F# makes asynchronous programming super easy, that is 100% true.&amp;nbsp; &lt;/P&gt;
&lt;P&gt;&lt;A href="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/FforArchitectsHittingthesweetspot_138C8/Slide15.png" mce_href="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/FforArchitectsHittingthesweetspot_138C8/Slide15.png"&gt;&lt;IMG style="BORDER-RIGHT-WIDTH: 0px; DISPLAY: inline; BORDER-TOP-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px" title=Slide15 border=0 alt=Slide15 src="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/FforArchitectsHittingthesweetspot_138C8/Slide15_thumb.png" width=334 height=252 mce_src="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/FforArchitectsHittingthesweetspot_138C8/Slide15_thumb.png"&gt;&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;The way to write asynchronous programs on .NET is through the use of the Asynchronous Programming Model or APM. This is a pattern where you begin an asynchronous operation – such as reading a file – by calling BeginOp (e.g.,&amp;nbsp; BeginRead) and passing in a callback. When the asynchronous operation completes, the callback is executed in which you must call EndOp (e.g., EndRead). &lt;/P&gt;
&lt;P&gt;While this approach has served .NET well for nearly a decade it’s a huge pain in the ass to deal with. &lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;Passing state across callbacks is tedious and error prone&lt;/LI&gt;
&lt;LI&gt;You cannot easily handle exceptions if your asynchronous code is spread across myriad callbacks&lt;/LI&gt;
&lt;LI&gt;etc.&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;The code in the slide is from the Microsoft Patterns and Practices group and is the recommended way for processing a series of images in parallel. If anything, I want to point out that there is a lot of code which doesn’t look that easy to write.&lt;/P&gt;
&lt;P&gt;&lt;A href="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/FforArchitectsHittingthesweetspot_138C8/Slide16.png" mce_href="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/FforArchitectsHittingthesweetspot_138C8/Slide16.png"&gt;&lt;IMG style="BORDER-RIGHT-WIDTH: 0px; DISPLAY: inline; BORDER-TOP-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px" title=Slide16 border=0 alt=Slide16 src="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/FforArchitectsHittingthesweetspot_138C8/Slide16_thumb.png" width=334 height=252 mce_src="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/FforArchitectsHittingthesweetspot_138C8/Slide16_thumb.png"&gt;&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;This is how to write that same code in F#, using the F# Asynchronous Workflows library. Like I’ve said many times, F# wasn’t created specifically to write parallel programs. F# Asynchronous Workflows is simply some functionality built into the F# library that makes asynchronous programming very easy. This is enabled through a feature called F# Computation Expressions.&lt;/P&gt;
&lt;P&gt;In the code you see the ‘let!’ and ‘do!’. The F# Asynchronous Workflows library completes these operations asynchronously, doing all that jazz with thread hopping and callbacks behind the scenes.&lt;/P&gt;
&lt;P&gt;&lt;A href="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/FforArchitectsHittingthesweetspot_138C8/Slide17.png" mce_href="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/FforArchitectsHittingthesweetspot_138C8/Slide17.png"&gt;&lt;IMG style="BORDER-RIGHT-WIDTH: 0px; DISPLAY: inline; BORDER-TOP-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px" title=Slide17 border=0 alt=Slide17 src="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/FforArchitectsHittingthesweetspot_138C8/Slide17_thumb.png" width=334 height=252 mce_src="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/FforArchitectsHittingthesweetspot_138C8/Slide17_thumb.png"&gt;&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;So I have told you all about how awesome F# is, but let’s try to bring the discussion back down to reality. Certainly F# isn’t all unicorns and rainbows, right?&lt;/P&gt;
&lt;P&gt;&lt;A href="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/FforArchitectsHittingthesweetspot_138C8/Slide18.png" mce_href="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/FforArchitectsHittingthesweetspot_138C8/Slide18.png"&gt;&lt;IMG style="BORDER-RIGHT-WIDTH: 0px; DISPLAY: inline; BORDER-TOP-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px" title=Slide18 border=0 alt=Slide18 src="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/FforArchitectsHittingthesweetspot_138C8/Slide18_thumb.png" width=334 height=252 mce_src="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/FforArchitectsHittingthesweetspot_138C8/Slide18_thumb.png"&gt;&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;&lt;I&gt;[Ed. I should probably get a better slide title from the marketing department ;) ]&lt;/I&gt;&lt;/P&gt;
&lt;P&gt;F# isn’t great for everything, here are a few such areas.&lt;/P&gt;
&lt;P&gt;&lt;B&gt;Presentation Layer&lt;/B&gt;&lt;/P&gt;
&lt;P&gt;In F# v1.0 we won’t support any code generators in the box. So you won’t get any of the WYSIWYG editors for WinForms or WPF in F#. So if you want to write presentation layer code in F# you’ll need to unfortunately do it all by hand. However, this isn’t the end of the world because of F#’s .NET interop story. You could just as easily create your UI in C# or VB and simply call into your F# code through a class library.&lt;/P&gt;
&lt;P&gt;&lt;B&gt;Object Oriented Hierarchies&lt;/B&gt;&lt;/P&gt;
&lt;P&gt;Even though F# can write object-oriented code, that isn’t the language’s main paradigm so when writing the heavily OO code of can look a little strange. Also F# supports many functional programming constructs that C# and VB don’t, such as discriminated unions and function currying. So if you created an F# library that exposed ‘functional’ code, it certainly wouldn’t look right if you tried to bring that into a non-functional language.&lt;/P&gt;
&lt;P&gt;The key here is to properly encapsulate your F# code – programming in the small – when you want to integrate it with a larger component – programming in the large.&lt;/P&gt;
&lt;P&gt;&lt;A href="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/FforArchitectsHittingthesweetspot_138C8/Slide19.png" mce_href="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/FforArchitectsHittingthesweetspot_138C8/Slide19.png"&gt;&lt;IMG style="BORDER-RIGHT-WIDTH: 0px; DISPLAY: inline; BORDER-TOP-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px" title=Slide19 border=0 alt=Slide19 src="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/FforArchitectsHittingthesweetspot_138C8/Slide19_thumb.png" width=334 height=252 mce_src="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/FforArchitectsHittingthesweetspot_138C8/Slide19_thumb.png"&gt;&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;So what happens if F# does make sense for part of your application? Are you going to need to hire a bunch of rocket scientists? No. Actually, I’ll even go on record and bust out a hearty hell no. F# isn’t just for eggheads. In fact, this summer we’ve had a highschool intern working on some F# samples. (That’s right, someone who just graduated highschool writing F# code for their internship.)&lt;/P&gt;
&lt;P&gt;There is nothing inherently difficult with functional programming, it’s just a different way to &lt;I&gt;view&lt;/I&gt; problems. But pay attention to what your team says while they are learning F#:&lt;/P&gt;
&lt;UL&gt;
&lt;LI&gt;“It’s just like C#”. This means they are doing it wrong. The whole point of F# is that it provides you a different way to think about programming, and in that different approach be more effective. If you write C# code in F# you won’t be gaining anything.&lt;/LI&gt;
&lt;LI&gt;“F# is too simple for real-world problems”. While F# is a simple programming language to learn, you can accomplish quite a lot through just writing simple functions.&lt;/LI&gt;
&lt;LI&gt;“Functional programming hurts my brains”. This means you are on the right track. Learning F# will expose you to different approaches to solving problems. (functional v imperative, functional v object-oriented, etc.)&lt;/LI&gt;&lt;/UL&gt;
&lt;P&gt;&lt;A href="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/FforArchitectsHittingthesweetspot_138C8/Slide20.png" mce_href="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/FforArchitectsHittingthesweetspot_138C8/Slide20.png"&gt;&lt;IMG style="BORDER-RIGHT-WIDTH: 0px; DISPLAY: inline; BORDER-TOP-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px" title=Slide20 border=0 alt=Slide20 src="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/FforArchitectsHittingthesweetspot_138C8/Slide20_thumb.png" width=334 height=252 mce_src="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/FforArchitectsHittingthesweetspot_138C8/Slide20_thumb.png"&gt;&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;Even if F# will help you be more productive writing code &lt;I&gt;today&lt;/I&gt;, what is the long-term cost of that F# code?&lt;/P&gt;
&lt;P&gt;Well one great benefit of F# is that it is terse. I mentioned this before, but when you are trying to debug an issue being able to see all the relevant code on the screen at once you don’t have to constantly be context switching between different code files. &lt;/P&gt;
&lt;P&gt;It can be said that mind-bending functional code is harder to understand than more normal imperative code. That’s totally true – but the reality is that you shouldn’t write mind-bending functional code in the first place. (Just like you shouldn’t write mind-bending code in any programming language.) Idiomatic F# code is clear and readable. You can certainly use features like function composition and function currying without making the code ‘write once’.&lt;/P&gt;
&lt;P&gt;&lt;A href="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/FforArchitectsHittingthesweetspot_138C8/Slide21.png" mce_href="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/FforArchitectsHittingthesweetspot_138C8/Slide21.png"&gt;&lt;IMG style="BORDER-RIGHT-WIDTH: 0px; DISPLAY: inline; BORDER-TOP-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px" title=Slide21 border=0 alt=Slide21 src="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/FforArchitectsHittingthesweetspot_138C8/Slide21_thumb.png" width=334 height=252 mce_src="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/FforArchitectsHittingthesweetspot_138C8/Slide21_thumb.png"&gt;&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;The bottom line is this: if you are happy with C# or VB, then just keep using them. In fact, ignore F# all together. You can benefit from learning F# like any programming language to make you a better programmer, but don’t switch to F# if there isn’t a specific reason.&lt;/P&gt;
&lt;P&gt;But if you find that you are struggling against your programming language to express your ideas. That you find too much syntactic clutter gets in the way, then check out F#. In domains where there is a lot of computation or data transformation to perform – technical computing, language oriented programming, parallel / async – you might be more productive.&lt;/P&gt;
&lt;P&gt;Writing code in F# doesn’t magically make it faster or take up less memory. All it does is provide you with a different way to &lt;I&gt;view&lt;/I&gt; the problem space, and in that different view be more effective in encoding algorithms to solve your problems by giving you more ways of expressing your ideas. (That is, in an imperative, object-oriented, or functional style.)&lt;/P&gt;
&lt;P&gt;&lt;A href="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/FforArchitectsHittingthesweetspot_138C8/Slide22.png" mce_href="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/FforArchitectsHittingthesweetspot_138C8/Slide22.png"&gt;&lt;IMG style="BORDER-RIGHT-WIDTH: 0px; DISPLAY: inline; BORDER-TOP-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px" title=Slide22 border=0 alt=Slide22 src="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/FforArchitectsHittingthesweetspot_138C8/Slide22_thumb.png" width=334 height=252 mce_src="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/FforArchitectsHittingthesweetspot_138C8/Slide22_thumb.png"&gt;&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;Unlike a lot of ‘awesome new technologies’ coming out from Microsoft, you can actually use F# today. In fact to my knowledge there are a growing number of developers who are paid to write F# code every day. You can find the latest F# CTP, which is an add-in for Visual Studio 2008, from the F# Dev Center at &lt;A href="http://fsharp.net/" mce_href="http://fsharp.net"&gt;http://fsharp.net&lt;/A&gt;. I you want to try even fancier new technologies, you can also check out Visual Studio 2010 Beta1 from &lt;A href="http://msdn.com/" mce_href="http://msdn.com"&gt;http://msdn.com&lt;/A&gt;. &lt;/P&gt;
&lt;P&gt;For non-windows folks you can F# via Mono at &lt;A href="http://mono-project.com/" mce_href="http://mono-project.com"&gt;http://mono-project.com&lt;/A&gt;.&amp;nbsp; &lt;/P&gt;
&lt;P&gt;&lt;A href="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/FforArchitectsHittingthesweetspot_138C8/Slide23.png" mce_href="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/FforArchitectsHittingthesweetspot_138C8/Slide23.png"&gt;&lt;IMG style="BORDER-RIGHT-WIDTH: 0px; DISPLAY: inline; BORDER-TOP-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px" title=Slide23 border=0 alt=Slide23 src="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/FforArchitectsHittingthesweetspot_138C8/Slide23_thumb.png" width=334 height=252 mce_src="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/FforArchitectsHittingthesweetspot_138C8/Slide23_thumb.png"&gt;&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;For learning F# I recommend the three B’s: Books, Blogs, and Bugging other people.&lt;/P&gt;
&lt;P&gt;&lt;B&gt;Books&lt;/B&gt;&lt;/P&gt;
&lt;P&gt;For being a language that hasn’t officially come out here there are already several great books on the subject. The most recent general book on F# was &lt;I&gt;Expert F# &lt;/I&gt;by Don Syme, Adam Granicz, and Antonio Cisternino. It’s a good book, but it’s main drawback these days is just when it was published: 2007. Since then the language has undergone some significant revision, especially in the F# libraries.&lt;/P&gt;
&lt;P&gt;I – &lt;I&gt;in my completely unbiased opinion &lt;/I&gt;– recommend you wait until early November and buy my book,&lt;A title="Programming F#" href="http://www.amazon.com/Programming-Animal-Guide-Chris-Smith/dp/0596153643" mce_href="http://www.amazon.com/Programming-Animal-Guide-Chris-Smith/dp/0596153643"&gt; &lt;I&gt;Programming F#&lt;/I&gt;&lt;/A&gt; from O’Reilly. :)&amp;nbsp; It is a comprehensive guide to the F# language. In it you won’t find a lot of theory, but instead a clear introduction to what F# has that your favorite language doesn’t, and how you can take advantage of those features.&lt;/P&gt;
&lt;P&gt;&lt;B&gt;Blogs&lt;/B&gt;&lt;/P&gt;
&lt;P&gt;There is a great F# community online with a ton of high-quality blogs. In fact nearly everyone on the F# team has their own blog. Check out the F# Development Center where you’ll find an aggregated feed for F# blogs.&lt;/P&gt;
&lt;P&gt;&lt;B&gt;Bugging other people&lt;/B&gt;&lt;/P&gt;
&lt;P&gt;Finally, there are two great places to go for learning more about F#. &lt;A href="http://hubfs.net/" mce_href="http://hubfs.net"&gt;http://hubfs.net&lt;/A&gt; is the Hub FS website, a great forum dedicated to exclusively F#. In addition, there has been growing interest in F# on &lt;A href="http://stackoverflow.com/" mce_href="http://stackoverflow.com"&gt;http://stackoverflow.com&lt;/A&gt;. I recommend you ask questions there so that I may answer you and receive glorious reputation. ;)&lt;/P&gt;
&lt;P&gt;&lt;A href="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/FforArchitectsHittingthesweetspot_138C8/Slide24.png" mce_href="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/FforArchitectsHittingthesweetspot_138C8/Slide24.png"&gt;&lt;IMG style="BORDER-RIGHT-WIDTH: 0px; DISPLAY: inline; BORDER-TOP-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-LEFT-WIDTH: 0px" title=Slide24 border=0 alt=Slide24 src="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/FforArchitectsHittingthesweetspot_138C8/Slide24_thumb.png" width=334 height=252 mce_src="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/FforArchitectsHittingthesweetspot_138C8/Slide24_thumb.png"&gt;&lt;/A&gt;l&lt;/P&gt;
&lt;P&gt;I hope you enjoyed the talk, if it sounds like F# doesn’t apply to your line of work and never will – no hard feelings. If it does, then I encourage you to download the latest F# CTP and experiment.&lt;/P&gt;
&lt;P&gt;&lt;I&gt;[Ed. Hopefully I’ve been able to capture the essence of my presentation. While you can’t summarize everything about F# in a single blog post, hopefully this helps clarify some domains where we expect F# to be the most heavily used. If you have any questions please feel free to use the contact link on this blog.]&lt;/I&gt;&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9878185" width="1" height="1"&gt;&lt;img src="http://feeds.feedburner.com/~r/ChrisSmithsCompletelyUniqueView/~4/_jNFcsdVq8w" height="1" width="1"/&gt;</description><category domain="http://blogs.msdn.com/chrsmith/archive/tags/F_2300_/default.aspx">F#</category><category domain="http://blogs.msdn.com/chrsmith/archive/tags/Community/default.aspx">Community</category><feedburner:origLink>http://blogs.msdn.com/chrsmith/archive/2009/08/20/f-for-architects-hitting-the-sweet-spot.aspx</feedburner:origLink><enclosure url="http://feedproxy.google.com/~r/ChrisSmithsCompletelyUniqueView/~5/UiH3hHMHK6U/9878185.ashx" length="1413140" type="application/vnd.openxmlformats-officedocument.pres" /><feedburner:origEnclosureLink>http://blogs.msdn.com/chrsmith/attachment/9878185.ashx</feedburner:origEnclosureLink></item><item><title>Back in Action!</title><link>http://feedproxy.google.com/~r/ChrisSmithsCompletelyUniqueView/~3/iMsKyo1dRdE/back-in-action.aspx</link><pubDate>Thu, 20 Aug 2009 07:46:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9876337</guid><dc:creator>ChrSmith</dc:creator><slash:comments>9</slash:comments><comments>http://blogs.msdn.com/chrsmith/comments/9876337.aspx</comments><wfw:commentRss>http://blogs.msdn.com/chrsmith/commentrss.aspx?PostID=9876337</wfw:commentRss><description>&lt;P&gt;I know it’s cliché to blog about blogging, but I’d like to take this opportunity to explain why there has been such a lull. In short, I’ve been busy.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Finished &lt;EM&gt;Programming F#&lt;/EM&gt;&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;As you might have heard, I was working on &lt;A href="http://www.amazon.com/Programming-Animal-Guide-Chris-Smith/dp/0596153643" mce_href="http://www.amazon.com/Programming-Animal-Guide-Chris-Smith/dp/0596153643"&gt;a book&lt;/A&gt;. Well no more! The book is done and only undergoing minor technical edits (read fixing bugs due to breaking changes). Check for it in stores late October.&lt;/P&gt;
&lt;P&gt;Unfortunately, the sad news is that the final book will have a different cover than the previously discussed &lt;A href="http://blogs.msdn.com/chrsmith/archive/2009/05/13/programming-f-official-cover.aspx" mce_href="http://blogs.msdn.com/chrsmith/archive/2009/05/13/programming-f-official-cover.aspx"&gt;Jelly Fish&lt;/A&gt;. Instead, it’ll be a fat (but cute) songbird… Perhaps singing in the key of F#? (Sorry to disappoint you &lt;A href="http://coolthingoftheday.blogspot.com/2009/05/programming-f-official-book-cover-while.html" mce_href="http://coolthingoftheday.blogspot.com/2009/05/programming-f-official-book-cover-while.html"&gt;Greg&lt;/A&gt;.)&lt;/P&gt;
&lt;P&gt;&lt;A href="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/BackinAction_13215/lrg%5B1%5D_2.jpg" mce_href="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/BackinAction_13215/lrg%5B1%5D_2.jpg"&gt;&lt;IMG title=lrg[1] style="BORDER-RIGHT: 0px; BORDER-TOP: 0px; DISPLAY: inline; BORDER-LEFT: 0px; BORDER-BOTTOM: 0px" height=250 alt=lrg[1] src="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/BackinAction_13215/lrg%5B1%5D_thumb.jpg" width=192 border=0 mce_src="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/BackinAction_13215/lrg%5B1%5D_thumb.jpg"&gt;&lt;/A&gt;&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Finished my Masters Degree&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;I’ve been attending the University of Washington’s &lt;A href="http://pmp.cs.washington.edu/" mce_href="http://pmp.cs.washington.edu/"&gt;Professional Masters Program&lt;/A&gt; for the past few years, and I finally got around to graduating. If you live in the Seattle area and are interested in taking your education to the next level I would highly recommend it. I certainly wouldn’t be able to excel at my job working on the F# team if it weren’t for taking a few graduate-level classes in Programming Languages and Compilers.&lt;/P&gt;
&lt;P&gt;&lt;IMG src="http://www.cs.washington.edu/info/aboutus/LMN_UW_019.jpg" mce_src="http://www.cs.washington.edu/info/aboutus/LMN_UW_019.jpg"&gt;&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Went to Japan&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;After working nights and weekends for over a year with the book and grad school, I figured I would take a little vacation. So I spent a week in Japan bumming around with a buddy of mine. I’ll spare you the boring details, but let’s just say a LOT of karaoke was involved.&lt;/P&gt;
&lt;P&gt;&lt;A href="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/BackinAction_13215/Japan%20097.jpg" mce_href="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/BackinAction_13215/Japan%20097.jpg"&gt;&lt;IMG title="Japan 097" style="BORDER-RIGHT: 0px; BORDER-TOP: 0px; DISPLAY: inline; BORDER-LEFT: 0px; BORDER-BOTTOM: 0px" height=244 alt="Japan 097" src="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/BackinAction_13215/Japan%20097_thumb.jpg" width=184 border=0 mce_src="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/BackinAction_13215/Japan%20097_thumb.jpg"&gt;&lt;/A&gt; &lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Spoke at DevLink&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;Last week I was in Nashville speaking at &lt;A href="http://www.devlink.net/Default.aspx" mce_href="http://www.devlink.net/Default.aspx"&gt;DevLink&lt;/A&gt;. It was a wonderful opportunity to meet up with some old friends and find plenty of new ones. There I gave &lt;STRONG&gt;four&lt;/STRONG&gt; talks on F# and functional programming, totaling &lt;STRONG&gt;six&lt;/STRONG&gt; hours of material. Some talks went better than others, but I’m pleased to note that the talk I really wanted to knock out of the park – &lt;EM&gt;F# for Architects: Hitting the sweet spot&lt;/EM&gt; – was very well received.&lt;/P&gt;
&lt;P&gt;&lt;EM&gt;Edit 8/20: I'll post the slides for the F# for Architects talk here later this week.&lt;/EM&gt;&lt;/P&gt;
&lt;P&gt;&lt;IMG height=77 alt="devLink Technical Conference" src="http://www.devlink.net/Portals/0/siteHeader.png" width=538 mce_src="http://www.devlink.net/Portals/0/siteHeader.png"&gt;&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;So What’s Next?&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;So where does that leave me? Now that I’ve got my new degree, the book coming out, and some painful personal life drama behind me – what’s next? Well I’ve been thinking about that myself for a while. And the answer is more of the same. Specifically, I want to keep writing, blogging, and getting an awesome v1.0 of F# out and in the hands of developers. So check back soon!&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9876337" width="1" height="1"&gt;&lt;img src="http://feeds.feedburner.com/~r/ChrisSmithsCompletelyUniqueView/~4/iMsKyo1dRdE" height="1" width="1"/&gt;</description><category domain="http://blogs.msdn.com/chrsmith/archive/tags/A+day+in+the+life/default.aspx">A day in the life</category><category domain="http://blogs.msdn.com/chrsmith/archive/tags/Personal/default.aspx">Personal</category><feedburner:origLink>http://blogs.msdn.com/chrsmith/archive/2009/08/19/back-in-action.aspx</feedburner:origLink></item><item><title>Lightweight PGN parser in F# – Part I</title><link>http://feedproxy.google.com/~r/ChrisSmithsCompletelyUniqueView/~3/BEQAXP-TVmc/lightweight-pgn-parser-in-f.aspx</link><pubDate>Sat, 13 Jun 2009 22:43:27 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9745849</guid><dc:creator>ChrSmith</dc:creator><slash:comments>5</slash:comments><comments>http://blogs.msdn.com/chrsmith/comments/9745849.aspx</comments><wfw:commentRss>http://blogs.msdn.com/chrsmith/commentrss.aspx?PostID=9745849</wfw:commentRss><description>&lt;p&gt;If you’ve ever spent a lot of time around the game of Chess you’ve probably seen or interacted with the PGN file format in one way or another. PGN stands for &lt;a href="http://en.wikipedia.org/wiki/Portable_Game_Notation"&gt;Portable Game Notation&lt;/a&gt; and is a concise way to represent Chess games.&lt;/p&gt;  &lt;p&gt;Using regular expressions I’ve written a very lightweight parser to handle the file format. I wouldn’t be surprised if the regular expressions don’t capture every legal .pgn file, but it shows how effective regular expressions can be for semi-structured data.&lt;/p&gt;  &lt;p&gt;Not being a Chess player myself, I’m not really sure what to do with: &lt;/p&gt;  &lt;pre class="code"&gt;&lt;span style="color: maroon"&gt;&amp;quot;Nxf7 Rxe1+&amp;quot;&lt;/span&gt;&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;but perhaps I’ll look at that in a future blog post.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Edit: On second thought, there is all sorts of wrong with this parser. For example, notice how move ‘3’ is listed twice. The ‘3…’ continues on after the comment.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Alas, once the raw list of moves is parsed another step to coalesce them is required. In addition, a commenter pointed out that the 1/2-1/2 is the result of the game (a draw). I’ll spend a little more time on this before I can call it an official ‘parser’ but it’s a nice start :D.&lt;/em&gt;&amp;#160; &lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;open &lt;/span&gt;System.Text.RegularExpressions

&lt;span style="color: blue"&gt;let &lt;/span&gt;pgnGameText = &lt;span style="color: maroon"&gt;&amp;quot;
[Event \&amp;quot;F/S Return Match\&amp;quot;]
[Site \&amp;quot;Belgrade, Serbia Yugoslavia|JUG\&amp;quot;]
[Date \&amp;quot;1992.11.04\&amp;quot;]
[Round \&amp;quot;29\&amp;quot;]
[White \&amp;quot;Fischer, Robert J.\&amp;quot;]
[Black \&amp;quot;Spassky, Boris V.\&amp;quot;]
[Result \&amp;quot;1/2-1/2\&amp;quot;]
 
1. e4 e5 2. Nf3 Nc6 3. Bb5 {This opening is called the Ruy Lopez.} 3... a6
4. Ba4 Nf6 5. O-O Be7 6. Re1 b5 7. Bb3 d6 8. c3 O-O 9. h3 Nb8  10. d4 Nbd7
11. c4 c6 12. cxb5 axb5 13. Nc3 Bb7 14. Bg5 b4 15. Nb1 h6 16. Bh4 c5 17. dxe5
Nxe4 18. Bxe7 Qxe7 19. exd6 Qf6 20. Nbd2 Nxd6 21. Nc4 Nxc4 22. Bxc4 Nb6
23. Ne5 Rae8 24. Bxf7+ Rxf7 25. Nxf7 Rxe1+ 26. Qxe1 Kxf7 27. Qe3 Qg5 28. Qxg5
hxg5 29. b3 Ke6 30. a3 Kd6 31. axb4 cxb4 32. Ra5 Nd5 33. f3 Bc8 34. Kf2 Bf5
35. Ra7 g6 36. Ra6+ Kc5 37. Ke1 Nf4 38. g3 Nxh3 39. Kd2 Kb5 40. Rd6 Kc5 41. Ra6
Nf2 42. g4 Bd3 43. Re6 1/2-1/2
&amp;quot;

&lt;/span&gt;&lt;span style="color: green"&gt;// Remove comments and markup from the PGN file
&lt;/span&gt;&lt;span style="color: blue"&gt;let &lt;/span&gt;removeMarkup text = 
    &lt;span style="color: blue"&gt;let &lt;/span&gt;tagPairs = &lt;span style="color: blue"&gt;new &lt;/span&gt;Regex(&lt;span style="color: maroon"&gt;@&amp;quot;\[.*\]&amp;quot;&lt;/span&gt;)
    &lt;span style="color: blue"&gt;let &lt;/span&gt;noTagPairs = tagPairs.Replace(text, &lt;span style="color: maroon"&gt;&amp;quot;&amp;quot;&lt;/span&gt;)

    &lt;span style="color: blue"&gt;let &lt;/span&gt;comments = &lt;span style="color: blue"&gt;new &lt;/span&gt;Regex(&lt;span style="color: maroon"&gt;@&amp;quot;\{.*\}&amp;quot;&lt;/span&gt;)
    &lt;span style="color: blue"&gt;let &lt;/span&gt;noComments = comments.Replace(noTagPairs, &lt;span style="color: maroon"&gt;&amp;quot;&amp;quot;&lt;/span&gt;)
    
    &lt;span style="color: green"&gt;// Trim any leading whitespace and convert to a single-line
    &lt;/span&gt;noComments.Trim().Replace(&lt;span style="color: maroon"&gt;&amp;quot;\r&amp;quot;&lt;/span&gt;, &lt;span style="color: maroon"&gt;&amp;quot;&amp;quot;&lt;/span&gt;).Replace(&lt;span style="color: maroon"&gt;&amp;quot;\n&amp;quot;&lt;/span&gt;, &lt;span style="color: maroon"&gt;&amp;quot; &amp;quot;&lt;/span&gt;)
        
&lt;span style="color: green"&gt;// Get the list of moves, each prefixed with a number and one or three dots
&lt;/span&gt;&lt;span style="color: blue"&gt;let &lt;/span&gt;getMoves text =
    &lt;span style="color: blue"&gt;let &lt;/span&gt;factRegex = &lt;span style="color: blue"&gt;new &lt;/span&gt;Regex(&lt;span style="color: maroon"&gt;@&amp;quot;\d+\.+&amp;quot;&lt;/span&gt;, RegexOptions.Multiline)
    factRegex.Split(text)

&lt;span style="color: blue"&gt;let &lt;/span&gt;normalizedText = removeMarkup pgnGameText
    
&lt;span style="color: blue"&gt;let &lt;/span&gt;printGameMoves() = 
    getMoves normalizedText
    |&amp;gt; Array.map (&lt;span style="color: blue"&gt;fun &lt;/span&gt;move &lt;span style="color: blue"&gt;-&amp;gt; &lt;/span&gt;move.Trim())
    |&amp;gt; Array.iteri (&lt;span style="color: blue"&gt;fun &lt;/span&gt;idx move &lt;span style="color: blue"&gt;-&amp;gt; &lt;/span&gt;printfn &lt;span style="color: maroon"&gt;&amp;quot;Move %2d: %s&amp;quot; &lt;/span&gt;idx move)
&lt;span style="color: green"&gt;&lt;/span&gt;&lt;/pre&gt;

&lt;pre class="code"&gt;&lt;span style="color: green"&gt;(*
OUTPUT:

&amp;gt; printGameMoves();;
Move  0: 
Move  1: e4 e5
Move  2: Nf3 Nc6
Move  3: Bb5
Move  4: a6
Move  5: Ba4 Nf6
Move  6: O-O Be7
Move  7: Re1 b5
Move  8: Bb3 d6
Move  9: c3 O-O
Move 10: h3 Nb8
Move 11: d4 Nbd7
Move 12: c4 c6
Move 13: cxb5 axb5
Move 14: Nc3 Bb7
Move 15: Bg5 b4
Move 16: Nb1 h6
Move 17: Bh4 c5
Move 18: dxe5 Nxe4
Move 19: Bxe7 Qxe7
Move 20: exd6 Qf6
Move 21: Nbd2 Nxd6
Move 22: Nc4 Nxc4
Move 23: Bxc4 Nb6
Move 24: Ne5 Rae8
Move 25: Bxf7+ Rxf7
Move 26: Nxf7 Rxe1+
Move 27: Qxe1 Kxf7
Move 28: Qe3 Qg5
Move 29: Qxg5 hxg5
Move 30: b3 Ke6
Move 31: a3 Kd6
Move 32: axb4 cxb4
Move 33: Ra5 Nd5
Move 34: f3 Bc8
Move 35: Kf2 Bf5
Move 36: Ra7 g6
Move 37: Ra6+ Kc5
Move 38: Ke1 Nf4
Move 39: g3 Nxh3
Move 40: Kd2 Kb5
Move 41: Rd6 Kc5
Move 42: Ra6 Nf2
Move 43: g4 Bd3
Move 44: Re6 1/2-1/2
val it : unit = ()
*)&lt;/span&gt;&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9745849" width="1" height="1"&gt;&lt;img src="http://feeds.feedburner.com/~r/ChrisSmithsCompletelyUniqueView/~4/BEQAXP-TVmc" height="1" width="1"/&gt;</description><feedburner:origLink>http://blogs.msdn.com/chrsmith/archive/2009/06/13/lightweight-pgn-parser-in-f.aspx</feedburner:origLink></item><item><title>Programming F# – Official Cover</title><link>http://feedproxy.google.com/~r/ChrisSmithsCompletelyUniqueView/~3/EfKOx6fNHLs/programming-f-official-cover.aspx</link><pubDate>Thu, 14 May 2009 04:18:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9612832</guid><dc:creator>ChrSmith</dc:creator><slash:comments>22</slash:comments><comments>http://blogs.msdn.com/chrsmith/comments/9612832.aspx</comments><wfw:commentRss>http://blogs.msdn.com/chrsmith/commentrss.aspx?PostID=9612832</wfw:commentRss><description>&lt;p&gt;&lt;i&gt;Edit 8/19: You might notice, the cover is no longer a jellyfish. While I know this is a slight disapointment for some - including myself - trust me when I say I have a plan to remedy this. Stay tuned!&lt;/i&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;So as it turns out my &lt;a mce_href="http://blogs.msdn.com/chrsmith/archive/2009/02/02/petition-for-programming-f-s-book-cover.aspx" href="http://blogs.msdn.com/chrsmith/archive/2009/02/02/petition-for-programming-f-s-book-cover.aspx"&gt;petition&lt;/a&gt; for a kickass cover was ultimately unsuccessful. But the good news is that I’m not suck with something neither cute nor cuddly. Instead I got a Jellyfish, after spending some time thinking about it is pretty good. (Though certainly not as awesome as a hydra.)&lt;/p&gt;  &lt;h1&gt;Jellyfish Facts&lt;/h1&gt;  &lt;ul&gt;   &lt;li&gt;Jellyfish can be found in every ocean. Therefore, in the time if trouble they can call on the &lt;a mce_href="http://pirates.wikia.com/wiki/Pirate_Lord" href="http://pirates.wikia.com/wiki/Pirate_Lord"&gt;nine pirate lords&lt;/a&gt; for help. Much like F# being able to use nine different programming paradigms and styles: &lt;/li&gt;    &lt;ul&gt;     &lt;li&gt;functional, imperative, object-oriented, metaprogramming, scripting, concurrent, reactive, declaritive, and awesome. (Yes, ‘awesome’ is a programming paradigm… and Haskell doesn’t support it.)&lt;/li&gt;   &lt;/ul&gt;    &lt;li&gt;Jellyfish do not have a brain or central nervous system. Just like F#… umm… you don’t need a nervous system to write world-class applications?&amp;nbsp; Let me get back to you on this one…&lt;/li&gt;    &lt;li&gt;The real reason I’m excited about having a Jellyfish on the cover is that they can &lt;b&gt;Sting and Kill you&lt;/b&gt;. Like F#, Jellyfish are deadly.&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;So anyways, this October be on the lookout for &lt;a mce_href="http://oreilly.com/catalog/9780596801359/" href="http://oreilly.com/catalog/9780596801359/"&gt;Jellyfish Book&lt;/a&gt;!&lt;/p&gt;  &lt;p&gt;&lt;img alt="Programming F#: Rough Cuts Version" mce_src="http://covers.oreilly.com/images/9780596801359/lrg.jpg" src="http://covers.oreilly.com/images/9780596801359/lrg.jpg"&gt;&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9612832" width="1" height="1"&gt;&lt;img src="http://feeds.feedburner.com/~r/ChrisSmithsCompletelyUniqueView/~4/EfKOx6fNHLs" height="1" width="1"/&gt;</description><category domain="http://blogs.msdn.com/chrsmith/archive/tags/Programming+F_2300_/default.aspx">Programming F#</category><feedburner:origLink>http://blogs.msdn.com/chrsmith/archive/2009/05/13/programming-f-official-cover.aspx</feedburner:origLink></item><item><title>F# Scripting Zen – Bulk Updating Testcases</title><link>http://feedproxy.google.com/~r/ChrisSmithsCompletelyUniqueView/~3/IInN3Xg-Vo0/f-scripting-zen-bulk-updating-testcases.aspx</link><pubDate>Sat, 09 May 2009 20:35:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9599425</guid><dc:creator>ChrSmith</dc:creator><slash:comments>2</slash:comments><comments>http://blogs.msdn.com/chrsmith/comments/9599425.aspx</comments><wfw:commentRss>http://blogs.msdn.com/chrsmith/commentrss.aspx?PostID=9599425</wfw:commentRss><description>&lt;P class=MsoNormal style="MARGIN: 0in 0in 10pt; LINE-HEIGHT: normal; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 12pt; FONT-FAMILY: 'Times New Roman','serif'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;As the F# team is busy working to finish up &lt;A href="http://www.microsoft.com/visualstudio/en-us/products/2010/default.mspx"&gt;&lt;SPAN style="COLOR: blue"&gt;Visual Studio 2010&lt;/SPAN&gt;&lt;/A&gt;, one task left to complete is to localize the compiler, so that on a Japanese machine the error messages will be in Japanese.&lt;?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" /&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 10pt; LINE-HEIGHT: normal; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 12pt; FONT-FAMILY: 'Times New Roman','serif'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;While I’m sure a few &lt;A href="http://www.codinghorror.com/blog/archives/001248.html"&gt;&lt;SPAN style="COLOR: blue"&gt;Ugly American Programmers&lt;/SPAN&gt;&lt;/A&gt; might question the value of localized error messages, imagine if the F# compiler told you this every time you made a mistake:&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 10pt; LINE-HEIGHT: normal; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 12pt; FONT-FAMILY: 'Times New Roman','serif'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;"&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 12pt; FONT-FAMILY: 'MS Mincho'; mso-ansi-language: EN; mso-bidi-font-family: 'MS Mincho'"&gt;このタイプのパラメータ値を推定タイプ略語の安定の下では、消去されていません。このドロップ、または並べ替えのタイプのパラメータを、&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 12pt; FONT-FAMILY: 'Times New Roman','serif'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt; &lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 12pt; FONT-FAMILY: 'MS Mincho'; mso-ansi-language: EN; mso-bidi-font-family: 'MS Mincho'"&gt;のタイプは、例えば、略語の使用によるものです&lt;/SPAN&gt;&lt;SPAN lang=EN style="FONT-SIZE: 12pt; FONT-FAMILY: 'Times New Roman','serif'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&amp;lt; ' a &amp;gt;&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 12pt; FONT-FAMILY: 'MS Mincho'; mso-ansi-language: EN; mso-bidi-font-family: 'MS Mincho'"&gt;を&lt;/SPAN&gt;&lt;SPAN lang=EN style="FONT-SIZE: 12pt; FONT-FAMILY: 'Times New Roman','serif'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;= &lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 12pt; FONT-FAMILY: 'MS Mincho'; mso-ansi-language: EN; mso-bidi-font-family: 'MS Mincho'"&gt;はまたは&lt;/SPAN&gt;&lt;SPAN lang=EN style="FONT-SIZE: 12pt; FONT-FAMILY: 'Times New Roman','serif'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;\ Ñ \ ttype&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 12pt; FONT-FAMILY: 'MS Mincho'; mso-ansi-language: EN; mso-bidi-font-family: 'MS Mincho'"&gt;スワップ&lt;/SPAN&gt;&lt;SPAN lang=EN style="FONT-SIZE: 12pt; FONT-FAMILY: 'Times New Roman','serif'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&amp;lt; '&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 12pt; FONT-FAMILY: 'MS Mincho'; mso-ansi-language: EN; mso-bidi-font-family: 'MS Mincho'"&gt;は、&lt;/SPAN&gt;&lt;SPAN lang=EN style="FONT-SIZE: 12pt; FONT-FAMILY: 'Times New Roman','serif'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt; ' b &amp;gt; = ' b * '&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 12pt; FONT-FAMILY: 'MS Mincho'; mso-ansi-language: EN; mso-bidi-font-family: 'MS Mincho'"&gt;を&lt;/SPAN&gt;&lt;SPAN lang=EN style="FONT-SIZE: 12pt; FONT-FAMILY: 'Times New Roman','serif'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;1&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 12pt; FONT-FAMILY: 'MS Mincho'; mso-ansi-language: EN; mso-bidi-font-family: 'MS Mincho'"&gt;つの。&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 12pt; FONT-FAMILY: 'Times New Roman','serif'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt; &lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 12pt; FONT-FAMILY: 'MS Mincho'; mso-ansi-language: EN; mso-bidi-font-family: 'MS Mincho'"&gt;明示的にこの値の型のパラメータを宣言、&lt;/SPAN&gt;&lt;SPAN lang=EN style="FONT-SIZE: 12pt; FONT-FAMILY: 'Times New Roman','serif'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt; \ Ñ&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 12pt; FONT-FAMILY: 'MS Mincho'; mso-ansi-language: EN; mso-bidi-font-family: 'MS Mincho'"&gt;例：&lt;/SPAN&gt;&lt;SPAN lang=EN style="FONT-SIZE: 12pt; FONT-FAMILY: 'Times New Roman','serif'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt; \ tlet&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 12pt; FONT-FAMILY: 'MS Mincho'; mso-ansi-language: EN; mso-bidi-font-family: 'MS Mincho'"&gt;金&lt;/SPAN&gt;&lt;SPAN lang=EN style="FONT-SIZE: 12pt; FONT-FAMILY: 'Times New Roman','serif'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&amp;lt; '&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 12pt; FONT-FAMILY: 'MS Mincho'; mso-ansi-language: EN; mso-bidi-font-family: 'MS Mincho'"&gt;は、&lt;/SPAN&gt;&lt;SPAN lang=EN style="FONT-SIZE: 12pt; FONT-FAMILY: 'Times New Roman','serif'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt; ' b &amp;gt; &lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 12pt; FONT-FAMILY: 'MS Mincho'; mso-ansi-language: EN; mso-bidi-font-family: 'MS Mincho'"&gt;（&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 12pt; FONT-FAMILY: 'Times New Roman','serif'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt; &lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 12pt; FONT-FAMILY: 'MS Mincho'; mso-ansi-language: EN; mso-bidi-font-family: 'MS Mincho'"&gt;（&lt;/SPAN&gt;&lt;SPAN lang=EN style="FONT-SIZE: 12pt; FONT-FAMILY: 'Times New Roman','serif'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt; x &lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 12pt; FONT-FAMILY: 'MS Mincho'; mso-ansi-language: EN; mso-bidi-font-family: 'MS Mincho'"&gt;、&lt;/SPAN&gt;&lt;SPAN lang=EN style="FONT-SIZE: 12pt; FONT-FAMILY: 'Times New Roman','serif'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt; y &lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 12pt; FONT-FAMILY: 'MS Mincho'; mso-ansi-language: EN; mso-bidi-font-family: 'MS Mincho'"&gt;）に：スワップ&lt;/SPAN&gt;&lt;SPAN lang=EN style="FONT-SIZE: 12pt; FONT-FAMILY: 'Times New Roman','serif'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&amp;lt; ' b &lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 12pt; FONT-FAMILY: 'MS Mincho'; mso-ansi-language: EN; mso-bidi-font-family: 'MS Mincho'"&gt;、&lt;/SPAN&gt;&lt;SPAN lang=EN style="FONT-SIZE: 12pt; FONT-FAMILY: 'Times New Roman','serif'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt; ' a &amp;gt;&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 12pt; FONT-FAMILY: 'MS Mincho'; mso-ansi-language: EN; mso-bidi-font-family: 'MS Mincho'"&gt;を参照）&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 12pt; FONT-FAMILY: 'Times New Roman','serif'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt; &lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 12pt; FONT-FAMILY: 'MS Mincho'; mso-ansi-language: EN; mso-bidi-font-family: 'MS Mincho'"&gt;：スワップ&lt;/SPAN&gt;&lt;SPAN lang=EN style="FONT-SIZE: 12pt; FONT-FAMILY: 'Times New Roman','serif'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&amp;lt; '&lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 12pt; FONT-FAMILY: 'MS Mincho'; mso-ansi-language: EN; mso-bidi-font-family: 'MS Mincho'"&gt;は、&lt;/SPAN&gt;&lt;SPAN lang=EN style="FONT-SIZE: 12pt; FONT-FAMILY: 'Times New Roman','serif'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt; ' b &amp;gt; = &lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 12pt; FONT-FAMILY: 'MS Mincho'; mso-ansi-language: EN; mso-bidi-font-family: 'MS Mincho'"&gt;（イは、&lt;/SPAN&gt;&lt;SPAN lang=EN style="FONT-SIZE: 12pt; FONT-FAMILY: 'Times New Roman','serif'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt; X &lt;/SPAN&gt;&lt;SPAN style="FONT-SIZE: 12pt; FONT-FAMILY: 'MS Mincho'; mso-ansi-language: EN; mso-bidi-font-family: 'MS Mincho'"&gt;）&lt;/SPAN&gt;&lt;SPAN lang=EN style="FONT-SIZE: 12pt; FONT-FAMILY: 'Times New Roman','serif'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;"&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 10pt; LINE-HEIGHT: normal; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 12pt; FONT-FAMILY: 'Times New Roman','serif'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;Anyways, my job is to update our F# compiler test automation to be localization agonistic. Meaning that tests will work just fine on both English, Japanese, and any of the other dozen or so languages Visual Studio gets localized to.&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 10pt; LINE-HEIGHT: normal; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 12pt; FONT-FAMILY: 'Times New Roman','serif'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;The majority of our compiler automation works by taking a code file, compiling and running it, and if the process returns with a non-zero exit code report a failure. Negative tests - where we expect the code file not to compile – work by checking the compiler output for specific messages.&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 10pt; LINE-HEIGHT: normal; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 12pt; FONT-FAMILY: 'Times New Roman','serif'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;The following is a sample F# compiler testcase. Note that the ‘expected message’ is an arbitrary regular expression, which is why the ‘(‘ and ‘)’ need to be escaped with a backslash.&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; COLOR: green; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;// FSB 1488, Implement redundancy checking for dynamic type test patterns&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; COLOR: green; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; COLOR: green; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;//&amp;lt;Expects status=warning&amp;gt;\(9,7-9,16\): warning FS0026: This rule will never be matched&amp;lt;/Expects&amp;gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; COLOR: green; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;//&amp;lt;Expects status=warning&amp;gt;\(15,7-15,16\): warning FS0026: This rule will never be matched&amp;lt;/Expects&amp;gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; COLOR: green; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; COLOR: blue; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;let &lt;/SPAN&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;_ = &lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;match &lt;/SPAN&gt;box &lt;SPAN style="COLOR: maroon"&gt;"3" &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;with &lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; COLOR: blue; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;| :? string&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;-&amp;gt; &lt;/SPAN&gt;1 &lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;| :? string&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;-&amp;gt; &lt;/SPAN&gt;1&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: green"&gt;// check this rule is marked as 'never be matched'&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; COLOR: green; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;| _ &lt;SPAN style="COLOR: blue"&gt;-&amp;gt; &lt;/SPAN&gt;2&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; COLOR: blue; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;let &lt;/SPAN&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;_ = &lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;match &lt;/SPAN&gt;box &lt;SPAN style="COLOR: maroon"&gt;"3" &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;with &lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; COLOR: blue; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;| :? System.IComparable &lt;SPAN style="COLOR: blue"&gt;-&amp;gt; &lt;/SPAN&gt;1 &lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;| :? string&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;-&amp;gt; &lt;/SPAN&gt;1&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: green"&gt;// check this rule is marked as 'never be matched'&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; COLOR: green; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;| _ &lt;SPAN style="COLOR: blue"&gt;-&amp;gt; &lt;/SPAN&gt;2&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;exit 0&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 10pt; LINE-HEIGHT: normal; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 12pt; FONT-FAMILY: 'Times New Roman','serif'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;As you can probably guess, matching against English compiler output is problematic when testing a localized compiler. The F# QA team (consisting of 3 people) discussed a few options, but the design we settled on was simply encode more metadata into the ‘Expects’ tag, and simply not validate specific error text on non-English builds.&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 10pt; LINE-HEIGHT: normal; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 12pt; FONT-FAMILY: 'Times New Roman','serif'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;So we want to rewrite all of our negative tests to look something like this:&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; COLOR: green; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;// FSB 1488, Implement redundancy checking for dynamic type test patterns&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; COLOR: green; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; COLOR: green; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;//&amp;lt;Expects &lt;B&gt;id="FS0026" span=(9,7-9,16) &lt;/B&gt;status="warning"&amp;gt;This rule will never be matched&amp;lt;/Expects&amp;gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; COLOR: green; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;//&amp;lt;Expects &lt;B&gt;id="FS0026" span=(15,7-15,16)&lt;/B&gt; status="warning"&amp;gt;This rule will never be matched&amp;lt;/Expects&amp;gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; COLOR: green; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; COLOR: blue; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;let &lt;/SPAN&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;_ = &lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;match &lt;/SPAN&gt;box &lt;SPAN style="COLOR: maroon"&gt;"3" &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;with &lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; COLOR: blue; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;| :? string&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;-&amp;gt; &lt;/SPAN&gt;1 &lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;| :? string&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;-&amp;gt; &lt;/SPAN&gt;1&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: green"&gt;// check this rule is marked as 'never be matched'&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; COLOR: green; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;| _ &lt;SPAN style="COLOR: blue"&gt;-&amp;gt; &lt;/SPAN&gt;2&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; COLOR: blue; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;let &lt;/SPAN&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;_ = &lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;match &lt;/SPAN&gt;box &lt;SPAN style="COLOR: maroon"&gt;"3" &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;with &lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; COLOR: blue; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;| :? System.IComparable &lt;SPAN style="COLOR: blue"&gt;-&amp;gt; &lt;/SPAN&gt;1 &lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;| :? string&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;-&amp;gt; &lt;/SPAN&gt;1&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: green"&gt;// check this rule is marked as 'never be matched'&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; COLOR: green; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;| _ &lt;SPAN style="COLOR: blue"&gt;-&amp;gt; &lt;/SPAN&gt;2&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;exit 0&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 10pt; LINE-HEIGHT: normal; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 12pt; FONT-FAMILY: 'Times New Roman','serif'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;When the testcase is in this format, then rather than just matching the ‘message text’ we can build up the regular expression which we will match against the compiler output. So we will look for something like: &lt;I&gt;&amp;lt;span&amp;gt; + &amp;lt;message id&amp;gt; + &amp;lt;text&amp;gt;&lt;/I&gt;. &lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 10pt; LINE-HEIGHT: normal; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 12pt; FONT-FAMILY: 'Times New Roman','serif'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;Then, on localized installs we simply won’t match the text. (But still validate the line/column span of the error, and the error ID from the compiler.) This, combined with a little loc-specific testing, should be enough.&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 10pt; LINE-HEIGHT: normal; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 12pt; FONT-FAMILY: 'Times New Roman','serif'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;So how do you fix the testbed? We have ~1,600 automated testcases which use the &amp;lt;Expects&amp;gt; technique, of those ~600 which need to be updated. As much as I love manually going through and tweaking formatting of testcases, hopefully I can put my F# knowledge to good use and whip up an &lt;A href="http://blogs.msdn.com/chrsmith/archive/tags/Scripting/default.aspx"&gt;&lt;SPAN style="COLOR: blue"&gt;F# script&lt;/SPAN&gt;&lt;/A&gt; do to this for me.&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 10pt; LINE-HEIGHT: normal; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-outline-level: 1"&gt;&lt;B&gt;&lt;SPAN lang=EN style="FONT-SIZE: 24pt; FONT-FAMILY: 'Times New Roman','serif'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN; mso-font-kerning: 18.0pt"&gt;Defining Types&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/B&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 10pt; LINE-HEIGHT: normal; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 12pt; FONT-FAMILY: 'Times New Roman','serif'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;Before solving a problem in F#, the first step is usually defining new types. In this case, we want to create types to describe the metadata encoded in testcases.&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 10pt; LINE-HEIGHT: normal; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 12pt; FONT-FAMILY: 'Times New Roman','serif'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;I’d like to draw your attention to how concise F#’s syntax is for declaring types. If this were C# you would need to sprinkle in property getters and setters, curly braces and semicolons. Instead, creating discriminated unions and records is straight forward. In addition, I’ve added a static Parse methods which we will use later.&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; COLOR: blue; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;type &lt;/SPAN&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;MessageType = &lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;| Warning &lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;| Error &lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;| NotIn &lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;| Success&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;override &lt;/SPAN&gt;this.ToString() =&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;match &lt;/SPAN&gt;this &lt;SPAN style="COLOR: blue"&gt;with&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; COLOR: blue; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;| Warning &lt;SPAN style="COLOR: blue"&gt;-&amp;gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: maroon"&gt;"warning"&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; COLOR: maroon; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;| Error&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;-&amp;gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: maroon"&gt;"error"&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; COLOR: maroon; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;| NotIn&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;-&amp;gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: maroon"&gt;"notin"&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; COLOR: maroon; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;| Success &lt;SPAN style="COLOR: blue"&gt;-&amp;gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: maroon"&gt;"success"&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; COLOR: maroon; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; COLOR: maroon; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; COLOR: blue; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;static member &lt;/SPAN&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;Parse(txt : string) =&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;match &lt;/SPAN&gt;txt.ToUpper() &lt;SPAN style="COLOR: blue"&gt;with&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; COLOR: blue; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;| &lt;SPAN style="COLOR: maroon"&gt;"WARNING" &lt;/SPAN&gt;| &lt;SPAN style="COLOR: maroon"&gt;"\"WARNING\"" &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;-&amp;gt; &lt;/SPAN&gt;Warning&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;| &lt;SPAN style="COLOR: maroon"&gt;"ERROR"&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;/SPAN&gt;| &lt;SPAN style="COLOR: maroon"&gt;"\"ERROR\""&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;-&amp;gt; &lt;/SPAN&gt;Error&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;| &lt;SPAN style="COLOR: maroon"&gt;"NOTIN"&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;/SPAN&gt;| &lt;SPAN style="COLOR: maroon"&gt;"\"NOTIN\""&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;-&amp;gt; &lt;/SPAN&gt;NotIn&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;| &lt;SPAN style="COLOR: maroon"&gt;"SUCCESS" &lt;/SPAN&gt;| &lt;SPAN style="COLOR: maroon"&gt;"\"SUCCESS\"" &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;-&amp;gt; &lt;/SPAN&gt;Success&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;| _ &lt;SPAN style="COLOR: blue"&gt;-&amp;gt; &lt;/SPAN&gt;failwithf &lt;SPAN style="COLOR: maroon"&gt;"Unknown message type: [%s]" &lt;/SPAN&gt;txt&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; COLOR: blue; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;type &lt;/SPAN&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;MessageRange = &lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;| NoRange&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: green"&gt;// No error range specified&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; COLOR: green; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;| OnePoint &lt;SPAN style="COLOR: blue"&gt;of &lt;/SPAN&gt;int * int&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: green"&gt;// (a,b)&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; COLOR: green; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;| TwoPoints &lt;SPAN style="COLOR: blue"&gt;of &lt;/SPAN&gt;int * int * int * int &lt;SPAN style="COLOR: green"&gt;// (a,b-c,d)&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; COLOR: green; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; COLOR: green; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; COLOR: blue; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;static member &lt;/SPAN&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;Parse(txt : string) =&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;let &lt;/SPAN&gt;onePtRegex = &lt;SPAN style="COLOR: maroon"&gt;@".*\\\((\d+),(\d+)\\\).*"&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; COLOR: maroon; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; COLOR: blue; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;let &lt;/SPAN&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;twoPtRegex = &lt;SPAN style="COLOR: maroon"&gt;@".*\\\((\d+),(\d+)-(\d+),(\d+)\\\).*"&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; COLOR: maroon; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; COLOR: maroon; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; COLOR: blue; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;let &lt;/SPAN&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;onePtMatch = Regex.Match(txt, onePtRegex)&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;let &lt;/SPAN&gt;twoPtMatch = Regex.Match(txt, twoPtRegex)&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;if&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;/SPAN&gt;onePtMatch.Success &lt;SPAN style="COLOR: blue"&gt;then &lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; COLOR: blue; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;OnePoint(int onePtMatch.Groups.[1].Value, int onePtMatch.Groups.[2].Value)&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;elif &lt;/SPAN&gt;twoPtMatch.Success &lt;SPAN style="COLOR: blue"&gt;then &lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; COLOR: blue; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;TwoPoints(int twoPtMatch.Groups.[1].Value, int twoPtMatch.Groups.[2].Value,&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;int twoPtMatch.Groups.[3].Value, int twoPtMatch.Groups.[4].Value)&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;else &lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; COLOR: blue; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;NoRange&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; COLOR: blue; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;type &lt;/SPAN&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;ExpectedMessage = &lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;{ &lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;MsgType&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;: MessageType&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;MsgID&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;: string&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;MsgRange : MessageRange&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;MsgText&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;: string &lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;}&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 10pt; LINE-HEIGHT: normal; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-outline-level: 1"&gt;&lt;B&gt;&lt;SPAN lang=EN style="FONT-SIZE: 24pt; FONT-FAMILY: 'Times New Roman','serif'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN; mso-font-kerning: 18.0pt"&gt;Parsing (AKA Regular Expression voodoo)&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/B&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 10pt; LINE-HEIGHT: normal; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 12pt; FONT-FAMILY: 'Times New Roman','serif'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;Here comes the fun part: greping through each tescase file and trying to parse it using regular expressions. &lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 10pt; LINE-HEIGHT: normal; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 12pt; FONT-FAMILY: 'Times New Roman','serif'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;I’ll be honest when I say that we haven’t been super-consistent in how to encode error messages. So some tests have error spans, some don’t. Some match the error ID, some don’t. &lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 10pt; LINE-HEIGHT: normal; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 12pt; FONT-FAMILY: 'Times New Roman','serif'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;Admittedly this code could be better commented, but it should be pretty straight forward. Note that the removeTokens function could easily be rewritten to be a bunch of functions composed together (rather than using piplining). Having the separate ‘fixLineForm'X’ methods makes debugging a tad easier.&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; COLOR: green; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;/// Given the match string for a testcase strip out error spans and compiler error numbers.&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; COLOR: green; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;/// E.G.&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;"\(9,18-9,21\): warning FS0035: This form of object expression is deprecated."&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; COLOR: green; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;/// becomes: "This form of object expression is deprecated"&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; COLOR: blue; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;let &lt;/SPAN&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;removeTokens line =&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;let &lt;/SPAN&gt;fixLine regexPattern (groupIdx : int) line =&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;let &lt;/SPAN&gt;m =&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;Regex.Match(&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;line,&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;regexPattern)&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;if &lt;/SPAN&gt;m.Success &lt;SPAN style="COLOR: blue"&gt;then&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; COLOR: blue; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;m.Groups.[groupIdx].Value&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;else&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; COLOR: blue; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;line&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: green"&gt;// Specify error range (a,b-c,d): error FS????:&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; COLOR: green; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; COLOR: blue; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;let &lt;/SPAN&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;fixLineForm1 = fixLine &lt;SPAN style="COLOR: maroon"&gt;@"\\\(\d+,\d+-\d+,\d+\\\)..(error|warning) FS\d\d\d\d..([^&amp;lt;]*)" &lt;/SPAN&gt;2&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: green"&gt;// Specify error range (a,b): error FS????:&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; COLOR: green; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; COLOR: blue; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;let &lt;/SPAN&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;fixLineForm2 = fixLine &lt;SPAN style="COLOR: maroon"&gt;"\\(\d+,\d+\\): (error|warning) FS\d\d\d\d..([^&amp;lt;]*)" &lt;/SPAN&gt;2&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: green"&gt;// Start with error FS????:&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; COLOR: green; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; COLOR: blue; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;let &lt;/SPAN&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;fixLineForm3 = fixLine &lt;SPAN style="COLOR: maroon"&gt;@"(error|warning) FS\d\d\d\d..([^&amp;lt;]*)" &lt;/SPAN&gt;2&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: green"&gt;// Start with FS????:&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; COLOR: green; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; COLOR: blue; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;let &lt;/SPAN&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;fixLineForm4 = fixLine &lt;SPAN style="COLOR: maroon"&gt;@"FS\d\d\d\d..([^&amp;lt;]*)" &lt;/SPAN&gt;1&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: green"&gt;// Just error range (Note this must come before line form1)&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; COLOR: green; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; COLOR: blue; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;let &lt;/SPAN&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;fixLineForm5 = fixLine &lt;SPAN style="COLOR: maroon"&gt;@"\\\(\d+,\d+-\d+,\d+\\\)..([^&amp;lt;]*)" &lt;/SPAN&gt;1&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: green"&gt;// Just error FS????&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; COLOR: green; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; COLOR: blue; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;let &lt;/SPAN&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;fixLineForm6 = fixLine &lt;SPAN style="COLOR: maroon"&gt;@"(error|warning) FS\d\d\d\d([^&amp;lt;]*)" &lt;/SPAN&gt;2&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;line |&amp;gt; fixLineForm1 |&amp;gt; fixLineForm2 &lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;|&amp;gt; fixLineForm3 |&amp;gt; fixLineForm4&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;|&amp;gt; fixLineForm5&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; COLOR: green; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;/// If the line contains an &amp;lt;Expects&amp;gt; block, parse out the error ID, span, and text&lt;BR&gt;/// and rewrite it making them explicit.&lt;BR&gt;&lt;BR&gt;&lt;/SPAN&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; COLOR: blue; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;let &lt;/SPAN&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;fixExpectedMessageLine line =&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;let &lt;/SPAN&gt;isMessageLineRegex = &lt;SPAN style="COLOR: maroon"&gt;"//.*&amp;lt;Expect[^&amp;gt;]*status=([^&amp;gt;]+)&amp;gt;([^&amp;lt;]*)&amp;lt;/Expect.+"&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; COLOR: maroon; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; COLOR: maroon; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; COLOR: blue; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;let &lt;/SPAN&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;m = Regex.Match(line, isMessageLineRegex)&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;if &lt;/SPAN&gt;m.Success &lt;SPAN style="COLOR: blue"&gt;then&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; COLOR: blue; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; COLOR: green; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;// If we've identified it as a line containing testcase metadata,&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; COLOR: green; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;// parse it and rewrite it.&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; COLOR: green; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; COLOR: blue; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;let &lt;/SPAN&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;message = &lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;{&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;MsgType&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;= MessageType.Parse(m.Groups.[1].Value)&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/SPAN&gt;MsgID&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;= (&lt;SPAN style="COLOR: blue"&gt;let &lt;/SPAN&gt;id = Regex.Match(m.Groups.[2].Value, &lt;SPAN style="COLOR: maroon"&gt;".*(FS\d\d\d\d).*"&lt;/SPAN&gt;)&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;if &lt;/SPAN&gt;id.Success &lt;SPAN style="COLOR: blue"&gt;then &lt;/SPAN&gt;id.Groups.[1].Value&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;else&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN style="COLOR: maroon"&gt;"FS0191"&lt;/SPAN&gt;)&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;MsgRange = MessageRange.Parse(m.Groups.[2].Value)&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;MsgText&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp; &lt;/SPAN&gt;= removeTokens (m.Groups.[2].Value)&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;}&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;let &lt;/SPAN&gt;spanPart = &lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;match &lt;/SPAN&gt;message.MsgRange &lt;SPAN style="COLOR: blue"&gt;with&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; COLOR: blue; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;| NoRange&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;-&amp;gt; &lt;/SPAN&gt;&lt;SPAN style="COLOR: maroon"&gt;""&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; COLOR: maroon; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;| OnePoint(x,y)&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;-&amp;gt; &lt;/SPAN&gt;sprintf &lt;SPAN style="COLOR: maroon"&gt;"span=\"(%d,%d)\" " &lt;/SPAN&gt;x y&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;| TwoPoints(a,b,c,d) &lt;SPAN style="COLOR: blue"&gt;-&amp;gt; &lt;/SPAN&gt;sprintf &lt;SPAN style="COLOR: maroon"&gt;"span=\"(%d,%d,%d,%d)\" " &lt;/SPAN&gt;a b c d&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;if &lt;/SPAN&gt;message.MsgType = Error || message.MsgType = Warning &lt;SPAN style="COLOR: blue"&gt;then&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; COLOR: blue; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; COLOR: blue; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;sprintf&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: maroon"&gt;"//&amp;lt;Expects id=\"%s\" %sstatus=\"%s\"&amp;gt;%s&amp;lt;/Expects&amp;gt;"&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; COLOR: maroon; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;message.MsgID spanPart (message.MsgType.ToString()) message.MsgText&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;else&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; COLOR: blue; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; COLOR: green; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;// Only rewrite negative tests, skip SUCCESS or NOTIN tests...&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; COLOR: green; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;line&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;else&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; COLOR: blue; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; COLOR: green; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;// This line didn't contain any metadata information&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; COLOR: green; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;line&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 10pt; LINE-HEIGHT: normal; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-outline-level: 1"&gt;&lt;B&gt;&lt;SPAN lang=EN style="FONT-SIZE: 24pt; FONT-FAMILY: 'Times New Roman','serif'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN; mso-font-kerning: 18.0pt"&gt;Fixing Testcases&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/B&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 10pt; LINE-HEIGHT: normal; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 12pt; FONT-FAMILY: 'Times New Roman','serif'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;The work to actually fix testcases requires a few utility functions. I’ll cover each one in order.&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 10pt; LINE-HEIGHT: normal; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 12pt; FONT-FAMILY: 'Times New Roman','serif'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;First is my favorite four-line sequence expression: return all files under a given folder. Using yield! inside of a sequence expression is quite sexy.&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; COLOR: blue; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;let rec &lt;/SPAN&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;filesUnder basePath =&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;seq {&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;yield! &lt;/SPAN&gt;Directory.GetFiles(basePath)&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;for &lt;/SPAN&gt;subDir &lt;SPAN style="COLOR: blue"&gt;in &lt;/SPAN&gt;Directory.GetDirectories(basePath) &lt;SPAN style="COLOR: blue"&gt;do&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; COLOR: blue; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;yield! &lt;/SPAN&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;filesUnder subDir }&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 10pt; LINE-HEIGHT: normal; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 12pt; FONT-FAMILY: 'Times New Roman','serif'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;Next is creating a type called FixedFile, which keeps track of any changes we made to the source code. (That is, if we need to rewrite any lines containing testcase metadata.) The code simply tries to modify each line, and if the updated array of strings is different then we know the file has been modified. &lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 10pt; LINE-HEIGHT: normal; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 12pt; FONT-FAMILY: 'Times New Roman','serif'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;You cannot compare two arrays to see if they are equal in C#, because it will use referential equality (comparing pointers.) The F# code on the other hand uses structural equality (comparing array elements).&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; COLOR: blue; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;type &lt;/SPAN&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;FixedFile = { FilePath : string; FileFixed : bool; UpdatedLines : string[] }&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; COLOR: blue; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;let &lt;/SPAN&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;fixFile filePath =&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;let &lt;/SPAN&gt;lines = File.ReadAllLines(filePath)&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&lt;/SPAN&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;let &lt;/SPAN&gt;fixedLines = lines |&amp;gt; Array.map fixExpectedMessageLine&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: green"&gt;// Note use of structural equality&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; COLOR: green; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;{&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;FilePath = filePath&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;FileFixed = (lines &amp;lt;&amp;gt; fixedLines)&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;UpdatedLines = fixedLines &lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;}&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 10pt; LINE-HEIGHT: normal; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 12pt; FONT-FAMILY: 'Times New Roman','serif'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;Next is a couple of functions to checkout a file for edit using using &lt;A href="http://en.wikipedia.org/wiki/Visual_SourceSafe#In-house_use"&gt;&lt;SPAN style="COLOR: blue"&gt;Source Depot&lt;/SPAN&gt;&lt;/A&gt;. (Shelling out to tf.exe to use &lt;A href="http://en.wikipedia.org/wiki/Team_Foundation_Server"&gt;&lt;SPAN style="COLOR: blue"&gt;Visual Studio Team Foundation Server&lt;/SPAN&gt;&lt;/A&gt; would work just as well.)&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; COLOR: green; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;/// Spawns a new process. Returns (exit code, stdout)&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; COLOR: blue; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;let &lt;/SPAN&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;shellExecute executablePath workingDir args =&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;let &lt;/SPAN&gt;startInfo = &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;ProcessStartInfo()&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;startInfo.FileName&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&amp;lt;- executablePath&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;startInfo.WorkingDirectory &amp;lt;- workingDir&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;startInfo.Arguments&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&amp;lt;- args&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;startInfo.UseShellExecute&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&amp;lt;- &lt;SPAN style="COLOR: blue"&gt;false&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; COLOR: blue; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;startInfo.CreateNoWindow&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&amp;lt;- &lt;SPAN style="COLOR: blue"&gt;true&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; COLOR: blue; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;startInfo.RedirectStandardOutput &amp;lt;- &lt;SPAN style="COLOR: blue"&gt;true&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; COLOR: blue; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; COLOR: blue; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;let &lt;/SPAN&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;proc = Process.Start(startInfo)&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;proc.WaitForExit()&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;(proc.ExitCode, proc.StandardOutput.ReadToEnd())&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; COLOR: green; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;/// Checks out a given file for edit&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; COLOR: blue; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;let &lt;/SPAN&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;checkoutFile filePath =&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;printfn &lt;SPAN style="COLOR: maroon"&gt;"Checking out: %s" &lt;/SPAN&gt;filePath&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;o:p&gt;&amp;nbsp;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;let &lt;/SPAN&gt;pathToSD = &lt;SPAN style="COLOR: maroon"&gt;@"d:\Tools\SourceDepot\sd.exe"&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; COLOR: maroon; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; COLOR: blue; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;let &lt;/SPAN&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;enlistmentPath = &lt;SPAN style="COLOR: maroon"&gt;@"D:\dd\cambridge_staging_3\src\"&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; COLOR: maroon; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; COLOR: maroon; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; COLOR: green; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;// Add working directory so SD knows which client to use...&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; COLOR: green; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;/SPAN&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; COLOR: blue; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;let &lt;/SPAN&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;(ec, txt) = shellExecute pathToSD enlistmentPath (&lt;SPAN style="COLOR: maroon"&gt;"edit " &lt;/SPAN&gt;+ filePath)&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;printfn &lt;SPAN style="COLOR: maroon"&gt;"SD exited with code %d\n%s" &lt;/SPAN&gt;ec txt&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;()&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 10pt; LINE-HEIGHT: normal; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto; mso-outline-level: 1"&gt;&lt;B&gt;&lt;SPAN lang=EN style="FONT-SIZE: 24pt; FONT-FAMILY: 'Times New Roman','serif'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN; mso-font-kerning: 18.0pt"&gt;Putting it Together&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/B&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 10pt; LINE-HEIGHT: normal; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 12pt; FONT-FAMILY: 'Times New Roman','serif'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;Unfortunately our script is somewhat anti-climactic. To fix all 600 compiler testcases the actual work is done in six lines of code:&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; COLOR: maroon; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;@"D:\dd\cambridge_staging_3\src\tests\fsharpqa\Source"&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;|&amp;gt; filesUnder&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;|&amp;gt; Seq.map fixFile&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;|&amp;gt; Seq.filter (&lt;SPAN style="COLOR: blue"&gt;fun &lt;/SPAN&gt;fixedFile &lt;SPAN style="COLOR: blue"&gt;-&amp;gt; &lt;/SPAN&gt;fixedFile.FileFixed)&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;|&amp;gt; Seq.iter (&lt;SPAN style="COLOR: blue"&gt;fun &lt;/SPAN&gt;ff &lt;SPAN style="COLOR: blue"&gt;-&amp;gt; &lt;/SPAN&gt;checkoutFile ff.FilePath&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 0pt; LINE-HEIGHT: normal; tab-stops: 45.8pt 91.6pt 137.4pt 183.2pt 229.0pt 274.8pt 320.6pt 366.4pt 412.2pt 458.0pt 503.8pt 549.6pt 595.4pt 641.2pt 687.0pt 732.8pt"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 10pt; FONT-FAMILY: 'Courier New'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;&lt;SPAN style="mso-spacerun: yes"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/SPAN&gt;File.WriteAllLines(ff.FilePath, ff.UpdatedLines))&lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 10pt; LINE-HEIGHT: normal; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 12pt; FONT-FAMILY: 'Times New Roman','serif'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;So about 167 lines later, I have a script file that automates a task that would have easily taken a couple work days to complete. This F# script leveraged the existing IO and Regular Expressions libraries built into .NET, and can easily be packaged into a class library and shared with other developers. &lt;o:p&gt;&lt;/o:p&gt;&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class=MsoNormal style="MARGIN: 0in 0in 10pt; LINE-HEIGHT: normal; mso-margin-top-alt: auto; mso-margin-bottom-alt: auto"&gt;&lt;SPAN lang=EN style="FONT-SIZE: 12pt; FONT-FAMILY: 'Times New Roman','serif'; mso-fareast-font-family: 'Times New Roman'; mso-ansi-language: EN"&gt;So when you next encounter a problem you want to automate, consider looking to see if an F# script is the right solution for you.&lt;/SPAN&gt;&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9599425" width="1" height="1"&gt;&lt;img src="http://feeds.feedburner.com/~r/ChrisSmithsCompletelyUniqueView/~4/IInN3Xg-Vo0" height="1" width="1"/&gt;</description><category domain="http://blogs.msdn.com/chrsmith/archive/tags/Testing/default.aspx">Testing</category><category domain="http://blogs.msdn.com/chrsmith/archive/tags/F_2300_/default.aspx">F#</category><category domain="http://blogs.msdn.com/chrsmith/archive/tags/Scripting/default.aspx">Scripting</category><category domain="http://blogs.msdn.com/chrsmith/archive/tags/Real+World/default.aspx">Real World</category><feedburner:origLink>http://blogs.msdn.com/chrsmith/archive/2009/05/09/f-scripting-zen-bulk-updating-testcases.aspx</feedburner:origLink></item><item><title>F# Community Roundup</title><link>http://feedproxy.google.com/~r/ChrisSmithsCompletelyUniqueView/~3/sAAHpaJ-nJI/f-community-roundup.aspx</link><pubDate>Tue, 05 May 2009 19:17:55 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9589147</guid><dc:creator>ChrSmith</dc:creator><slash:comments>1</slash:comments><comments>http://blogs.msdn.com/chrsmith/comments/9589147.aspx</comments><wfw:commentRss>http://blogs.msdn.com/chrsmith/commentrss.aspx?PostID=9589147</wfw:commentRss><description>&lt;p&gt;There’s plenty going on in the F# community these days, I figured I’d provide a shameless plug for few blog posts or videos I especially liked.&lt;/p&gt;  &lt;h2&gt;&lt;a href="http://groups.google.com/group/toronto-fsharp-study-group"&gt;Toronto F# Study Group&lt;/a&gt;&lt;/h2&gt;  &lt;p&gt;If you live in Soviet Canuckistan and are in the Toronto area, &lt;a href="http://blogs.objectsharp.com/CS/blogs/jlee/rss.aspx"&gt;Justin Lee&lt;/a&gt; is hosting an F# Study Group at the Dark Horse Cafe in Spadina on Thursday, May 7th.&lt;/p&gt;  &lt;h2&gt;&lt;a href="http://www.voyce.com/index.php/2009/04/24/il-analysis-using-fsharp/"&gt;IL analysis using F#&lt;/a&gt;&lt;/h2&gt;  &lt;p&gt;Ian Voyce looks (briefly) at some minimal F# code for picking apart the IL of a managed assembly. This is certainly something that I’d love to see more of in the future. &lt;/p&gt;  &lt;p&gt;To learn a bit more about IL, a great resource is &lt;a href="http://blogs.msdn.com/haibo_luo/default.aspx"&gt;Haibo Luo’s&lt;/a&gt; (now defunct) blog. &lt;/p&gt;  &lt;h2&gt;Jason Olson, the Tom Cruise of F#?&lt;/h2&gt;  &lt;p&gt;&lt;a href="http://www.managed-world.com/"&gt;Jason Olson&lt;/a&gt; F# lover and all around nice guy has been busy the past few weeks:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;&lt;a href="http://channel9.msdn.com/posts/Charles/Jason-Olson-Composing-Programming-Languages-F-and-OO/"&gt;Interview for Channel 9 from Lang.NET&lt;/a&gt;&lt;/li&gt;    &lt;li&gt;&lt;a href="http://channel9.msdn.com/shows/10-4/10-4-Episode-17-F-Intro/"&gt;F# Intro screen cast&lt;/a&gt;&lt;/li&gt; &lt;/ul&gt;  &lt;h2&gt;&lt;a href="http://tomasp.net/blog/imperative-ii-break.aspx"&gt;Imperative Computation in F#&lt;/a&gt;&lt;/h2&gt;  &lt;p&gt;Thomas Petricek has a great blog post up showing how you can create imperative constructs for F# code when using computation expressions. In short, you can add support for break and continue within while loops (just like C#).&lt;/p&gt;  &lt;pre class="code"&gt;&lt;span style="color: green"&gt;// Counts '1, 3, 5, 7, 9'
&lt;/span&gt;imperative { 
    &lt;span style="color: blue"&gt;for &lt;/span&gt;x &lt;span style="color: blue"&gt;in &lt;/span&gt;1 .. 10 &lt;span style="color: blue"&gt;do 
        
        if &lt;/span&gt;x % 2 = 0 &lt;span style="color: blue"&gt;then 
            do! &lt;/span&gt;continue &lt;span style="color: green"&gt;// &amp;lt;---
            
        &lt;/span&gt;printfn &lt;span style="color: maroon"&gt;&amp;quot;number = %d&amp;quot; &lt;/span&gt;x 
}
 
&lt;span style="color: green"&gt;// Counts '1, 2, 3' and then stops   
&lt;/span&gt;imperative { 
    &lt;span style="color: blue"&gt;for &lt;/span&gt;x &lt;span style="color: blue"&gt;in &lt;/span&gt;1 .. 10 &lt;span style="color: blue"&gt;do

      if &lt;/span&gt;x &amp;gt;= 4 &lt;span style="color: blue"&gt;then 
        do! &lt;/span&gt;break &lt;span style="color: green"&gt;// &amp;lt;---

      &lt;/span&gt;printfn &lt;span style="color: maroon"&gt;&amp;quot;number = %d&amp;quot; &lt;/span&gt;!x
}&lt;/pre&gt;

&lt;p&gt;If you’d like to keep a better pulse on what the blogosphere has to say about F#, checkout the &lt;a href="http://feeds.feedburner.com/planet_fsharp"&gt;Planet F#&lt;/a&gt; RSS feed.&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9589147" width="1" height="1"&gt;&lt;img src="http://feeds.feedburner.com/~r/ChrisSmithsCompletelyUniqueView/~4/sAAHpaJ-nJI" height="1" width="1"/&gt;</description><category domain="http://blogs.msdn.com/chrsmith/archive/tags/F_2300_/default.aspx">F#</category><category domain="http://blogs.msdn.com/chrsmith/archive/tags/Shameless+Plugs/default.aspx">Shameless Plugs</category><category domain="http://blogs.msdn.com/chrsmith/archive/tags/Community/default.aspx">Community</category><feedburner:origLink>http://blogs.msdn.com/chrsmith/archive/2009/05/05/f-community-roundup.aspx</feedburner:origLink></item><item><title>Idiomatic F# – Functional vs. Imperative</title><link>http://feedproxy.google.com/~r/ChrisSmithsCompletelyUniqueView/~3/_irZe0zcjPE/idiomatic-f-functional-vs-imperative.aspx</link><pubDate>Thu, 23 Apr 2009 19:37:16 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9565043</guid><dc:creator>ChrSmith</dc:creator><slash:comments>11</slash:comments><comments>http://blogs.msdn.com/chrsmith/comments/9565043.aspx</comments><wfw:commentRss>http://blogs.msdn.com/chrsmith/commentrss.aspx?PostID=9565043</wfw:commentRss><description>&lt;p&gt;&lt;/p&gt;  &lt;p&gt;Our story begins with this guy, Stuart Bowers, sipping functional programming cool aid out of a kickass mug from &lt;a href="http://www.cafepress.com/programmingfs"&gt;Cafe Press&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/IdiomaticFFunctionalvs.Imperative_F1FF/IMAGE_154_2.jpg"&gt;&lt;img title="IMAGE_154" style="border-right: 0px; border-top: 0px; display: inline; border-left: 0px; border-bottom: 0px" height="244" alt="IMAGE_154" src="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/IdiomaticFFunctionalvs.Imperative_F1FF/IMAGE_154_thumb.jpg" width="184" border="0" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;Stuart is a developer on &lt;a href="http://www.microsoft.com/amalga/default.mspx"&gt;Amalga&lt;/a&gt; and full-time F# developer at Microsoft. The world is at a loss because this man does not blog... &lt;/p&gt;  &lt;p&gt;Anyways, he has been reviewing chapters some chapters of &lt;a href="http://oreilly.com/catalog/9780596801359/"&gt;my book&lt;/a&gt; and we recently had a long conversation about what should be idiomatic F# style which I’d like to share. &lt;/p&gt;  &lt;h1&gt;The Problem&lt;/h1&gt;  &lt;p&gt;Question: What is the ‘correct F# way’ to write the following code:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;Create a shared, mutable value and spawn two thread pool threads to sum elements in a list. (Intentionally creating a race condition, which was the point of the code example.)&lt;/p&gt; &lt;/blockquote&gt;  &lt;h2&gt;The Imperative (?) Way&lt;/h2&gt;  &lt;p&gt;Let’s start with how to do this imperatively.&lt;/p&gt;  &lt;pre class="code"&gt;&lt;span style="color: blue"&gt;open &lt;/span&gt;System.Threading

&lt;span style="color: blue"&gt;let &lt;/span&gt;sumArray (arr : int[]) =
    &lt;span style="color: blue"&gt;let &lt;/span&gt;total = ref 0

    &lt;span style="color: green"&gt;// Add the first half
    &lt;/span&gt;&lt;span style="color: blue"&gt;let &lt;/span&gt;thread1Finished = ref &lt;span style="color: blue"&gt;false
    &lt;/span&gt;ThreadPool.QueueUserWorkItem(
        &lt;span style="color: blue"&gt;fun &lt;/span&gt;_ &lt;span style="color: blue"&gt;-&amp;gt; for &lt;/span&gt;i = 0 &lt;span style="color: blue"&gt;to &lt;/span&gt;arr.Length / 2 - 1 &lt;span style="color: blue"&gt;do
                    &lt;/span&gt;total := arr.[i] + !total
                 thread1Finished := &lt;span style="color: blue"&gt;true
        &lt;/span&gt;) |&amp;gt; ignore

    &lt;span style="color: green"&gt;// Add the second half
    &lt;/span&gt;&lt;span style="color: blue"&gt;let &lt;/span&gt;thread2Finished = ref &lt;span style="color: blue"&gt;false
    &lt;/span&gt;ThreadPool.QueueUserWorkItem(
        &lt;span style="color: blue"&gt;fun &lt;/span&gt;_ &lt;span style="color: blue"&gt;-&amp;gt; for &lt;/span&gt;i = arr.Length / 2 &lt;span style="color: blue"&gt;to &lt;/span&gt;arr.Length - 1 &lt;span style="color: blue"&gt;do
                    &lt;/span&gt;total := arr.[i] + !total
                 thread2Finished := &lt;span style="color: blue"&gt;true
        &lt;/span&gt;) |&amp;gt; ignore

    &lt;span style="color: green"&gt;// Wait while the two threads finish their work
    &lt;/span&gt;&lt;span style="color: blue"&gt;while &lt;/span&gt;!thread1Finished = &lt;span style="color: blue"&gt;false &lt;/span&gt;||
          !thread2Finished = &lt;span style="color: blue"&gt;false do

          &lt;/span&gt;Thread.Sleep(0)

    !total&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;The imperative code is very straight forward and offers a few benefits:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Simplicity. Not a whole lot is actually going on, just two calls to QueueUserWorkItem and a couple of boolean flags to keep track of when the threads complete.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;However, there are some drawbacks too:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Redundancy. Both lambdas passed to QueueUserWorkItem are essentially the same, so the code is duplicated. If you want to spice things up, such as adding logging you will either forget to update the code in both locations or simply add it twice.&lt;/li&gt;

  &lt;li&gt;Hidden data. The key difference between the two threads is the range of elements in the array that they sum. The first array counts 0 to len / 2 – 1, the second thread to len / 2 to len. However, this crucial fact is buried in the code in two separate places.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;The Functional (?) Way&lt;/h2&gt;

&lt;p&gt;&lt;span style="color: blue"&gt;&lt;font color="#333333"&gt;Now let’s examine how to do this in a more functional style.&lt;/font&gt;&lt;/span&gt;&lt;/p&gt;

&lt;pre class="code"&gt;&lt;span style="color: blue"&gt;open &lt;/span&gt;System.Threading

&lt;span style="color: blue"&gt;let &lt;/span&gt;sumArray (arr : int[]) =
    &lt;span style="color: green"&gt;// Define a location in shared memory for counting
    &lt;/span&gt;&lt;span style="color: blue"&gt;let &lt;/span&gt;total = ref 0

    &lt;span style="color: green"&gt;// Define two flags in shared memory
    &lt;/span&gt;&lt;span style="color: blue"&gt;let &lt;/span&gt;thread1Finished, thread2Finished = ref &lt;span style="color: blue"&gt;false&lt;/span&gt;, ref &lt;span style="color: blue"&gt;false
    
    &lt;/span&gt;&lt;span style="color: green"&gt;// Generate a lambda to sum a section of the array. 
    &lt;/span&gt;&lt;span style="color: blue"&gt;let &lt;/span&gt;sumElements (startIndex,endIndex) flag = 
          &lt;span style="color: blue"&gt;fun &lt;/span&gt;(_:obj) &lt;span style="color: blue"&gt;-&amp;gt; 
              for &lt;/span&gt;i = startIndex &lt;span style="color: blue"&gt;to &lt;/span&gt;endIndex &lt;span style="color: blue"&gt;do
                &lt;/span&gt;total := arr.[i] + !total
              flag := &lt;span style="color: blue"&gt;true  
    
    &lt;/span&gt;&lt;span style="color: green"&gt;// Divy up the array
    &lt;/span&gt;&lt;span style="color: blue"&gt;let &lt;/span&gt;firstHalf  = 0,(arr.Length / 2 - 1)  
    &lt;span style="color: blue"&gt;let &lt;/span&gt;secondHalf = (snd firstHalf)+1,(arr.Length - 1)
    
    &lt;span style="color: green"&gt;// Generate Delegates to sum portions of the array
    &lt;/span&gt;&lt;span style="color: blue"&gt;let &lt;/span&gt;thread1Delegate = sumElements  firstHalf  thread1Finished
    &lt;span style="color: blue"&gt;let &lt;/span&gt;thread2Delegate = sumElements  secondHalf thread2Finished
    
    [ thread1Delegate; thread2Delegate ]       &lt;span style="color: green"&gt;// Queue up the delegates     
    &lt;/span&gt;|&amp;gt; List.map ThreadPool.QueueUserWorkItem   &lt;span style="color: green"&gt;// Queue the use work items
    &lt;/span&gt;|&amp;gt; ignore                                  &lt;span style="color: green"&gt;// Ignore the results 
        
    // Wait while the two threads finish their work
    &lt;/span&gt;&lt;span style="color: blue"&gt;while &lt;/span&gt;!thread1Finished = &lt;span style="color: blue"&gt;false &lt;/span&gt;||
          !thread2Finished = &lt;span style="color: blue"&gt;false do

          &lt;/span&gt;Thread.Sleep(0)

    !total&lt;/pre&gt;
&lt;a href="http://11011.net/software/vspaste"&gt;&lt;/a&gt;

&lt;p&gt;Let me start with the drawbacks of this functional style first:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Too many values. There are seven let bindings in the function – presumably they are all important.&lt;/li&gt;

  &lt;li&gt;Concept count. This more functional way of doing thing certainly requires you to understand a bit about F# coding. (Mapping the thread code to a curried QueueUserWorkItem is pretty hot though.)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;While arguably obfuscated, the functional style offers some clear benefits:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Important data is called out. Rather than hard coding the ‘0 to len / 2’ and ‘len / 2 to len’ values, the bounds for which to sum array elements is called out explicitly and on consecutive lines. This makes declaring an off-by-one error much easier to spot and fix.&lt;/li&gt;

  &lt;li&gt;Code reuse. Rather than hard coding the two thread pool functions, a sumElements function is introduced which takes explicit bounds to sum.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Personally I’m partial to the simplicity of the first example, but the value in calling out the range values in the second example shouldn’t be discounted. One of the best things I like about F# is that being a multi-paradigm language there is usually more than one approach to solve a problem, meaning you have options.&lt;/p&gt;

&lt;p&gt;Thanks goes to Stuart for letting me post his code. I’m curious to hear what you think with regard to the two styles, please leave a comment and let me know what you think.&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9565043" width="1" height="1"&gt;&lt;img src="http://feeds.feedburner.com/~r/ChrisSmithsCompletelyUniqueView/~4/_irZe0zcjPE" height="1" width="1"/&gt;</description><category domain="http://blogs.msdn.com/chrsmith/archive/tags/F_2300_/default.aspx">F#</category><category domain="http://blogs.msdn.com/chrsmith/archive/tags/F_2300_+Design/default.aspx">F# Design</category><feedburner:origLink>http://blogs.msdn.com/chrsmith/archive/2009/04/23/idiomatic-f-functional-vs-imperative.aspx</feedburner:origLink></item><item><title>F# and the PFX Round 1</title><link>http://feedproxy.google.com/~r/ChrisSmithsCompletelyUniqueView/~3/TimH8LkG8IQ/f-and-the-pfx-round-1.aspx</link><pubDate>Wed, 08 Apr 2009 23:21:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9538885</guid><dc:creator>ChrSmith</dc:creator><slash:comments>11</slash:comments><comments>http://blogs.msdn.com/chrsmith/comments/9538885.aspx</comments><wfw:commentRss>http://blogs.msdn.com/chrsmith/commentrss.aspx?PostID=9538885</wfw:commentRss><description>&lt;P&gt;I’m currently working on a chapter for &lt;A href="http://oreilly.com/catalog/9780596801359/" mce_href="http://oreilly.com/catalog/9780596801359/"&gt;Programming F#&lt;/A&gt; titled &lt;EM&gt;Asynchronous and Parallel Programming &lt;/EM&gt;which should turn out pretty well. Anyways, I have an example that was too awesome not to blog.&lt;/P&gt;
&lt;P&gt;In this post I’ll show how to use the Parallel Extensions to the .NET Framework for finding the shortest path between two nodes on a graph.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Problem Description&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;Let’s say you are planning a road trip this summer, you will start in city X and travel to city Y. Since your car cannot fly, you cannot head straight to city Y. Instead, you need to find the shortest path from X to Y. (With bonus points for site seeing, like the &lt;A href="http://www.worldslargestthings.com/iowa/rocker.htm" mce_href="http://www.worldslargestthings.com/iowa/rocker.htm"&gt;World’s Largest Rocking Chair&lt;/A&gt; in Iowa)&lt;/P&gt;
&lt;P&gt;&lt;A href="http://www.ddj.com/security/187201451;jsessionid=NY1K313YWRT4GQSNDLRSKH0CJUNN2JVN?_requestid=588900" mce_href="http://www.ddj.com/security/187201451;jsessionid=NY1K313YWRT4GQSNDLRSKH0CJUNN2JVN?_requestid=588900"&gt;CS Gangstas&lt;/A&gt; have studied this problem and gave it the banal name ‘&lt;A href="http://en.wikipedia.org/wiki/Shortest_path_problem" mce_href="http://en.wikipedia.org/wiki/Shortest_path_problem"&gt;Shortest path problem&lt;/A&gt;’. If you do your research you can find plenty of clever and efficient algorithms; in this blog post I’ll just be solving this problem using a simple approach.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;The Algorithm&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;&lt;A href="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/FTheParallelFXandFlyingacrosstheUS_78F6/image_2.png" mce_href="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/FTheParallelFXandFlyingacrosstheUS_78F6/image_2.png"&gt;&lt;IMG title=image style="BORDER-TOP-WIDTH: 0px; DISPLAY: inline; BORDER-LEFT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; BORDER-RIGHT-WIDTH: 0px" height=327 alt=image src="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/FTheParallelFXandFlyingacrosstheUS_78F6/image_thumb.png" width=553 border=0 mce_src="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/FTheParallelFXandFlyingacrosstheUS_78F6/image_thumb.png"&gt;&lt;/A&gt; &lt;/P&gt;
&lt;P&gt;The simplest way to solve this problem is create a dictionary of ‘shortest known path to city X’. Then, keep track of the cities you would like to visit and the distance traveled so far on that route. &lt;/P&gt;
&lt;P&gt;If you are at a city and the distance you have traveled so far exceeds the shortest known path, then return because you already know a shorter route to that city. &lt;/P&gt;
&lt;P&gt;Otherwise, update your ‘shortest known path’ data structure, and visit all of the city’s neighbors and repeat the process. Once you have exhaustively tried all paths the resulting ‘shortest known path’ data structure will contain the shortest path from your starting city to your final destination.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Lame Solution in C#&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;Let’s try to quickly write this up in C#.&lt;/P&gt;&lt;PRE class=code&gt;    &lt;SPAN style="COLOR: blue"&gt;enum &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;City
    &lt;/SPAN&gt;{
        LosAngeles,
        Seattle, 
        &lt;SPAN style="COLOR: green"&gt;// [List cities here]
        &lt;/SPAN&gt;Boston,
        NewYork
    }

    &lt;SPAN style="COLOR: gray"&gt;/// &amp;lt;summary&amp;gt;
    /// &lt;/SPAN&gt;&lt;SPAN style="COLOR: green"&gt;Initialize the routes between cities and the distances. 
    &lt;/SPAN&gt;&lt;SPAN style="COLOR: gray"&gt;/// &lt;/SPAN&gt;&lt;SPAN style="COLOR: green"&gt;Example: int distTweenBostonAndChicago = x[Boston][Chicago];
    &lt;/SPAN&gt;&lt;SPAN style="COLOR: gray"&gt;/// &amp;lt;/summary&amp;gt;
    &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;static void &lt;/SPAN&gt;InitializeDistances(&lt;SPAN style="COLOR: #2b91af"&gt;Dictionary&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;City&lt;/SPAN&gt;, &lt;SPAN style="COLOR: #2b91af"&gt;Dictionary&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;City&lt;/SPAN&gt;, &lt;SPAN style="COLOR: blue"&gt;int&lt;/SPAN&gt;&amp;gt;&amp;gt; dist)
    {
        &lt;SPAN style="COLOR: green"&gt;// [Load your data here]
        &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;return new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;Dictionary&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;City&lt;/SPAN&gt;, &lt;SPAN style="COLOR: #2b91af"&gt;Dictionary&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;City&lt;/SPAN&gt;, &lt;SPAN style="COLOR: blue"&gt;int&lt;/SPAN&gt;&amp;gt;&amp;gt;();
    }

    &lt;SPAN style="COLOR: gray"&gt;/// &amp;lt;summary&amp;gt;
    /// &lt;/SPAN&gt;&lt;SPAN style="COLOR: green"&gt;Object to represent a route to a given city.
    &lt;/SPAN&gt;&lt;SPAN style="COLOR: gray"&gt;/// &amp;lt;/summary&amp;gt;
    &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;class &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;Route
    &lt;/SPAN&gt;{
        &lt;SPAN style="COLOR: blue"&gt;public &lt;/SPAN&gt;Route()
        {
            DistanceTraveled = 0;
            Route = &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;List&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;City&lt;/SPAN&gt;&amp;gt;();
        }
        &lt;SPAN style="COLOR: gray"&gt;/// &amp;lt;summary&amp;gt;
        /// &lt;/SPAN&gt;&lt;SPAN style="COLOR: green"&gt;Add a new leg to an existing route.
        &lt;/SPAN&gt;&lt;SPAN style="COLOR: gray"&gt;/// &amp;lt;/summary&amp;gt;
        &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;public &lt;/SPAN&gt;Route(&lt;SPAN style="COLOR: #2b91af"&gt;Route &lt;/SPAN&gt;r, &lt;SPAN style="COLOR: #2b91af"&gt;City &lt;/SPAN&gt;nextCity, &lt;SPAN style="COLOR: blue"&gt;int &lt;/SPAN&gt;distance)
        {
            DistanceTraveled = r.DistanceTraveled + distance;
            Route = &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;List&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;City&lt;/SPAN&gt;&amp;gt;(r.Route);
            Route.Add(nextCity);
        }
        &lt;SPAN style="COLOR: blue"&gt;public int &lt;/SPAN&gt;DistanceTraveled { &lt;SPAN style="COLOR: blue"&gt;get&lt;/SPAN&gt;; &lt;SPAN style="COLOR: blue"&gt;set&lt;/SPAN&gt;; }
        &lt;SPAN style="COLOR: blue"&gt;public &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;List&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;City&lt;/SPAN&gt;&amp;gt; Route { &lt;SPAN style="COLOR: blue"&gt;get&lt;/SPAN&gt;; &lt;SPAN style="COLOR: blue"&gt;set&lt;/SPAN&gt;; }
    }

    &lt;SPAN style="COLOR: gray"&gt;/// &amp;lt;summary&amp;gt;
    /// &lt;/SPAN&gt;&lt;SPAN style="COLOR: green"&gt;This makes up for C# not having Tuples...
    &lt;/SPAN&gt;&lt;SPAN style="COLOR: gray"&gt;/// &amp;lt;/summary&amp;gt;
    &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;class &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;CityToVisit
    &lt;/SPAN&gt;{
        &lt;SPAN style="COLOR: blue"&gt;public &lt;/SPAN&gt;CityToVisit(&lt;SPAN style="COLOR: #2b91af"&gt;City &lt;/SPAN&gt;c, &lt;SPAN style="COLOR: #2b91af"&gt;Route &lt;/SPAN&gt;r)
        {
            &lt;SPAN style="COLOR: blue"&gt;this&lt;/SPAN&gt;.City = c;
            &lt;SPAN style="COLOR: blue"&gt;this&lt;/SPAN&gt;.Route = r;
        }
        &lt;SPAN style="COLOR: blue"&gt;public &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;City &lt;/SPAN&gt;City { &lt;SPAN style="COLOR: blue"&gt;get&lt;/SPAN&gt;; &lt;SPAN style="COLOR: blue"&gt;set&lt;/SPAN&gt;; }
        &lt;SPAN style="COLOR: blue"&gt;public &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;Route &lt;/SPAN&gt;Route { &lt;SPAN style="COLOR: blue"&gt;get&lt;/SPAN&gt;; &lt;SPAN style="COLOR: blue"&gt;set&lt;/SPAN&gt;; }
    }

    &lt;SPAN style="COLOR: blue"&gt;static void &lt;/SPAN&gt;Main(&lt;SPAN style="COLOR: blue"&gt;string&lt;/SPAN&gt;[] args)
    {
        &lt;SPAN style="COLOR: blue"&gt;var &lt;/SPAN&gt;distTweenCities = &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;Dictionary&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;City&lt;/SPAN&gt;, &lt;SPAN style="COLOR: #2b91af"&gt;Dictionary&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;City&lt;/SPAN&gt;, &lt;SPAN style="COLOR: blue"&gt;int&lt;/SPAN&gt;&amp;gt;&amp;gt;();
        InitializeDistances(distTweenCities);

        &lt;SPAN style="COLOR: blue"&gt;var &lt;/SPAN&gt;StartingCity = &lt;SPAN style="COLOR: #2b91af"&gt;City&lt;/SPAN&gt;.LosAngeles;
        &lt;SPAN style="COLOR: blue"&gt;var &lt;/SPAN&gt;FinalDestination = &lt;SPAN style="COLOR: #2b91af"&gt;City&lt;/SPAN&gt;.NewYork;

        &lt;SPAN style="COLOR: green"&gt;// Keep track of the shorest paths to get from the starting city to
        // any other reachable city.
        &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;var &lt;/SPAN&gt;shortestPaths = &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;Dictionary&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;City&lt;/SPAN&gt;, &lt;SPAN style="COLOR: #2b91af"&gt;Route&lt;/SPAN&gt;&amp;gt;();

        &lt;SPAN style="COLOR: green"&gt;// Initialize our 'cities to visit' list, begining at our start city having
        // traveled zero miles.
        &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;var &lt;/SPAN&gt;citiesToVisit = &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;Stack&lt;/SPAN&gt;&amp;lt;&lt;SPAN style="COLOR: #2b91af"&gt;CityToVisit&lt;/SPAN&gt;&amp;gt;();
        citiesToVisit.Push(&lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;CityToVisit&lt;/SPAN&gt;(&lt;SPAN style="COLOR: #2b91af"&gt;City&lt;/SPAN&gt;.LosAngeles, &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;Route&lt;/SPAN&gt;());


        &lt;SPAN style="COLOR: blue"&gt;while &lt;/SPAN&gt;(citiesToVisit.Count &amp;gt; 0)
        {
            &lt;SPAN style="COLOR: blue"&gt;var &lt;/SPAN&gt;curLoc = citiesToVisit.Pop();

            &lt;SPAN style="COLOR: green"&gt;// Have we visited this city before? If not, then add it...
            &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;if &lt;/SPAN&gt;(!shortestPaths.ContainsKey(curLoc.City))
                shortestPaths.Add(curLoc.City, nextCity.Route);

            &lt;SPAN style="COLOR: green"&gt;// Is the route we used to get here shorter than the best known?
            &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;if &lt;/SPAN&gt;(shortestPaths[curLoc.City] &amp;lt; curLoc.Route.DistanceTraveled)
            {
                &lt;SPAN style="COLOR: green"&gt;// Update our shortest paths...
                &lt;/SPAN&gt;shortestPaths[curLoc.City] = nextCity.Route;

                &lt;SPAN style="COLOR: green"&gt;// ... and visit all of its neighbors using this shortest path
                &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;foreach &lt;/SPAN&gt;(&lt;SPAN style="COLOR: blue"&gt;var &lt;/SPAN&gt;neighboringCity &lt;SPAN style="COLOR: blue"&gt;in &lt;/SPAN&gt;distTweenCities[curLoc.City].Keys)
                {
                    &lt;SPAN style="COLOR: blue"&gt;var &lt;/SPAN&gt;updatedRoute = &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;Route&lt;/SPAN&gt;(curLoc.Route, &lt;BR&gt;                                                 neighboringCity, &lt;BR&gt;                                                 distTweenCities[curLoc.City][neighboringCity];
                    &lt;SPAN style="COLOR: blue"&gt;var &lt;/SPAN&gt;cityToVisit = &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;&lt;SPAN style="COLOR: #2b91af"&gt;CityToVisit&lt;/SPAN&gt;(neighboringCity, updatedRoute); 
                    
                    citiesToVisit.Push(cityToVisit);
                }
            }
        }

        &lt;SPAN style="COLOR: #2b91af"&gt;Console&lt;/SPAN&gt;.WriteLine(&lt;SPAN style="COLOR: #a31515"&gt;"Shorest path from {0} to {1} is {2} miles."&lt;/SPAN&gt;,
                          StartingCity, FinalDestination, 
                          shortestPaths[StartingCity][FinalDestination]);
    }
}&lt;/PRE&gt;&lt;A href="http://11011.net/software/vspaste" mce_href="http://11011.net/software/vspaste"&gt;&lt;/A&gt;
&lt;P&gt;&lt;FONT color=#009933&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Awesome Solution in F#&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;So while the above code solves the problem, it suffers two major setbacks. First, the algorithm behaves on order O(N^2), which means it is slow. This wouldn’t be as much of a problem if it weren’t for problem two: the implementation is single threaded. &lt;/P&gt;
&lt;P&gt;Being either slow or being single threaded is OK, but both at the same time is bad news.&lt;/P&gt;
&lt;P&gt;Fortunately in CLR 4.0 (&lt;A href="http://www.microsoft.com/downloads/details.aspx?FamilyId=348F73FD-593D-4B3C-B055-694C50D2B0F3&amp;amp;displaylang=en" mce_href="http://www.microsoft.com/downloads/details.aspx?FamilyId=348F73FD-593D-4B3C-B055-694C50D2B0F3&amp;amp;displaylang=en"&gt;and available on 3.5 in CTP form&lt;/A&gt;) the &lt;A href="http://blogs.msdn.com/pfxteam/default.aspx" mce_href="http://blogs.msdn.com/pfxteam/default.aspx"&gt;Parallel Extensions to the .NET Framework&lt;/A&gt; (PFX) make parallelizing code pretty simple.&lt;/P&gt;
&lt;P&gt;It is pretty clear how you to execute our algorithm in parallel, simple parallelize the process of visiting each city. The problem however comes when you are trying to read or write from the shorestPaths dictionary. Having multiple threads read and write from the same data structure at the same time is a recipe for disaster.&lt;/P&gt;
&lt;P&gt;However, the PFX contain some built-in collection types that are designed exactly for this sort of application. The PFX ConcurrentDictionary type acts and behaves just like a normal dictionary, except that you can safely use it in a concurrent environment. (I know that sounds really vague, I’ll write more about the benefits of the ConcurrentDictionary type in a later post.)&lt;/P&gt;
&lt;BLOCKQUOTE&gt;
&lt;P&gt;Pedant’s Note: The solution locks on STDOUT so output messages don’t spew nonsense to the output; however this effectively makes the program run synchronously.&lt;/P&gt;&lt;/BLOCKQUOTE&gt;&lt;PRE class=code&gt;&lt;SPAN style="COLOR: blue"&gt;open &lt;/SPAN&gt;System
&lt;SPAN style="COLOR: blue"&gt;open &lt;/SPAN&gt;System.Threading.Tasks
&lt;SPAN style="COLOR: blue"&gt;open &lt;/SPAN&gt;System.Collections.Generic
&lt;SPAN style="COLOR: blue"&gt;open &lt;/SPAN&gt;System.Collections.Concurrent
    
&lt;SPAN style="COLOR: blue"&gt;type &lt;/SPAN&gt;City = 
    | Boise     | LosAngeles    | NewYork   | Seattle
    | StLouis   | Phoenix       | Boston    | Chicago   
    | Denver
    
&lt;SPAN style="COLOR: green"&gt;// Known disances between US cities in miles. If there is a path from A to B,
// there is also a path from B to A. If no path is listed, then you cannot travel
// between the two cities.
&lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;let &lt;/SPAN&gt;distTweenCities = 
    &lt;SPAN style="COLOR: blue"&gt;let &lt;/SPAN&gt;distances = &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;Dictionary&amp;lt;City, Dictionary&amp;lt;City, int&amp;gt;&amp;gt;()
    
    [
        (Boise,   Seattle, 496);      (Boise,   Denver,  830);    
        (Boise,   Chicago, 1702);     (Seattle, LosAngeles, 1141); 
        (Seattle, Denver,  1321);     (LosAngeles, Denver,  1022);  
        (LosAngeles, Phoenix, 371);   (Phoenix, Denver,  809);      
        (Phoenix, StLouis, 1504);     (Denver,  StLouis, 8588);     
        (Denver,  Chicago, 1009);     (Chicago, NewYork, 811);     
        (Chicago, Boston,  986);      (StLouis, Chicago, 300);
        (Boston, StLouis,  986);      (NewYork, Boston,  211)
    ]
    &lt;SPAN style="COLOR: green"&gt;// Convert the list of links between cities into a dictionary
    &lt;/SPAN&gt;|&amp;gt; List.iter (&lt;SPAN style="COLOR: blue"&gt;fun &lt;/SPAN&gt;(cityA, cityB, dist) &lt;SPAN style="COLOR: blue"&gt;-&amp;gt; 
        
        if &lt;/SPAN&gt;not &amp;lt;| distances.ContainsKey(cityA) &lt;SPAN style="COLOR: blue"&gt;then
            &lt;/SPAN&gt;distances.Add(cityA, &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;Dictionary&amp;lt;City, int&amp;gt;())
        &lt;SPAN style="COLOR: blue"&gt;if &lt;/SPAN&gt;not &amp;lt;| distances.ContainsKey(cityB) &lt;SPAN style="COLOR: blue"&gt;then
            &lt;/SPAN&gt;distances.Add(cityB, &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;Dictionary&amp;lt;City, int&amp;gt;())
            
        distances.[cityA].Add(cityB, dist)
        distances.[cityB].Add(cityA, dist))
        
    &lt;SPAN style="COLOR: green"&gt;// Return our dictionary of dictionaries of distances
    &lt;/SPAN&gt;distances

&lt;SPAN style="COLOR: blue"&gt;let &lt;/SPAN&gt;stdout = Console.Out

&lt;SPAN style="COLOR: blue"&gt;let &lt;/SPAN&gt;shortestPathBetween startingCity finalDestination =
    
    &lt;SPAN style="COLOR: green"&gt;// Keep track of the shorest path from 'startCity' to a given city, and
    // the path used to get to that city.
    &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;let &lt;/SPAN&gt;shortestPaths = &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;ConcurrentDictionary&amp;lt;City, int * City list&amp;gt;()
    
    &lt;SPAN style="COLOR: blue"&gt;let rec &lt;/SPAN&gt;searchForShortestPath curCity distanceSoFar citiesVisitedSoFar = 

        &lt;SPAN style="COLOR: green"&gt;// Visit all available cities from the current city
        &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;let &lt;/SPAN&gt;visitAvailableDestinations() =
            
            &lt;SPAN style="COLOR: blue"&gt;let &lt;/SPAN&gt;availableDestinations = distTweenCities.[curCity]
            
            &lt;SPAN style="COLOR: green"&gt;// Loop through destinations and spawn new tasks
            &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;for &lt;/SPAN&gt;dest &lt;SPAN style="COLOR: blue"&gt;in &lt;/SPAN&gt;availableDestinations.Keys &lt;SPAN style="COLOR: blue"&gt;do
                &lt;/SPAN&gt;Task.Factory.StartNew(
                    &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;Action(&lt;SPAN style="COLOR: blue"&gt;fun &lt;/SPAN&gt;() &lt;SPAN style="COLOR: blue"&gt;-&amp;gt; 
                        &lt;/SPAN&gt;searchForShortestPath 
                            dest 
                            (distTweenCities.[curCity].[dest] + distanceSoFar) 
                            (citiesVisitedSoFar @ [dest])
                )) |&amp;gt; ignore

        &lt;SPAN style="COLOR: green"&gt;// Have I already found a way to travel to this city?
        &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;let &lt;/SPAN&gt;visitedBefore = shortestPaths.ContainsKey(curCity)
        
        &lt;SPAN style="COLOR: blue"&gt;if &lt;/SPAN&gt;not visitedBefore &lt;SPAN style="COLOR: blue"&gt;then
            &lt;/SPAN&gt;&lt;SPAN style="COLOR: green"&gt;// First time visiting this city, add to our 'visited cities'
            &lt;/SPAN&gt;shortestPaths.TryAdd(curCity, (distanceSoFar, citiesVisitedSoFar))
            
            lock stdout 
                 (&lt;SPAN style="COLOR: blue"&gt;fun &lt;/SPAN&gt;() &lt;SPAN style="COLOR: blue"&gt;-&amp;gt; &lt;/SPAN&gt;printfn 
                                &lt;SPAN style="COLOR: maroon"&gt;"Origional route to %A (%d) via: %A" 
                                &lt;/SPAN&gt;curCity distanceSoFar citiesVisitedSoFar)

            
            visitAvailableDestinations()
        &lt;SPAN style="COLOR: blue"&gt;else &lt;/SPAN&gt;&lt;SPAN style="COLOR: green"&gt;// We have visited this city before, let's see if this route is faster
            &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;let &lt;/SPAN&gt;shortestKnownPath, cities = shortestPaths.[curCity]
            
            &lt;SPAN style="COLOR: blue"&gt;if &lt;/SPAN&gt;distanceSoFar &amp;lt; shortestKnownPath &lt;SPAN style="COLOR: blue"&gt;then
                &lt;/SPAN&gt;&lt;SPAN style="COLOR: green"&gt;// Update shortest path, revisit neighboring cities
                &lt;/SPAN&gt;shortestPaths.[curCity] &amp;lt;- (distanceSoFar, citiesVisitedSoFar)
                
                lock stdout 
                     (&lt;SPAN style="COLOR: blue"&gt;fun &lt;/SPAN&gt;() &lt;SPAN style="COLOR: blue"&gt;-&amp;gt; &lt;/SPAN&gt;printfn 
                                    &lt;SPAN style="COLOR: maroon"&gt;"Found shorter route to %A (%d) via:  %A" 
                                    &lt;/SPAN&gt;curCity distanceSoFar citiesVisitedSoFar)
                
                visitAvailableDestinations()
            &lt;SPAN style="COLOR: blue"&gt;else &lt;/SPAN&gt;&lt;SPAN style="COLOR: green"&gt;// Ignore, we have already found a faster way to get here
                &lt;/SPAN&gt;()

    &lt;SPAN style="COLOR: green"&gt;// Create the master task to find the shortest path between the two cities
    &lt;/SPAN&gt;&lt;SPAN style="COLOR: blue"&gt;let &lt;/SPAN&gt;t = 
        Task.Factory.StartNew(
            &lt;SPAN style="COLOR: blue"&gt;new &lt;/SPAN&gt;Action(&lt;SPAN style="COLOR: blue"&gt;fun &lt;/SPAN&gt;() &lt;SPAN style="COLOR: blue"&gt;-&amp;gt; &lt;/SPAN&gt;searchForShortestPath startingCity 0 [])
        )
    t.Wait()
    
    &lt;SPAN style="COLOR: blue"&gt;let &lt;/SPAN&gt;dist, path = shortestPaths.[finalDestination]
    
    printfn 
        &lt;SPAN style="COLOR: maroon"&gt;"The shortest distance from %A to %A is %d miles, with route:\n%A" 
        &lt;/SPAN&gt;startingCity finalDestination 
        dist path&lt;/PRE&gt;&lt;A href="http://11011.net/software/vspaste" mce_href="http://11011.net/software/vspaste"&gt;&lt;/A&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9538885" width="1" height="1"&gt;&lt;img src="http://feeds.feedburner.com/~r/ChrisSmithsCompletelyUniqueView/~4/TimH8LkG8IQ" height="1" width="1"/&gt;</description><category domain="http://blogs.msdn.com/chrsmith/archive/tags/F_2300_/default.aspx">F#</category><category domain="http://blogs.msdn.com/chrsmith/archive/tags/Performance/default.aspx">Performance</category><category domain="http://blogs.msdn.com/chrsmith/archive/tags/PFX/default.aspx">PFX</category><feedburner:origLink>http://blogs.msdn.com/chrsmith/archive/2009/04/08/f-and-the-pfx-round-1.aspx</feedburner:origLink></item><item><title>Book Update – NEW Coauthor!</title><link>http://feedproxy.google.com/~r/ChrisSmithsCompletelyUniqueView/~3/Q-WwP_NhAsI/book-update-new-coauthor.aspx</link><pubDate>Thu, 02 Apr 2009 05:28:03 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9528396</guid><dc:creator>ChrSmith</dc:creator><slash:comments>4</slash:comments><comments>http://blogs.msdn.com/chrsmith/comments/9528396.aspx</comments><wfw:commentRss>http://blogs.msdn.com/chrsmith/commentrss.aspx?PostID=9528396</wfw:commentRss><description>&lt;p&gt;You might be concerned about my lack of blogging, perhaps that I was lost in the woods and perhaps eaten by a bear. Well, unfortunately, all of my time has been devoted to three tasks:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Writing &lt;em&gt;&lt;a href="http://oreilly.com/catalog/9780596801359/"&gt;Programming F#&lt;/a&gt;&lt;/em&gt; &lt;/li&gt;    &lt;li&gt;Passing &lt;a href="http://www.cs.washington.edu/education/courses/csep505/09wi/"&gt;Programming Languages&lt;/a&gt; &lt;/li&gt;    &lt;li&gt;Shipping &lt;a href="http://blogs.msdn.com/chrsmith/archive/2008/12/10/f-no-longer-vaporware.aspx"&gt;F# in Dev10&lt;/a&gt; &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;I would like to give you an update on item #1 my book, as there have been some rather interesting developments. There are plenty of great books on F# being written, and book competition is a great thing. However, one F#-related book in particular has caught my attention:&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;h1&gt;&lt;a href="http://www.manning.com/petricek/"&gt;Real World Functional Programming&lt;/a&gt;&lt;/h1&gt;  &lt;p&gt;By &lt;a href="http://tomasp.net/"&gt;Tomas Petricek&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&lt;a href="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/BookUpdate_B333/clip_image001_2.jpg"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="clip_image001" border="0" alt="clip_image001" src="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/BookUpdate_B333/clip_image001_thumb.jpg" width="154" height="192" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Tomas currently works as an intern at Microsoft Research in Cambridge on F# and is crazy-smart. (Seriously, he’s a level-9 ninja master at F#. Have you checked out &lt;a href="http://www.codeplex.com/fswebtools"&gt;F# Web Tools?&lt;/a&gt;) &lt;/p&gt;  &lt;p&gt;But I’m not too worried about my book competing with his for two reasons:&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;His book is about Functional Programming and mine is specifically about F#. So while there is some overlap, his book is about applications of functional programming while mine is about concepts and syntax. &lt;/li&gt;    &lt;li&gt;His has some creepy looking dude* and mine will (&lt;a href="http://blogs.msdn.com/chrsmith/archive/2009/02/02/petition-for-programming-f-s-book-cover.aspx"&gt;hopefully&lt;/a&gt;) have a fire-breathing Hydra on the cover. &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;For a time I wasn’t worried about Tomas’ book. Until now…&lt;/p&gt;  &lt;p&gt;It was &lt;a href="http://msmvps.com/blogs/jon_skeet/archive/2009/02/27/current-book-project-real-world-functional-programming.aspx"&gt;recently announced&lt;/a&gt; that Manning was adding a co-author to Tomas’ book; none other than &lt;a href="http://msmvps.com/blogs/jon_skeet/default.aspx"&gt;Jon Skeet&lt;/a&gt; himself. Make no mistake, Jon is not some mortal programmer. Rather, his brain &lt;a href="http://stackoverflow.com/users/22656/jon-skeet"&gt;contains 63.8% of all knowledge on StackOverflow&lt;/a&gt;. &lt;/p&gt;  &lt;p&gt;So &lt;em&gt;Real World Functional Programming&lt;/em&gt; not only has one great authoring. But now it has &lt;strong&gt;two&lt;/strong&gt;. So really, any other book on F# or functional programming is simply hosed. No point in publishing it – Tomas Petricek and Jon Skeet are teaming up to write a book on functional programming. Save your time and go home.&lt;/p&gt;  &lt;p&gt;I don’t mind the challenge of competing with this book, but it certainly raises the stakes. &lt;/p&gt;  &lt;p&gt;I’ve been making a few phone calls to &lt;a href="http://www.oreillynet.com/pub/au/27"&gt;Tim O’Reilly&lt;/a&gt; and &lt;a href="http://twitter.com/laurelatoreilly"&gt;Laurel Ruma&lt;/a&gt; about what we can do about this. It took a while to get layers to figure things out, but now I have a new coauthor of my own for &lt;em&gt;Programming F#&lt;/em&gt;:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/BookUpdate_B333/image_2.png"&gt;&lt;img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="image" border="0" alt="image" src="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/BookUpdate_B333/image_thumb.png" width="332" height="440" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;That’s right. &lt;strong&gt;CHUCK NORRIS &lt;/strong&gt;has agreed to not only write the forward, but help coauthor the book to!&lt;/p&gt;  &lt;p&gt;Chuck and I are still working out who will own which chapters, but I’ve been able to get an advanced copy of his forward to the book.&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;Dear Reader,&lt;/p&gt;    &lt;p&gt;The fact you are sitting here reading this forward means that you weren’t already killed by the Russians. You have me and me alone to thank for that. &lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;&lt;/p&gt;    &lt;p&gt;In this book Chris Smith and I will teach you how to roundhouse kick concurrency issues, use an M16 to mow down mutation-related bugs, and how to divide by zero. (I’ve been doing it for years, and trust me – it’s worth it.)&lt;/p&gt;    &lt;p&gt;…&lt;/p&gt;    &lt;p&gt;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;While I am very excited to have Chuck onboard, reading the page on &lt;a href="http://stackoverflow.com/questions/305223/jon-skeet-facts"&gt;Jon Skeet Facts&lt;/a&gt; has me worried.&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Jon Skeet is immutable. If something's going to change, it's going to have to be the rest of the universe. &lt;/li&gt;    &lt;li&gt;The &lt;a href="http://en.wikipedia.org/wiki/Dining_philosophers_problem"&gt;Dining Philosophers&lt;/a&gt; wait while Jon Skeet eats. &lt;/li&gt;    &lt;li&gt;Jon Skeet can recite π. Backwards. &lt;/li&gt;    &lt;li&gt;When Jon gives a method an argument, the method loses &lt;/li&gt;    &lt;li&gt;When Jon pushes a value onto a stack, it &lt;em&gt;stays&lt;/em&gt; pushed &lt;/li&gt;    &lt;li&gt;When invoking one of Jon's callbacks, the runtime adds &amp;quot;please&amp;quot; &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;It may be a tough call as for which book turns out better, but I can’t wait to see the results! In related news, Chapters 1-4 of Programming F# are available on &lt;a href="http://oreilly.com/catalog/9780596801359/"&gt;Rough Cuts&lt;/a&gt; with another couple on the way. So stay tuned!&lt;/p&gt;  &lt;p&gt;*Rumor has it that, the “creepy looking dude” on the cover of &lt;em&gt;Real World Functional Programming&lt;/em&gt; is Danish philosopher &lt;a href="http://en.wikipedia.org/wiki/S%C3%B8ren_Kierkegaard"&gt;Søren Kierkegaard&lt;/a&gt; [&lt;a href="http://www.island-of-freedom.com/tsi/biography.html"&gt;pic&lt;/a&gt;]… but does he breath fire?&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9528396" width="1" height="1"&gt;&lt;img src="http://feeds.feedburner.com/~r/ChrisSmithsCompletelyUniqueView/~4/Q-WwP_NhAsI" height="1" width="1"/&gt;</description><feedburner:origLink>http://blogs.msdn.com/chrsmith/archive/2009/04/01/book-update-new-coauthor.aspx</feedburner:origLink></item><item><title>Petition for Programming F#’s Book Cover!</title><link>http://feedproxy.google.com/~r/ChrisSmithsCompletelyUniqueView/~3/annRgicepzo/petition-for-programming-f-s-book-cover.aspx</link><pubDate>Mon, 02 Feb 2009 21:41:46 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9391122</guid><dc:creator>ChrSmith</dc:creator><slash:comments>21</slash:comments><comments>http://blogs.msdn.com/chrsmith/comments/9391122.aspx</comments><wfw:commentRss>http://blogs.msdn.com/chrsmith/commentrss.aspx?PostID=9391122</wfw:commentRss><description>&lt;p&gt;You might have noticed my blogging has slowed down to a lull; never fear, this is just because I have been working&amp;#160; it is been because I have been hard at work writing I am working full steam on finishing up &lt;i&gt;&lt;a href="http://blogs.msdn.com/chrsmith/archive/2008/10/19/due-out-next-year-programming-f-by-chris-smith.aspx"&gt;Programming F#&lt;/a&gt;&lt;/i&gt;. But &lt;strong&gt;I cannot finish this book without your help&lt;/strong&gt;, read on.&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;The good news&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;The good news is that the first three chapters of &lt;i&gt;Programming F#&lt;/i&gt; should be available online at O’Reilly’s &lt;a href="http://oreilly.com/roughcuts/"&gt;Rough Cuts&lt;/a&gt; site very soon. (Maybe this week…) Signing up for &lt;a href="http://my.safaribooksonline.com/"&gt;Safari&lt;/a&gt; will give you access to pre-release chapters of the book as well as give me feedback on how to make the book better. (Something I would greatly appreciate.)&lt;/p&gt;  &lt;p&gt;&lt;strong&gt;The bad news&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;But to be honest, as much as I’d like your feedback on early chapters of the book what I really need your help on is convincing &lt;a href="http://tim.oreilly.com/"&gt;‘the man’&lt;/a&gt; that Programming F# deserves a better cover than merely &lt;a href="http://oreilly.com/catalog/9780596521066/colophon.html"&gt;a fish&lt;/a&gt;, &lt;a href="http://oreilly.com/catalog/9780596513986/colophon.html"&gt;a rat&lt;/a&gt;, or &lt;a href="http://oreilly.com/catalog/9780596007973/colophon.html"&gt;a rabbit&lt;/a&gt;. Seriously, a rabbit?!? The linked books are all great, but having some cute and cuddly creature on the front doesn’t really inspire me to take the technology seriously.&lt;/p&gt;  &lt;p&gt;That is why when I first announced the book I mocked up a cover with a &lt;a href="http://warhammeronline.wikia.com/wiki/Squig"&gt;Squig&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/PetitionforProgrammingFsBookCover_89E7/Old%20and%20Busted%20Squigg_2.jpg"&gt;&lt;img title="The Squigg - old and busted" style="border-top-width: 0px; display: inline; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="375" alt="The Squigg - old and busted" src="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/PetitionforProgrammingFsBookCover_89E7/Old%20and%20Busted%20Squigg_thumb.jpg" width="280" border="0" /&gt;&lt;/a&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;But &lt;a href="http://tim.oreilly.com/"&gt;‘the man’&lt;/a&gt; shot me down. You see, if O’Reilly is going to start having creatures more awesome than &lt;a href="http://oreilly.com/catalog/9780596153601/"&gt;a frog&lt;/a&gt; on the cover they need to enforce a few other rules:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;The creature should be easily identifiable. The awesomeness of the Squig is self-evident, but few can name what it &lt;em&gt;is&lt;/em&gt; exactly. The cover on the book should be something people could recognize. &lt;/li&gt;    &lt;li&gt;The creature can’t be copyright. Most of the Squig’s awesomeness was due to the fact it was created by &lt;a href="http://www.games-workshop.com/gws/"&gt;Games Workshop&lt;/a&gt;, currently licensed to &lt;a href="http://www.warhammeronline.com/"&gt;Mythic Entertainment&lt;/a&gt;. Licensing stuff like this makes lawyers cry at night. &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;So I literally went back to the drawing board to think about what animal best represents F#. Something that conveys its multi-paradigm nature. Specifically, it supports imperative, object-oriented, and functional programming&lt;/p&gt;  &lt;p&gt;Then it hit me. What creature has three heads and totally kicks ass?&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;h1&gt;&lt;a href="http://en.wikipedia.org/wiki/Cerberus"&gt;&lt;font size="+0"&gt;Cerberus&lt;/font&gt;&lt;/a&gt;&lt;/h1&gt;  &lt;p&gt;&lt;a href="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/PetitionforProgrammingFsBookCover_89E7/800px-Cerberus-Blake_2.jpg"&gt;&lt;img title="800px-Cerberus-Blake" style="border-top-width: 0px; display: inline; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="291" alt="800px-Cerberus-Blake" src="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/PetitionforProgrammingFsBookCover_89E7/800px-Cerberus-Blake_thumb.jpg" width="395" border="0" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&lt;b&gt;Cerberus&lt;/b&gt; (&lt;a href="http://en.wikipedia.org/wiki/Greek_language"&gt;Greek&lt;/a&gt;: Κέρβερος, &lt;i&gt;Kérberos&lt;/i&gt;) is the name given to the entity which, in &lt;a href="http://en.wikipedia.org/wiki/Greek_mythology"&gt;Greek&lt;/a&gt; and &lt;a href="http://en.wikipedia.org/wiki/Roman_mythology"&gt;Roman mythology&lt;/a&gt;, is a multi-headed &lt;a href="http://en.wikipedia.org/wiki/Dog"&gt;dog&lt;/a&gt; which guards the gates of &lt;a href="http://en.wikipedia.org/wiki/Hades"&gt;Hades&lt;/a&gt;, to prevent those who have crossed the &lt;a href="http://en.wikipedia.org/wiki/River_Styx"&gt;river Styx&lt;/a&gt; from ever escaping.&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;Now we are onto something, but to be honest having the gatekeeper for hell on the cover of my book doesn’t sit too well with me. While certainly keeping the denizens of Hades in check is a noble task, it carries along a lot of spirtual baggage. Is Cerberus evil? Or just doing his job?&amp;#160; Also, it isn’t like there are many cerberi – rather there is just the one (that I know of). &lt;/p&gt;  &lt;p&gt;So, unfortunately I need to try again. But the more I think about it I like my second choice much better. Instead of Cerberus I went with a G-D-M-F-fire-breathing-HYDRA!&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;h1&gt;&lt;a href="http://en.wikipedia.org/wiki/Hydra"&gt;&lt;font size="5"&gt;Hydra&lt;/font&gt;&lt;/a&gt;&lt;/h1&gt;  &lt;p&gt;You don’t F with those, you know why? Because it’s got multiple heads, and since the specifics on hydras are pretty unclear I’m going to go ahead and say that the hydra on the cover of my book &lt;strong&gt;is both undead and breathes fire&lt;/strong&gt;. &lt;/p&gt;  &lt;p&gt;Yes people, a lich hydra that breaths hellfire from its multi-paradigm heads of destruction.&lt;/p&gt;  &lt;p&gt;So, I present to you, the cover of my book hopefully awesome enough to make the powers that be rethink their ‘cute and cuddly’ colophons.&lt;/p&gt;  &lt;p&gt;&lt;a href="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/PetitionforProgrammingFsBookCover_89E7/Hydra%20Half_2.jpg"&gt;&lt;img title="Hydra Half" style="border-top-width: 0px; display: inline; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="727" alt="Hydra Half" src="http://blogs.msdn.com/blogfiles/chrsmith/WindowsLiveWriter/PetitionforProgrammingFsBookCover_89E7/Hydra%20Half_thumb.jpg" width="552" border="0" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;Use Multi-Paradigm Programming to Devour Your Foes!&lt;/p&gt;    &lt;p&gt;“The only thing better than one fire-breathing paradigm is three!”&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;Yeah, NOW we are talking. &lt;/p&gt;  &lt;p&gt;&lt;strong&gt;Call to Action!&lt;/strong&gt;&lt;/p&gt;  &lt;p&gt;However, to be clear this isn’t my official book cover, but it would certainly be awesome if it was. So I need your help to convince the good folks at O’Reilly the same.&lt;/p&gt;  &lt;p&gt;So please politely send a tell to &lt;a href="http://twitter.com/laurelatoreilly"&gt;@LaurelAtOReilly&lt;/a&gt; on Twitter and let her know that a Hydra would make a much better cover than whatever the hell is on the cover of &lt;a href="http://oreilly.com/catalog/9780596100292/"&gt;Unix in a Nutshell&lt;/a&gt;. &lt;/p&gt;  &lt;p&gt;I also have a &lt;a href="http://www.cafepress.com/programmingfs"&gt;Cafe Press&lt;/a&gt; site up for T-Shirts. I haven’t received mine in the mail yet so I can’t comment on how well they will turn out.&lt;/p&gt;  &lt;p&gt;Thanks for your help and support. And remember: the ability to breath fire is always better than being furry. Always.&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9391122" width="1" height="1"&gt;&lt;img src="http://feeds.feedburner.com/~r/ChrisSmithsCompletelyUniqueView/~4/annRgicepzo" height="1" width="1"/&gt;</description><feedburner:origLink>http://blogs.msdn.com/chrsmith/archive/2009/02/02/petition-for-programming-f-s-book-cover.aspx</feedburner:origLink></item></channel></rss>
