| Brian's profileInside F#BlogGuestbookNetwork | Help |
|
|
May 25 Improvements to the F# project system inside Visual StudioAs a developer on the F# team, I spend a bit of my time working on the F# project system, so I wanted to briefly share a few new features and bug fixes in the latest release of F#. Today's blog entry is mostly screenshots to call out features you might not otherwise be aware of. First, if you right click on a file in the Solution Explorer and select Properties, you'll see that files now have a 'Copy to Output Directory' property: This is useful for example when you want to drop a data file next to your .exe file (as suggested by the screenshot). Next, if you right click and select Properties on a Reference node, the 'Copy Local' and 'Specific Version' options are there, which enable more control over how references are found and deployed. Also, whereas previous versions of F# had bugs that prevented most uses of 'Solution Folders', now you can use them to organize your projects: Finally, the prior release of F# had a number of bugs when it came to building/rebuilding solutions with multiple projects. Symptoms included:
How embarrassing! Fortunately the latest release of F# fixes these issues. Now you can build with confidence! :) May 20 Improvements to F# data visualization in the Visual Studio debuggerOne of the improvements in the latest release of F# involves the way that F# data types appear inside the Visual Studio debugger. For example, here's a screenshot from F# 1.9.6.2 (the old version) that shows how that version displayed F# data types like lists and discriminated unions: Can you interpret the information in the "Locals" window? Yikes. Clearly there were improvements to be made. Well, now that I have just installed F# 1.9.6.16 (the new version) on my box, here's what I see: What a difference! Now it's easy to see the values in the list and discriminated union. (Eagle-eyed readers may also notice the absence of #light in the second screenshot - #light is now the default. For more details of changes, see the release notes.) This blog entry highlights just one of many improvements in the latest release of F#. I hope to find the time to write about more new features and improvements in the coming days and weeks... in the meantime, I hope you download the new bits and enjoy! How to get started with the new release of F#With the new release of F#, you have a few alternatives for grabbing these new bits to play with the latest F#:
You definitely want to check out the release notes for this release, as it has answers to many frequently asked questions. Don's blog also gives a good overview of the release. Note that if you have a previous version of F# installed, you will need to uninstall it before installing the May 2009 CTP Update. (You can install VS2010 Beta1 side-by-side with an F# CTP.) If you've used F# before, you may be curious about the most likely breaking changes (upgrade risks). F# 1.9.6.16 binaries (the new release) are incompatible with F# 1.9.6.2 binaries (the prior release), so all code must be recompiled. There are some revisions to the language and library relative to the prior CTP, but in our testing, source code migrates extremely smoothly/easily (e.g. often with no source changes, just lots of warnings about deprecated library functions that have been renamed to something else). One exception is the Array.sort function, which previously sorted 'in place', but now, for regularity with the rest of the library, returns a fresh array (the 'in place' version has the new name Array.sortInPlace). The other noteworthy bit is that if you rely on the PowerPack, you should wait to upgrade to VS2010 Beta1 until we publish the updated (1.9.6.16) PowerPack for .Net 4.0 Beta1 (due to some minor snags, it's not online yet; hopefully very soon). (For those using the CTP Update, the PowerPack binaries are included in that distribution, so you're good to go today.) By all means, if you have specific questions about migrating your code to this latest release of F#, ask questions on the Q&A sites I mentioned in a prior blog entry. New with this release: for the first time F# has some documentation on MSDN. (At the time of this posting, there is a minor known bug in the walkthroughs where the code snippets all have extra leading whitespace. Since F# is whitespace-significant by default, be sure to delete this leading whitespace when copying snippets.) These new docs are another good F# reference, as well as a resource for getting started with the language. The F# samples on the MSDN Code Gallery have been updated; these samples are another way to get started with the language by checking out some code. Enjoy! May 16 Brian's favorite online content for learning F#It's mid-May now, which means it's been more than 8 months since we released the first CTP of F# in early September 2008 (F# 1.9.6.2). We've seen continually strong download numbers for that release, and the F# user base continues to grow. I love it; it is great to be working on a product that so many people are enjoying (as well as a product that is making people more productive!). Since the last release, a ton of great content (blogs, Q&A, videos, etc.) about F# has been published on the web, and so I decided to summarize my favorite online content for learning F#. Of course, the very first link you need is the Microsoft F# Developer Center, as it has well-organized links to much of the content listed below. But I have my own favorites, so here they are. VideosLuca's An Introduction to Microsoft F# video from PDC2008 is fantastic - I can't say enough good things about it. If you want the overview talk of what F# is all about, as well as the chance to watch someone build an F# app and talk about the main syntax/features/etc, then grab a comfy chair and sit back and watch this terrific presentation. There is also a good recent video posted on Channel 9 of Don talking about F# and demoing a number of F#'s interactive features. The Microsoft F# Dev Center has links to more videos about F#. Q&AIf you've got questions about F#, the F# community has answers! There are two terrific Q&A sites for getting your F# questions answered:
Both sites have a strong readership, and the time between posting an F# question and receiving a useful answer is often measured in mere minutes. One StackOverflow question is worth calling out: "Getting started with F#", as it is very apropos for this blog entry. My blogOf course my own blog entries are among my favorites. :) For reference, here is a list of my own blog entries that I think will be useful to people learning F#:
(For a more complete overview of F#, you may consider checking out (or contributing to) the F# Wikibook.) Blogs by Microsoft peopleMany of the people who work full time on F# have blogs:
Additionally there are some other MS people who also blog a bit about F#:
There is a ton of content on the web regarding F#; here's a great aggregated feed of F# content:
That's all for now - I hope you find these links helpful! April 10 Transactional effects, part oneThis blog entry describes a useful idiom for coding a set of effects that need 'commit-or-rollback' semantics. OverviewOften times when you're writing code, you have objects that need to maintain some invariants among two or more pieces of mutable state. When you do an operation with a side-effect, you may need to update more than one piece of state in a way that preserves the invariant. Since some sub-operations may fail (e.g. with exceptions), you have to be careful to ensure the invariants are preserved even if the face of a failure mid-stream. Often times this means 'undo'ing some effects to return to the original state. The stuff I am talking about is a lot like transactions, e.g. 'atomic' and 'consistent', with 'commit-or-rollback' semantics. When the 'effects' are just changing values of variables, it is easy to 'undo' these effects - just change the variable back to its original value. But sometimes effects cannot be un-done. If I paint the walls of my bedroom blue, and then I decide I don't like the color, I can't simply click 'undo' to get back to the previous state of the world. (It sure would be handy if I could!) However I can do a 'compensating action' to bring me back to the original state - namely, I can paint the walls again, back to the original color. Similar kinds of 'non-undo-able' effects happen in software. If I call Dispose() on an IDisposable, this cannot be undone. (But I might be able to create a new object in the same state as the one I just Dispose()d.) If I delete or rename a file on the file system, I may not be able to simply 'undo' these actions (but one can imagine possible 'compensating actions' to return the filesystem to its original state). To sum up, there are times when you may find you need to 'effectively-undo' certain actions by performing other 'compensating' actions. But it can be non-trivial to write code that does this correctly. ExampleLet's consider a contrived and silly example to make this more concrete. Suppose I get a new job offer I want to take. I need to quit my old job, move into my new office and paint the office walls my favorite color, and fill out all the usual new-job paperwork. The catch is, some of these operations may fail and revoke the job offer. So if I quit my old job before I actually get the new job finalized, I need to go beg for my old job back as a 'compensating action'. And if I paint the walls of my new office before the new job paperwork is committed, I may have to paint the walls back to the original color as compensating action. To model this in a simple program, I will just print out the commentary of what is happening. Here's some sample C# methods that implement the actions and compensations I described: static Random rng = new System.Random(0); static void QuitMyOldJob() { Console.WriteLine("I quit!"); } static void GetMyOldJobBack() { Console.WriteLine("<get down on knees and beg for old job back>"); } static void MoveIntoNewOffice() { Console.WriteLine("I will paint my new office :)"); if (rng.Next(2) == 0) { Console.WriteLine("They don't let you paint the walls! They took away the job offer!"); throw new Exception("BUMMER!"); } Console.WriteLine("<painted the office blue>"); } static void UndoMoveIntoNewOffice() { Console.WriteLine("<painted the office back to white>"); } static void GetPaperworkApproved() { if (rng.Next(2) == 0) { Console.WriteLine("They discovered you are an ex-con and took away the job offer!"); throw new Exception("BOOO!"); } Console.WriteLine("Your paperwork is ok!"); } Now the goal is to glue these bits together into a program with one of these three possible outputs... /* I got a new job offer! Here is my story... I quit! I will paint my new office :) <painted the office blue> Your paperwork is ok! Success! I got a new job offer! Here is my story... I quit! I will paint my new office :) They don't let you paint the walls! They took away the job offer! <get down on knees and beg for old job back> Oh no, the whole thing fell apart at the last minute: BUMMER! I got a new job offer! Here is my story... I quit! I will paint my new office :) <painted the office blue> They discovered you are an ex-con and took away the job offer! <painted the office back to white> <get down on knees and beg for old job back> Oh no, the whole thing fell apart at the last minute: BOOO! */ ...depending on whether certain phases fail. In the first case, everything succeeds, in the second case, trying to paint the walls fails, and in the third case, the failure happens when completing the job paperwork. So how would you implement it in C#? Here is one possible way: Console.WriteLine("I got a new job offer! Here is my story..."); try { QuitMyOldJob(); try { MoveIntoNewOffice(); } catch (Exception) { GetMyOldJobBack(); throw; } try { GetPaperworkApproved(); } catch (Exception) { UndoMoveIntoNewOffice(); GetMyOldJobBack(); throw; } Console.WriteLine("Success!"); } catch (Exception e) { Console.WriteLine("Oh no, the whole thing fell apart at the last minute: {0}", e.Message); } This is straightforward - for each action that can possibly fail, we surround it with a try-catch and in the catch block we do any necessary compensating actions before re-throwing the exception. This works, but the code is a bit of a mess; when you face a similar situation with real code (rather than all these one-liner function calls) it can become very hard to reason about all the paths through the code to ensure everything works correctly. A better abstractionWhat we need is a handy way to group actions with their compensations and the failure semantics. It turns out that with a suitable method which I'll call "Transactional.Do", we can rewrite the code like this: Console.WriteLine("I got a new job offer! Here is my story..."); try { Transactional.Do(QuitMyOldJob, GetMyOldJobBack, () => Transactional.Do(MoveIntoNewOffice, UndoMoveIntoNewOffice, () => GetPaperworkApproved())); Console.WriteLine("Success!"); } catch (Exception e) { Console.WriteLine("Oh no, the whole thing fell apart at the last minute: {0}", e.Message); } What a difference! 21 lines of code in the original example were reduced to 4 lines of code here. Let's take a closer look at this; here's the definition of the "Transactional" class: class Transactional { /// Run 'stepWithEffect' followed by continuation 'k', but if the continuation later fails with /// an exception, undo the original effect by running 'compensatingEffect'. /// Note: if 'compensatingEffect' throws, it masks the original exception. public static B Do<A, B>(Func<A> stepWithEffect, Action<A> compensatingEffect, Func<A, B> k) { var stepCompleted = false; var allOk = false; A a = default(A); try { a = stepWithEffect(); stepCompleted = true; var r = k(a); allOk = true; return r; } finally { if (!allOk && stepCompleted) { compensatingEffect(a); } } } // if A == void, this is the overload public static B Do<B>(Action stepWithEffect, Action compensatingEffect, Func<B> k) { return Do( () => { stepWithEffect(); return 0; }, (int dummy) => { compensatingEffect(); }, (int dummy) => { return k(); }); } // if A & B are both void, this is the overload public static void Do(Action stepWithEffect, Action compensatingEffect, Action k) { Do( () => { stepWithEffect(); return 0; }, (int dummy) => { compensatingEffect(); }, (int dummy) => { k(); return 0; }); } } Check out the body of the main 'Do' method; it encompasses the general logic of what we need. Namely, if after completing some action, later actions fail, then we need to 'undo' the original effect by running a compensation. If everything succeeds, or if things fail before we have even done the original effect, then there is nothing to undo; in the former case, we 'commit' the result, whereas in the latter case nothing happened yet. (The last two overloads just deal with the annoyance that 'void' is special in C# and you need overloads to deal with both Action<Arg> (when there is no return value) and Func<Arg,Result> (when there is); practically every C# API that uses Action/Func needs to have multiple overloads like this.) With this handy little class, it becomes easy to write short, correct, readable code with transactional effects. Commentary, and looking forwardThis strategy has some limitations in C#, but is nonetheless an effective way to deal with cases where you have a number of sequential effects that need transactional semantics (either everything successfully commits, or else everything 'rolls back' to the original state) where each effect has its own 'undo' compensation. I am interested to hear comments/feedback on the approach, as I don't recall seeing it before, but in retrospect it seems to me like an obviously useful thing. It also happens that Transactional.Do has the right signature to be the 'Bind' of a monad, and so in a future blog entry I'll show how to capture this abstraction in F# using computation expressions, and hopefully show how the F# syntax sugars overcome some of the limitations you'd have in C# (I say 'hopefully' because I haven't worked out all the details fully yet myself). March 31 The basic syntax of F# - typesWhen learning F#, there are three main kinds of information about 'types' that you need to know. First, you need to know the names/aliases of common .Net types (e.g. that "int" means System.Int32). Second, you need to know the names of the main F#-specific types (e.g. "unit") and what these types are/do/mean. Finally, you need to know the syntactic elements used to write F# types (e.g. generics use angle brackets and function types use "->"). So this blog entry covers these useful bits of F# knowledge. I have covered most of this information (at least in passing) in other blog entries on F#; this entry serves mostly to consolidate the stuff on 'types' with lots of links to more detail.
The F# names of common .Net typesHere is a brief list of common .Net types and the aliases those types have in F#:
There are more, but those are the most common. For a full list of basic type abbreviations, see the F# language spec.
Types specific to F#There are a number of F#-specific types; the ones you'll most commonly encounter are: unit, list, option, ref, tuples, Async, Map, and Set. I'll discuss each briefly in turn. The unit type has only one value, written "()". It is a little bit like "void", in the sense that if you have a function that you only call for side-effects (e.g. printf), such a function will have a return type of "unit". Every function takes an argument and returns a result, so you use "unit" to signify that the argument/result is uninteresting/meaningless. (See also this entry.) The list<'T> type is a very common type in F#. It represents an immutable, singly-linked list. List literals are written in square brackets (e.g. "[1;2;3]"). The "::" operator can be used to cons an element onto the front of a list, or in a pattern to decompose a list into its first element and the rest of the list (e.g. "head::rest"). Lists are supported by a variety of functions in the List module. The option<'T> type is used to represent an optional value, either "Some(x)" or "None". See here and here for some more details. The ref<'T> type is sometimes used for creating mutable state. See here and here for details. Tuples are written with commas (and usually parentheses), e.g. "(1,2,3)". The name of the type of a tuple is the names of the types of its components, separated by '*'s. For example, "(true,42)" has type "bool * int". See this entry for details. The Async<'T> type is used for representing asynchronous computations. To learn more, this blog entry is one not bad jumping off point; also check out the PDC video (eight minutes, starting at 52:20, shows off Async; the whole video is a fantastic intro to F#). The F# Map<'Key,'Value> and Set<'T> types are roughly just immutable versions of the common .Net types "Dictionary<Key,Value>" and "HashSet<T>". One other type is worth mentioning: functions. F# function types (e.g. "int -> int") do not have 'names' (unlike e.g. C# where you'd use a named delegate type like "Func<int,int>"). Under the hood, F# represents function types using the FastFunc class. So if you see "FastFunc" (e.g. when viewing F# code in .Net Reflector), that's what it is.
F# syntax for expressing types(Since F# is a type-inferred language, you write out the names of types much more rarely than you do in other languages. Often times much of the interaction you'll have with type names comes from reading the inferred type names that come up in hover-tooltips in Visual Studio.) As mentioned above, F# represents function types using "->" syntax; "A -> R" is a function that takes an A and returns an R (see also here). In F#, a generic type parameter is an identifier preceded by a tick (apostrophe) character. For example, 'a and 'T are common names for generic parameters. As in .Net, generic types use angle bracket syntax, e.g. "Dictionary<'Key,'Value>". When there is a single generic parameter, you'll sometimes see it using 'prefix' syntax rather than angle brackets - most commonly with the F# generic types 'list' and 'option'. So for example "int list" means the same thing as "list<int>", just written a different way (mentioned here). Though you can write "array<int>" or "int array", the way you'll most often see array types written in F# is like this: "int []". Multidimensional array types use commas in the square brackets, so e.g. a two-dimensional array of integers is "int [,]", and a 3-D array is "int [,,]". Type annotations in F# look like "e : type" where 'e' is an expression or a pattern. Type annotations are most commonly used when declaring functions. An example: "let f (x:int) : int = x + 1" - the first ":int" says that the parameter 'x' has type 'int', and the second ":int" says that the return value of the function has type 'int'. Generic parameters on functions are often implicit, as in "let id (x:'a) : 'a = x", but can be explicit, as in "let id<'a> (x:'a) : 'a = x". The '_' character can be used to infer a type without naming it; for example, if 'myList' is a "list<int>" then the expression "myList :> seq<_>" will upcast myList to a "seq<int>" because the '_' was inferred as 'int'. There are a number of other bits of syntax in the type system that are more rarely used, so I describe them just briefly. The syntax #type roughly means "forall 'a when a :> type"; this feature is rarely used/needed. The syntax ^a is similar to 'a but allows for ad-hoc polymorphism ("statically resolved type variables", a la C++ templates) with interesting constraints on types; this feature is very advanced (used almost exclusively by the arithmetic operators). The 'delegate' keyword can be used to create .Net delegate types; this feature is only useful for interop with other .Net languages. February 13 The basic syntax of F# - classes, interfaces, and membersToday's blog entry covers the F# syntax for authoring classes, interfaces, and members. Together with the previous blog entry, this probably covers the most common 90% or so of the language. Again today I will intentionally err on the side of simplicity, at the expense of total accuracy. Defining F# typesThere are lots of ways to define new types and type names in F#, and most involve declarations with the "type" keyword. Today I'll focus on just classes and interfaces; in a future blog entry I'll describe the syntax for the rest of the kinds of types (records, discriminated unions, enums, type abbreviations, units of measure, structs, delegates, exceptions, and modules). Classes (sans interfaces or inheritance)Here is an example skeleton class definition whose only purpose is to demonstrate most of the language syntax involved in defining classes: type public (*1*) MyClass<'a> public (*2*) (x, y) (*3*) as this (*4*) = static let PI = 3.14 static do printfn "static constructor" let mutable z = x + y do printfn "%s" (this.ToString()) (*5*) printfn "more constructor effects" internal new (a) = MyClass(a,a) static member StaticProp = PI static member StaticMethod a = a + 1 member internal self.Prop1 = x member self.Prop2 with get() = z and set(a) = z <- a member self.Method(a,b) = x + y + z + a + b I'll discuss each part in turn; the commented numbers are to help call out specific bits in the prose that follows. A class definition usually starts like this: type SomeClass(constructor-args) = ... but there are lots of optional bits that can go before the '=' when defining a class. Back in the main example, type public (*1*) MyClass<'a> public (*2*) (x, y) (*3*) as this (*4*) = the 'public' before (*1*) is the accessibility of the class type itself; new types default to being public. After the name of the class, if the class is generic, you specify the generic parameters in angle brackets (MyClass<'a> is a class with one generic parameter; the generic parameter is unused in this example, it just demonstrates the syntax). The next portion defines the so-called "implicit constructor" (whose meaning is described in more detail below). The 'public' before (*2*) is the accessibility of the implicit constructor (public is the default) and the stuff inside parentheses before (*3*) are the arguments to the implicit constructor. The "as this" before (*4*) is an optional way to name the current object (you can use any identifier you like, it is lexically scoped to all non-static portions of the class body); the only time you need it is when referring to "this" inside the implicit constructor body (such as on the line marked (*5*) in the main example). The body of the class conceptually has two portions, 'let's and 'do's (which run as part of construction), and 'member's. Both portions can have 'static' and instance (non-static) parts; non-static is the default. Names bound by 'let's are lexically scoped in the class body (and thus are always "private" to the class). The non-static 'let's and 'do's run as the body of the implicit constructor (.ctor), the static 'let's and 'do's comprise the type's static constructor (.cctor). In other words, this code static let PI = 3.14 static do printfn "static constructor" runs when something first refers to the enclosing MyClass type, and this code let mutable z = x + y do printfn "%s" (this.ToString()) (*5*) printfn "more constructor effects" runs whenever you create an instance of MyClass. (As with other .NET languages, it is rare to define a static constructor.) Members are the public interface to functionality in a class, and come in two main flavors: properties and methods. Members without arguments are "getter" properties; members with arguments are methods. From the example: static member StaticProp = PI static member StaticMethod a = a + 1 member internal self.Prop1 = x member self.Prop2 with get() = z and set(a) = z <- a member self.Method(a,b) = x + y + z + a + b Members can be static or not (non-static is the default). Non-static (instance) members must declare a self-identifier. Just as with the optional "as this" from the class declaration, you can use any identifier you like; the identifier is bound to the current object and scoped to the member's body (in these examples I chose "self"). Members default to being public (though "Prop1" demonstrates that you can add an optional accessibility specifier). If you want to define a property with a "setter" as well as a "getter", you can use the syntax as in "Prop2". To define constructors overloads other than the implicit constructor, use a syntax like this: internal new (a) = MyClass(a,a) The accessibility specifier is optional (defaults to public, just like other members). The "body" of the constructor must "call forward" to another constructor (eventually ending up with a call to the implicit constructor). Pragmatically, this means your implicit constructor must initialize everything, and thus probably takes the most arguments of any constructor overload. There are a number of features of members I am omitting for simplicity, including named and optional parameters, overloading, events, and fields. You can read the language spec for more details on these features, or ask questions as a blog comment. InterfacesDefining and using interfaces in F# is very straightforward. An interface is a type that only defines abstract members and/or inherits other interfaces. Here are a couple examples: type IFooable = abstract member Foo : int -> int type IQuxable = abstract member Qux : unit -> string interface IFooable "IFooable" is an interface with a method "Foo" that takes an int and returns an int. "IQuxable" is an interface that inherits "IFooable" and adds another method named "Qux". To have a class implement an interface, just add an 'interface...with' declaration to the end of the class body for each interface you want to implement: type FooQux() = member this.SomeMethod() = printfn "hi" interface IQuxable with member this.Foo x = x + 1 member this.Qux() = "qux!" Here "FooQux" is a class containing a method "SomeMethod" and implementing the "IQuxable" interface. Note that in F#, when a class implements an interface, the interface implementation is always explicit, which means you need an explicit upcast to call interface methods. For example let fooQux = new FooQux() fooQux.SomeMethod() let x = (fooQux :> IFooable).Foo 42 // must upcast to call "Foo" Abstract classes and "virtual" methodsHere is an example of an abstract class: [<AbstractClass>] type SomeBase() = member this.ConcreteMethod y = y + 1 abstract member AbstractMethod : int -> int abstract member VirtualMethod : int -> int default this.VirtualMethod x = x + 1 An abstract class is like a (normal, concrete) class, except it contains some abstract (not implemented) members that a subclass must implement. What would be a "virtual" method in C# is expressed as an 'abstract' method that has a 'default' implementation. An abstract class type must be marked with the "AbstractClass" attribute. InheritanceWith inheritance come three more F# keywords: 'inherit', 'override', and 'base': type SomeDerived() = inherit SomeBase() override this.AbstractMethod z = z + 1 override this.VirtualMethod x = 1 + base.VirtualMethod x member this.OtherMethod() = () The 'inherit' clause defines the base class of a class, and also calls the base constructor as part of the implicit constructor. (That is, in this example the zero-argument implicit constructor of "SomeDerived" calls the zero-argument constructor of "SomeBase".) Abstract members that have no implementation must be overridden by the derived class (or else the derived class can also be marked abstract). Abstract methods with default implementations can be overridden; to call the inherited method, use the 'base' keyword. Other miscellanyI have intentionally omitted many details to keep this blog entry reasonably short (but still cover all the major common bits of syntax). Here are a few notable omissions:
February 08 The basic syntax of F# - keywords and constructsI have written lots of blog entries about F#, but I haven't yet described the basic syntax of the language! So today I'll try to remedy that, describing about a dozen keywords/syntactic-forms that you will most commonly encounter when reading F# code. This blog entry won't cover all the syntax, but it covers perhaps the most common 75% or so. Today I will also intentionally err on the side of simplicity, at the expense of total accuracy. #lightMost F# files start with #light and this just enables the 'lightweight syntax' option. I won't talk about the alternative to the lightweight syntax; everyone always uses this option, and it will be the default in the next release of F#. For now, just ensure this is always at the top of the file. CommentsThere are two kinds of comments in F#, seen here: // a one-line comment (* a multi-line comment (* these can nest *) *) "open" a namespaceThe "open" keyword is used to open a namespace or module. // must fully qualify the name System.Console System.Console.WriteLine("Hello, world!") // after opening the namespace, don't need to open System Console.WriteLine("Hello, world!") "let" defines functions and valuesThe 'let' keyword is used to define both functions and values. Here are examples of using 'let' to define values: let x = 42 // immutable, x is always 42 let mutable y = 0 // mutable, can re-assign y's value with <- operator let z : string = null // ": string" is type annotation to declare type You rarely need type annotations (F# is a type-inferred language), but the last example is one case where a type annotation might be necessary. (Without the annotation, 'z' would be inferred to have type "obj" (System.Object); the annotation says we want 'z' to have type "string".) Here are examples of using 'let' to define functions: let F x = x + 1 let G x y = x + y let G2 (x:float) (y:float) : float = x + y let H(x,y) = x + y let rec Kaboom x = Kaboom (x+1) "F" is a one-argument function. "G" and "G2" take two curried arguments (the latter specifies type annotations for the argument types and the result types of the function, to demonstrate the syntax), whereas "H" takes tupled parameters; to find out more on tuples and currying, you definitely want to read this blog entry. The 'let rec' keyword lets you define a recursive function. The lightweight syntax makes whitespace/indentation significant, and indentation is the normal way to scope function bodies (and many other constructs). Also, functions can be defined at any scope. This code exemplifies all that: let Area diameter = // define a function // everything indented under here is the body of "Area" let pi = 3.14 // define a value inside the function let Radius d = // define another function inside here // this is the body of the "Radius" function d / 2.0 let r = Radius diameter pi * r * r // use the function let answer = Area 5.0 Lambdas are "fun"The "fun" keyword is used to define a lambda (anonymous function). The syntax is "fun args -> body", and the precedence rules usually force you to enclose the whole thing in parentheses. Here's an example: let nums = [1; 2; 3; 4; 5] let odds = List.filter (fun x -> x%2 = 1) nums printfn "odds = %A" odds // odds = [1; 3; 5] In the example, note that '%' is the modulus operator, used here to determine if a number 'x' is odd, and List.filter is a function that applies a predicate (a function returning a bool) to a list, and returns a new list containing only the elements for which the predicate is true. Pipe data with |>One built-in operator is used very commonly: pipe. "x |> f" just means "f x". Thus the previous example would be written more idiomatically as let nums = [1; 2; 3; 4; 5] let odds = nums |> List.filter (fun x -> x%2 = 1) printfn "odds = %A" odds // odds = [1; 3; 5] There is no real benefit to using the pipeline operator in this tiny example, but this operator is often used to "stream" data through a series of transformative functions. See this blog entry for details. Pattern-matching with "match"Pattern matching is a very powerful language feature that can be used in a variety of contexts, but it is most commonly used in a "match" expression: match expr with | pat_1 -> body_1 ... | pat_n -> body_n The expression is tested against each pattern, and the first one that matches causes the corresponding body to be evaluated. The most common patterns you'll see involve simple algebraic data types such as discriminated unions, especially matching on a "list" or an "option"; check out the first half of this blog entry for a description of discriminated unions and how to use pattern matching on them. (I probably will eventually write at least two full blog entries on pattern matching, but the paragraph above and the linked blog entry are enough for you to 'get by' as you are trying to pick up the language.) Conditionals and loopsF# has if-then-else, while loops, and for loops, though you use them less frequently than in other languages (typically you use pattern-matching and recursion instead). And since F# is a functional language, these are all expressions that return values. The syntax for if-then-else has the general form if cond1 then expr1 elif cond2 then expr2 else expr3 The 'elif' and 'else' parts are optional, and you can have as many 'elif' (else if) parts as you like. All the exprn must have the same type, and this is the type of the resulting whole expression. If the 'else' is omitted, the exprn must have type "unit" (which is akin to "void"). The syntax for while is while cond do expr and the whole while expression always returns "unit". There is nothing like "break" or "continue" in F#. There are a variety of for-loop syntactic forms, but the most common one is for pat in expr do bodyexpr Here, expr is something you can enumerate (e.g. an IEnumerable<T>, known in F# as a seq<'a>), pat is any pattern (but most commonly just a new identifier name), and the bodyexpr runs for each element in the enumerated sequence. So for example for x in someArray do printfn "%d" x prints all the integers in "someArray". Like 'while' the whole 'for' expression returns "unit". Constructing objects with "new"You can use 'new' to construct objects just as in C#: let x = new System.Uri("http://hello.world/") though in F# the 'new' keyword is often optional. LiteralsThere are lots of literal forms in the language, but the most common are shown here: let b : bool = true // or false let i : int = 42 let s : string = "hi" let x : float = 3.14 // "3." same as "3.0" let ai : int array = [| 1; 2; 3 |] // "int array"=="array<int>" let lf : float list = [ 1.1; 2.2; 3.3 ] // "float list"=="list<float>" (None of the type annotations are necessary, but they aid my exposition.) Boolean, integer, and string literals work just as you expect. The "float" type corresponds to System.Double and is the type of numerical literals containing a decimal point. Array literals are written with [|these brackets|] whereas list literals are written with [these brackets]; both have elements delimited by semicolons (or newlines). These just demo the most common types; I'll talk more about all the built-in F# types in a future blog entry. Exception constructsF# has constructs like "try-catch-finally" and "using" (IDisposable) from C#. The basic syntaxes are try expr with | pat_i -> body_i try expr finally cleanup use ident = expr You can read a little more about these in this blog entry. What's left?This brief intro probably covers 95% of common syntactic forms of the language, apart from types (defining new types, classes, members, etc.; as well as describing less-common builtin types) and pervasives (builtin operators and functions), both of which I intend to cover in future blog entries. February 05 Where did Brian go?After three or four months of blogging about once per week, all of a sudden I disappeared for more than 9 weeks. What gives? As you may have guessed, in addition to being away for the holidays, I've been busy working on integrating F# into Visual Studio 2010 (and at the same time, improving F# atop VS 2008, since we will continue to ship out-of-band releases of F# before VS 2010 ships). It's been good to be focused at work, but I've been feeling very guilty about not blogging, so I decided to post a 'softball' entry today, in the hopes of gaining some blog-momentum back. What's today's topic? Why it's lambdacats of course! Lambdacats are like LOLcats except that they use obscure functional programming humor. (Thanks to Matt for pointing them out to me.) A typical example that's right up my alley is which plays off the facts that catamorphisms are sometimes written using (|banana-clips|) syntax. Trust me, it's very funny. :) I have a number of ideas for future blog posts... it's just about making the time to actually write them. For example, a couple months ago, after seeing this site, I had to try my hand at a similar problem, yielding results like these Those of you on StackOverflow may recognize that as my gravatar; indeed that's what I was using for test cases to tweak my algorithm: Fun! So of course I want to blog about that (about 300 lines of F#). I also would like to finish off this series describing the relationship between C# and F# code. I'd also like to write about modules, namespaces, and programming at the F# top-level, to help answer questions like these. What would you like to see? Still alive, Brian November 28 What does this C# code look like in F#? (part one: expressions and statements)If you have C# code and just try to transliterate it directly to F#, the F# code you wind up with is unlikely to be idiomatic or "good". Nevertheless, when you are new to a language (F#), it is sometimes useful to know how to transliterate from a well-known language (C#) for those cases where you just don't know the idioms yet, but don't want that to prevent you from making progress. So today's blog entry takes the general form of "here's some C# code, how do I write the same thing in F#". It is intended to be used as a reference or as casual reading to discover some little-used or lesser-known F# syntax/operators/functions. Don't use this blog post as a way to learn the language, instead use the many useful F# tutorials and samples on the web (start here), and just use this blog post to "fill in the gaps" if needed. Today's blog entry covers only code that goes inside a method body, so you won't find anything about declaring classes or using namespaces here. Instead I will be covering the following bits of C#:
and show a way to transliterate those C# forms into the corresponding F#. Along the way I will inject some editorial comments about what is good, bad, idiomatic, etc, but I will not go into much detail. If I leave anything common out, or something is very unclear, feel free to post a question as a comment on this blog entry. Without further ado! CastsThe cast "operator" in C# (saying "(Typename)expr") can mean all kinds of different things in C#, depending on the source type and destination type. I will just call out the four most common conversions done via casts: // C# char c = 'a'; int x = (int)c; // numerical conversion object o = (object)c; // boxing conversion Dog d = new Dog(); Animal a = (Animal)d; // upcast d = (Dog)a; // downcast (may fail at runtime) Here is the corresponding F# code, followed by some commentary. // F# let c = 'a' let x = int c // numerical conversion let o = box c // boxing conversion let d = new Dog() let a = d :> Animal // upcast let d2 = a :?> Dog // downcast (may fail at runtime) Numerical conversions in F# are done via library functions. For example, the function "int" converts a char (or a float or a uint or a whatever) into an int. There are similar functions for each destination type, so for example the function "char" converts it argument to a char. You can read a little more about these functions in the library reference. Note that the "enum" function converts to an enumerated type; the specific enumeration type will be inferred, which sometimes requires a type annotation, as in let y : MyEnumType = enum 0 // F#: y is 0-value of MyEnumType A boxing conversion turns a primitive value into an object. The F# function "box" does this. In fact, "box" will upcast anything to the object type System.Object (which in F# goes by the shorthand name "obj"). Upcast: If you want to make a conversion that goes up a class/interface hierarchy, use the F# syntax "expr :> type". If this compiles, then this conversion will always succeed at runtime. (Note: in F# 1.9.6.2, this expression form has somewhat weird precedence, and so you may sometimes need to surround it with parens, e.g. "(expr :> type)" to make the code parse.) You rarely need to use this operator. Downcast: If you want to make a conversion that goes down a class/interface hierarchy, use the F# syntax "expr :?> type". The question mark inside this operator is meant to suggest that the operation may fail; just as in C#, you may get an InvalidCastException. You should rarely use this operator; in C# you typically prefer "is" and "as", see those expressions below for the corresponding idiomatic F#. OperatorsMany arithmetic (e.g. +, *) and conditional (e.g. &&, ||) operators are the same in F# as in C#. The most common places to get tripped up are (1) with logical negation: in C# it is spelled "!", whereas in F# it is spelled "not"; (2) with equality testing, in C# it is "==" whereas in F# it is just "="; and (3) with inequality, where C# has "!=" whereas F# has "<>". (As for logical negation, note that "!" already has a meaning in F# associated with the "ref" type, which is inherited from OCaml, oh well.) The other somewhat common place to get tripped up is that in C# the bitwise-logic operators are one character (e.g. "|" and "&"), whereas the F# operators are three characters ("|||" and "&&&"); you'll need these operators when using e.g. "Flags" enums. Most F# operators are overloaded, don't be fooled by the type inference tooltips when hovering over code like this in Visual Studio: let f x y = x + y // hover mouse over f, says int -> int -> int This does not mean that "+" only works on ints; you can use "+" to add two floats, or two chars, or even two strings. (The mechanism by which this overloading works involves esoteric black magic involving "inline" and "^a" types. You'll be happier if you stay ignorant of those details; the language/tooltips pick "int" as a default when things are otherwise unconstrained in order to hide the underlying complexity. (A much better "solution" to "how to overload common operators like '+'" is to use type classes, but neither the CLR nor even F# have sufficiently expressive type systems to handle type classes, oh well.)) In C#, the same operator ('=') is used for both initialization and destructive assignment: int i = 3; // initialization i = 4; // destructive assignment In F#, these are separate operators ('=' and '<-'), and only mutable variables admit assignment: let i = 3 // initialization i <- 4 // does not compile, i is immutable let mutable j = 3 j <- 4 // destructive assignment ExpressionsMost expressions involving constructing objects, methods, and properties look the same in C# and F#: new Dog() // constructor s.StartsWith("h", StringComparison.Ordinal) // method call s.Length // property One notable difference is the syntax for indexing of arrays or other types. Whereas in C# you say: var dict = new Dictionary<string, int>(); dict["foo"] = 42; Console.WriteLine(dict["foo"]); in F# you need a dot ('.') before the square brackets: let dict = new Dictionary<string,int>() dict.["foo"] <- 42 printfn "%d" dict.["foo"] There are tons of variations of syntax for doing lambdas/delegates in C#, I'll show only one: Func<int, int, int> f = (x, y) => x + y; // C# lambda and the roughly corresponding F#: let f = (fun x y -> x + y) // F# lambda There are lots of interesting differences between the language when it comes to representing lambdas/functions/delegates, and I will not go into any detail about these differences in today's blog entry. Both C# and F# have "typeof" that returns a System.Type, but C# uses round brackets whereas F# uses angle brackets: typeof(int) // C# typeof typeof<int> // F# typeof Another distinction involves generic types; C# allows you to omit types to get the generic definition: Console.WriteLine(typeof(List<int>).IsGenericTypeDefinition); // false Console.WriteLine(typeof(List<>).IsGenericTypeDefinition); // true whereas F# has a separate operator called "typedefof" for getting uninstantiated generic types: printfn "%A" (typeof<List<int>>.IsGenericTypeDefinition) // false printfn "%A" (typedefof<List<_>>.IsGenericTypeDefinition) // true C# has "is" and "as" operators for type tests. F# uses a particular pattern in a match for this. So this C# code: if (animal is Dog) { Dog dog = animal as Dog; // ... } else if (animal is Cat) { Cat cat = animal as Cat; // ... } becomes this F# code: match animal with | :? Dog as dog -> // ... | :? Cat as cat -> // ... where ":? type" is a type test, and "as ident" names the resulting value of that type if the type test succeeds. (One other aside: in F# "else if" can be abbreviated as "elif".) C# has the ternary operator "?:" for conditional expressions: condition ? trueVal : falseVal F# has the same operator, but its name is if-then-else: if condition then trueVal else falseVal (Note that "if" is used much less frequently in F# than in C#; in F#, many conditional expressions are done via pattern-matching rather than if-then-else.) C# has an operator called "default" that returns the zero-initialization value of a given type: default(int) It has limited utility; most commonly you may use default(T) in a generic. F# has a similar construct as a library function: Unchecked.defaultof<int> These respective constructs are rarely used in C# and F#. StatementsThis section describes how to transliterate C# statements into F#. F# doesn't have "statements", per se; everything is just an expression, and evaluating a a method body just means evaluating its expressions. The expressions that are most statement-like in F# just return "()", the sole value of the "unit" type, which is akin to "void" in C#. C# has three looping constructs: // C# loops while (condition) { SomeCode(); } foreach (var e in someEnumerable) { SomeCode(); } for (int i = 0; i < 10; ++i) { SomeCode(); } F# has just "while" and a "foreach" (spelled "for" in F#); a C# "for" loop can usually be emulated with a "range": // F# loops while condition do SomeCode() for e in someEnumerable do // foreach SomeCode() for i in 0..9 do // compiles like a C# for loop SomeCode() F# lacks anything like "break" or "continue"; you must use control flow and/or boolean flag variables to emulate these constructs. "While" loops in F# are rare, since they imply mutable variables in the condition, and F# often eschews mutables, preferring recursion for simple loops. For(each) loops are also somewhat rarer in F#, since sometimes the form someEnumerable |> Seq.iter (fun e -> SomeCode()) is preferred (especially when the argument to Seq.iter is short). C# has a switch statement. It looks something like this: switch (x) { case 1: SomeCode(); break; default: SomeCode(); break; } In F#, this is just one of many things that pattern matching expresses more succinctly: match x with | 1 -> SomeCode() | _ -> SomeCode() // _ is a 'catch all' default C# has a "return" keyword that exits the current function. There is no comparable construct in F#. Note that the "return" keyword in F# is part of computation expression syntax (a.k.a. "workflows", a.k.a. "monads") and has nothing to do with C#'s "return". As with C#'s "break", in F# you will need to use control-flow constructs to simulate "return" for an early exit. (Though I do occasionally wish for "break" in F#, I have never wished for "return" - I don't recall ever needing/wanting it.) In C#, you raise an exception with the "throw" keyword. In F#, you use the function "raise". throw new Exception("boom"); // C# raise <| new Exception("boom") // F# This is one of the few places in F# where I think it is very idiomatic to use the backward-pipeline operator "<|". Without it, the precedence rules of F# force you to parenthesize the expression: raise( new Exception("boom") ) // F# which I think most people feel looks awkward. C# has a try-catch-finally construct for exception handling. As a result you can write code like this: try { SomeCode(); } catch (NullReferenceException nre) { // swallow it } catch (Exception e) { throw; } finally { SomeOtherCode(); } The equivalent F# code would be: try try SomeCode() with | :? NullReferenceException as nre -> () // swallow it | e -> rethrow() finally SomeOtherCode() There are a few things to point out here. First, in F#, try-with and try-finally are separate constructs - there is no try-with-finally. In practice, you usually only do one or the other (and you should probably be using try-finally about ten times as often as try-catch, in either language - catching exceptions is rarely the right thing to do). F# "catch" blocks just use pattern matching type tests on the exception, much like we saw earlier with the transliteration of C# "is"/"as". In F#, to re-throw the exception, use "rethrow()". C# has a "checked" statement for checking for arithmetic overflow; F# has checked operators in the library, so just open this namespace and use the operators there if you need overflow checking. C# has a "lock" statement for locking an object for a critical section: lock (o) // C# lock { SomeCode(); } In F#, "lock" is a function that takes the lock object and a lambda of the critical section: lock o (fun () -> // F# lock SomeCode() ) C# has "using" for IDisposables: using (var disp = someDisposable) { SomeCode(); } F#'s corresponding syntax: use disp = someDisposable SomeCode() F#'s "use" is like "let", it is scoped to the end of the surrounding block. Inside a C# method that returns an IEnumerable, the following "yield" statement forms are allowed: yield return 42; // C# yield a value yield break; // C# end the enumeration In F#, you don't have to declare a method-returning-IEnumerable to use "yield", instead you can make a sequence expression anywhere using "seq{...}": let myIntSeq : IEnumerable<int> = seq { yield 42; } I added a type annotation just to remind you that "seq" in F# just means "IEnumerable". So the sequence expression on the right-hand-side of the line of code above evaluates to an IEnumerable<int> that yields a single value (42). As with a C# iterator block, you can put arbitrary code using yields in an F# sequence expression. Just as with loops and C# "break", there is no "yield break" in F#. The endI think that just about covers all the interesting C# expressions and statements, showing the corresponding F# counterparts. I hope this is a useful reference for filling in gaps in your F# knowledge while learning F#. November 12 On lambdas, capture, and mutabilityThis blog entry is a little more esoteric than I would like, so the author apologizes up front. :) A C# brain teaserLast time I posed a teaser question: what does this C# code print? List<Func<int>> actions = new List<Func<int>>(); for (int i = 0; i < 5; ++i) { actions.Add( () => i * 2 ); } foreach (var act in actions) { Console.WriteLine( act() ); } At a glance it looks like it may print 0, 2, 4, 6, 8. But in fact it prints 10, 10, 10, 10, 10. The reason is that all five instances of the Func objects created by the lambda are capturing a reference to the same mutable variable instance "i". By the end of the "for" loop, the value of "i" is 5, so invoking the Func objects returns "i*2", which is 10. If you want to write code like that that prints 0, 2, 4, 6, 8, you can do it by changing the "for" loop to this: for (int i = 0; i < 5; ++i) { int copy = i; actions.Add( () => copy * 2 ); } There is a different instance of "copy" for each iteration of the loop. As a result, each lambda captures a different "int" object. If you feel that this is rather subtle, you're not alone. This example is based off a question on StackOverflow. But nearly everyone trips over this at some point. (The astute reader will note that I've even run into it myself on this blog - see the C# code at the end of this blog entry.) For other examples, see this question or this one. And this isn't just limited to C#. People run afoul of this in Python as well, as seen here and here. (I expect there are more such questions; those are just the ones I found when glancing quickly.) In general, with every language that has both mutable variables and closures (lambdas that can capture their environment), you run into this issue. The lambda captures the mutable variable now, but gets evaluated later, after further mutations may have occurred. This is an instance of the more general notion of how "lazy evaluation" and "side effects" don't always mix nicely. (You can read lots more on the topic by doing a web search for e.g. "closure capture value reference".) Ok, fine, so this is a gotcha in most languages with mutables and closures. So, you will ask, how does F# deal with this? I'm so glad you asked! Capture in F#Let's try transliterating that first C# example into F#. I write let FirstAttempt() = let actions = new List<unit->int>() let mutable i = 0 while i < 5 do actions.Add( fun () -> i * 2 ) i <- i + 1 for act in actions do printf "%d " (act()) printfn "" What do you think it will print? The answer: it doesn't compile! The compiler points inside the lambda ("fun") and tells me
One interpretation of this error message is "you are about to fall headlong into this messy gotcha of mutables+closures, so I (the compiler) am going to stop you before you have an accident". Ok, great, so the compiler stopped me before I incautiously drove off a cliff. How do I do what I want? Well, that depends on what I want. The compiler has stopped me from perhaps accidentally capturing mutable state, and now I have to choose. Do I intend to capture mutable state or not? That is, do I want to print "0 2 4 6 8" or "10 10 10 10 10"? If the former, then I need to ensure that the identifier captured by the lambda is not a mutable, which leads naturally to the analogue of the revised C# example: let Option1() = // prints "0 2 4 6 8" let actions = new List<unit->int>() let mutable i = 0 while i < 5 do let copy = i actions.Add( fun () -> copy * 2 ) i <- i + 1 for act in actions do printf "%d " (act()) printfn "" The new identifier "copy" is not declared mutable, so now the lambda can capture it. In each iteration of the loop, "copy" is bound to a different value, so each lambda captures a different value. On the other hand, if I did intend to capture mutable state, then I can use "ref". As suggested by the compiler diagnostic (and discussed in the previous blog entry), one can use ref cells to hold mutable state that can be captured by closures. So to write code like the original C# example I could say let Option2() = // prints "10 10 10 10 10" let actions = new List<unit->int>() let i = ref 0 while !i < 5 do actions.Add( fun () -> !i * 2 ) i := !i + 1 for act in actions do printf "%d " (act()) printfn "" Now "i" has type Ref<int> - an object with a single integer field. "i" itself is immutable (it's a reference to that object in memory; "i" never changes to point to some other object), but the int stored inside the object is mutable. The lambda captures "i", an immutable reference to the mutable object, and so when it finally executes "!i" it will read the current value of the int field in that object. (There's nothing magic about "ref" here, any heap-allocated object would do. The point is I needed to add a layer of indirection so as to get 'reference semantics' rather than 'value semantics'.) Language design commentaryAny time a language designer adds closures to a language, he has to decide the semantics for the symbols being closed over. Ought closures capture by value or by reference? If you're in a totally pure (side-effect-free) language, then it doesn't matter - both "by value" and "by reference" yield the same results. But one you introduce effects, the distinction matters. That's the reason that the programming "teaser" that started this blog entry is, in fact, a brain-teaser; the human reader can easily imagine the program being executed as though the lambdas capture by-value, though in fact C# captures by reference. F# takes an interesting tack here. Rather than choose to capture "by value" or "by reference", the F# compiler notices if these two different capture modes would yield distinctive behavior(*) (simply by noting if any of the captured symbols are declared as local mutables), and if they would, then the program doesn't compile. The advantage of this strategy is that it makes you far less likely to write brain-teaser code (code that you cannot easily predict the behavior of just by reading it). The disadvantage is that when you do really want to capture mutable state, you may have to rewrite a bit of "let mutable" code to use "ref"s instead. Scenarios for capturing mutable state like this are relatively uncommon, so the F# approach seems like a good trade-off. (*) This is not entirely true, as F# lambdas can capture "let mutable" symbols bound at module-scope or class-scope, but not those bound at expression-scope. Why this distinction? Modules and classes are OO software engineering structures designed to encapsulate members in a way that makes it easy to reason about their lifetime, concurrent access & mutability, etc. As a result, capturing these entities is allowed. Expression bindings, on the other hand, are less appropriate software-engineering site for such purposes, and thus the ad-hoc capture of let-bound mutable variables from expression bindings is not part of the F# design. There are a variety of choices available to language designers and compiler implementers... As Jared pointed out in a comment on my prior blog entry, another option is for compilers to emit a warning diagnostic when closing over mutables; apparently this is what VB does (I haven't tried it myself). A final noteOf course, we could have avoided all of these issues by eschewing mutation from the start. When everything is immutable, the code in F# is both shorter to write and harder to misinterpret: let CompletelyImmutableOption() = // prints "0 2 4 6 8" let actions = List.init 5 (fun i -> fun() -> i*2) for act in actions do printf "%d " (act()) printfn "" When nothing is mutable, you don't have to reason about whether the lambda will be called "now" or "later" - the value will always be the same. This is the principle motivation for reducing the number of side-effects in your code; "pure" code without side-effects is immune to changes elsewhere in the program, and thus is easier to reason about (since many considerations, such as 'timing', can be ignored in effect-free code). November 09 The F# "ref" typeI haven't written much about the F# "ref" type, as it's not used all that often. But I have an interesting blog entry coming up that needs "ref", so I thought I should write a short blog entry on the topic to get the basics out of the way. Values and Variables; "let" and "let mutable"In F#, immutability is the default; when I write let x = 1 the symbol 'x' is permanently bound to the value 1 for the whole scope of 'x'. F# introduces the more verbose "let mutable" syntax for creating mutable variables, as in let mutable x = 1 printfn "%d" x // 1 x <- x + 1 printfn "%d" x // 2 The value of a mutable variable can be accessed just by referring to the variable name (e.g. "x"), and an assignment operator "<-" mutates the variable's value. That information is likely "old hat" to you. But did you know there is another way to do mutability in F#? The "ref" typeF# has another construct for mutable state that it inherits from OCaml: refs. A "ref" is a mutable heap-allocated cell that holds one piece of data. Here's a short example: let y = ref 1 printfn "%d" !y // 1 y := !y + 1 printfn "%d" !y // 2 In that snippet, "y" has type "int ref" (a.k.a. "Ref<int>"). There are three notable entities here:
The syntax is a little ugly in my opinion (especially when so many of us are now accustomed to '!' meaning "not"), but it's easy and straightforward to use. For those who like to see a more operational definition of the construct, here is a possible implementation of a type that's very similar to the one built-in to the F# library: type MyRef<'a>(x:'a) = let mutable contents = x member this.Contents with get() = contents and set(x) = contents <- x let ref x = new MyRef<_>(x) let (:=) (x:MyRef<_>) y = x.Contents <- y let (!) (x:MyRef<_>) = x.Contents (In fact, both in F# and OCaml, the built-in ref type uses a "record" as an implementation, but I have said very little about records on this blog, and didn't want to explain one unfamiliar construct via another unfamiliar one, so here I chose to write "MyRef" as a class, instead.) Straightforward, yes? So of course this begs the question: if F# has "let mutable", when would I ever use "ref" (other than to author OCaml-compatible code)? It turns out that in some situations you must use "ref" instead of "let mutable", and I'll describe those situations... in the next blog entry. Next timeHere is a teaser for next time, though. What does the following C# code print? Is it 0, 2, 4, 6, 8? Perhaps you should run it and find out. List<Func<int>> actions = new List<Func<int>>(); for (int i = 0; i < 5; ++i) { actions.Add( () => i * 2 ); } foreach (var act in actions) { Console.WriteLine( act() ); } We'll see how this C# code snippet relates to F# "ref" next time, too! October 17 An oldie but a goodie...What does the following F# program do? Why not run it and find out? #light open System let nl = new String([|char 13;char 10|]) let quote = char 34 let Quote (s:String) = s.Replace(new String([|quote|]), new String([|char 92; quote|])) let Quine s = String.Format("let s = {0}{1}{2}{3}printf {4}%s%s{5} s (Quine s){6}", [| box quote; box (Quote s); box quote; box nl; box quote; box quote; box nl|]) let s = "#light open System let nl = new String([|char 13;char 10|]) let quote = char 34 let Quote (s:String) = s.Replace(new String([|quote|]), new String([|char 92; quote|])) let Quine s = String.Format(\"let s = {0}{1}{2}{3}printf {4}%s%s{5} s (Quine s){6}\", [| box quote; box (Quote s); box quote; box nl; box quote; box quote; box nl|]) " printf "%s%s" s (Quine s) October 16 A programming problem, part four (bet the river!)Last time I finished the "software engineer" solution and briefly discussed some aspects of that strategy. In this blog entry, I'll show the "hacker" solution, and draw comparisons between the two strategies. This final installment of the series is by far the most interesting! A "hacker" solutionTo start things off, I'll use the implicit representations suggested here: //type Card = int * char // rank (ace=14), suit //type Hand = Card list That is, an int-char tuple will be used to represent Cards, and a list of those will represent Hands. I could define these as type aliases in F#, but due to type inference I never actually need type annotations for these, so I don't bother defining them. I define a HandValuation type similar to previous solution. The automatic lexicographical ordering is something a "hacker" wants to leverage. The difference is that this time, I use lists of ranks rather than fixed numbers of them for each case: type HandValuation = | Nothing of int list // descending order | Pair of int list // pair, then kickers in descending order | TwoPair of int list // high pair, low pair, kicker | ThreeOfAKind of int list // trips, kickers in descending order | Straight of int // high card | Flush of int list // descending order | FullHouse of int list // three then two | FourOfAKind of int list // quad, kicker | StraightFlush of int // high card The advantage of e.g. "int list" over "int * int * int" is brevity, both at the definition point and some points of use. The disadvantage is that it's possible to accidentally create a list with an unintended number of entries. I wrote the Evaluate function using the same logic, so it's extremely similar to the other solution. I could have gone a different way, but doing so would not have illustrated any new points I wanted to discuss in this blog series, so I kept things similar for simplicity. (If you want to see a different strategy for Evaluate, check out Laurent's solution.) Note that since ranks are now just "int"s, the code for "isStraight" got a bit simpler, since there's no more converting to/from enums. let Evaluate cards = // ranks in ascending sorted order, so r1 is lowest and r5 is highest let [ r1; r2; r3; r4; r5 ] as sorted = cards |> List.map fst |> List.sort compare // handy helper function let rec AllSame l = match l with | [] | [_] -> true | h::(i::_ as t) -> h = i && AllSame t // decide up front if hand contains a flush and/or a straight let isFlush = cards |> List.map snd |> AllSame let theWheel = [ 2; 3; 4; 5; 14 ] let isStraight = sorted = theWheel // since Ace is valued 14, this is a special case || (sorted |> List.map (fun x -> x - r1)) = [ 0; 1; 2; 3; 4 ] // all the tedious logic for classifying the hand if isStraight && isFlush then StraightFlush r5 elif AllSame [r1;r2;r3;r4] then FourOfAKind [r1;r5] elif AllSame [r2;r3;r4;r5] then FourOfAKind [r2;r1] elif AllSame [r1;r2;r3] && AllSame[r4;r5] then FullHouse [r1;r4] elif AllSame [r1;r2] && AllSame[r3;r4;r5] then FullHouse [r3;r1] elif isFlush then Flush [r5;r4;r3;r2;r1] elif isStraight then Straight r5 elif AllSame[r1;r2;r3] then ThreeOfAKind [r1;r5;r4] elif AllSame[r2;r3;r4] then ThreeOfAKind [r2;r5;r1] elif AllSame[r3;r4;r5] then ThreeOfAKind [r3;r2;r1] elif r1=r2 && r3=r4 then TwoPair [r3;r1;r5] elif r1=r2 && r4=r5 then TwoPair [r4;r1;r3] elif r2=r3 && r4=r5 then TwoPair [r4;r2;r1] elif r1=r2 then Pair [r1;r5;r4;r3] elif r2=r3 then Pair [r2;r5;r4;r1] elif r3=r4 then Pair [r3;r5;r2;r1] elif r4=r5 then Pair [r4;r3;r2;r1] else Nothing [r5;r4;r3;r2;r1] The code for ChooseN is exactly the same as the previous solution, so I don't reproduce it here. The same is true of ValToString. BestHand is quite simplified in this version: let BestHand sevenCards = ChooseN sevenCards 5 |> List.max_by Evaluate I'll talk about BestHand a great deal more in the discussion section below, as this one function highlights a number of differences between the two coding strategies. Thanks to a lack of error-handling and no enums to provoke extra type conversions, the code for MakeCard can be short: let MakeCard (s:string) = (match s.[0] with | 'T' -> 10 | 'J' -> 11 | 'Q' -> 12 | 'K' -> 13 | 'A' -> 14 | digit -> int digit - int '0'), s.[1] Finally, the main algorithm: let lines = fileContents.Split([|"\r\n"|], System.StringSplitOptions.RemoveEmptyEntries) let vals = lines |> Array.map (fun s -> let cards = s.Split([|' '|], System.StringSplitOptions.RemoveEmptyEntries) |> Array.map MakeCard |> List.of_array if cards.Length < 7 then Nothing [] else Evaluate (BestHand cards) ) let bestVal = vals |> Array.max Array.zip lines vals |> Array.iter (fun (s,v) -> match v with | Nothing [] -> printfn "%s" s | _ -> printfn "%s %s %s" s (ValToString v) (if v = bestVal then "(winner)" else "") ) What was previously separate "ParseFile" and "MakePlayer" functions has now just been written inline at the call-sites. Whereas previously a separate data type ("Folded") represented folded hands and an option ("None") represented the valuation of folded hands, now folded hands are just a list of cards whose length is less than 7, and their valuation is represented with the otherwise meaningless HandValuation "Nothing []". (The more flexible valuation representation lets us store uninteresting values using a representation within the domain of the type, whereas in the previous solution we needed a separate type (the None option) to deal with the valuation of folded hands.) That's it! Comparison of the "hacker" solution with "software engineer"True to form, the "hacker" solution is shorter than "software engineer". This one comes in at about 110 lines, compared to about 180 for the other solution (ignoring unit tests). What are the main trade-offs between the two solutions? A deep look at the "BestHand" function is terrifically interesting, as it hosts most of the differences in microcosm. Here once again is the "software engineer" solution: // BestHand: Card -> Card -> Card -> Card -> Card -> Card -> Card -> Hand let BestHand c1 c2 c3 c4 c5 c6 c7 = let allSetsOf5Cards = ChooseN [c1; c2; c3; c4; c5; c6; c7] 5 let allHands = allSetsOf5Cards |> List.map (fun [c1;c2;c3;c4;c5] -> Hand(c1,c2,c3,c4,c5)) allHands |> List.max_by Evaluate and here again is the "hacker" solution: // BestHand: (int * 'a) list -> (int * 'a) list let BestHand sevenCards = ChooseN sevenCards 5 |> List.max_by Evaluate I've added the inferred type signatures in comments. The type signature of the first version enforces a variety of constraints: there are seven cards coming in, five cards going out (recall, a "Hand" was exactly five Cards), and each Card is a Rank and a Suit. Now consider the second version. Here there are no constraints to the number of elements in or out, and the data is a tuple of an int (intended to represent the rank) and any other type (the suit). The reason the "suit" became generic is that the only thing that could impose a constraint on the second part of the tuple was Evaluate, and all it does for suits is check if they are all the same value (the poker "flush" check), which works for any data type. So the "hacker" solution admits a host of potential run-time errors (such as passing in a zero-element list) ruled out by the "software engineer" solution, but also implements a "wider" solution than is necessary to meet the problem spec, but is potentially useful (the "hacker" code can compute the best hand from eight cards, or nine cards, etc.). So the "software engineer" solution leverages the type system to rule out some incorrect or meaningless programs; whereas the "hacker" solution picks up some potentially useful extra behavior. Another advantage to the "software engineer" solution is that the type is self-documenting. Read the signature and it's pretty clear what will happen; with the "hacker" signature, you need more context about the representation to grok what it does. Another advantage to the "hacker" solution is that it is shorter. (By a factor of three!) And the reason is that there is no conversion to and from data structures to mediate the impedance mismatches among various function signatures. "ChooseN" is a very general function, so of course it takes in a list and returns a list. In the "software engineer" solution, I'd represented the cards individually, so I had to put the seven cards in a list to call "ChooseN". And then the result was a list, which meant I had to pick apart that list to get the five cards back out so that I could re-wrap them in my domain-specific type "Hand". The price I paid for the advantages of the extra static type checks was longer code that will be less performant at run-time due to extra data structure conversions. In a sense, this tiny function captures the essence of the ongoing debate between static and dynamic typing. The programmer can create domain-specific static types to structure the program, convey intent, and rule out a class of errors and behaviors at compile-time, at the price of having to author that structure and mediate structural mismatches at module boundaries. Or the programmer can choose to compute most everything with just scalars and lists, in which case data flows easily everywhere, resulting in short code, but with the loss of compile-time checks and conveyance of intent. Both programs yield the correct behavior on well-formed inputs. What about bad input? The "hacker" solution has the spirit of "garbage in, garbage out", whereas the "software engineer" solution imposes stricter expectations and yields error diagnostics when those expectations are violated. Here are a few examples, with commentary. When passed this illegal hand
the "software engineer" solution yields a helpful diagnostic
whereas "hacker" accepts this and decides
The former solution constrained the set of legal suits when parsing the input, and tries to preserve those constraints by representing suits via enums. The latter made no check while parsing and represented suits as just 'char's, so these "suit" values flow freely through the program logic, sometimes with unexpected results. This hand
has similar diagnostic results for "software engineer", but for "hacker" yields the more opaque exception
as it tries to access the second character of the string "J". Finally this hand (with 'extra' cards tacked on the end)
fed to "software engineer" yields this diagnostic
whereas "hacker" says
The hacker behavior is outside the problem specification, but might be useful if we ever need a variation where players have more than just two hole cards in addition to the five community cards. Notice how all of these behaviors are related to the representational choices (discussed earlier) made by each of the two solutions. Summing upI really enjoyed this blog series for a number of reasons:
I hope you learned half as much as I did along the way! Comments welcome! The source codeThe source code for both solutions is available here. The project named "Poker" is the "software engineer", and "Poker2" is "hacker". October 12 A programming problem, part three (make the turn!)Last time I sketched out two different strategies for solving the poker problem ("software engineer" and "hacker"), and started coding the "software engineer" solution. In this blog entry, I'll finish that solution and discuss some characteristics of the strategy. A "software engineer" solution, part twoPicking up where I left off, the next thing to do is select the best 5 cards from a set of 7 (a player's two hole cards plus the five common cards on the board). An algorithm for this is straightforward; I can just enumerate all possible 5-card subsets and then pick the one with the maximum valuation. Here's a generic function for choosing "n" elements from a given list: let rec ChooseN l n = if n < 0 then invalid_arg "n must be >= 0" if n = 0 then [ [] ] // one solution (empty list) else match l with | [] -> [] // no solution (n > list length) | h :: t -> let doPickH = ChooseN t (n-1) |> List.map (fun res -> h :: res) let dontPickH = ChooseN t n doPickH @ dontPickH The logic is straightforward; recurse down the list, and at each step of of the way compute both the solutions that do pick the current list element and those that do not pick the current element. (This is not a particularly efficient implementation; it allocates a lot of extra lists along the way.) With the "ChooseN" function in hand, making the best hand from 7 cards is a snap: let BestHand c1 c2 c3 c4 c5 c6 c7 = let allSetsOf5Cards = ChooseN [c1; c2; c3; c4; c5; c6; c7] 5 let allHands = allSetsOf5Cards |> List.map (fun [c1;c2;c3;c4;c5] -> Hand(c1,c2,c3,c4,c5)) allHands |> List.max_by Evaluate The "max_by" library function selects the list element with the maximum value under a given projection; here it chooses the Hand that has the greatest HandValuation as determined by applying Evaluate to each Hand in the list. That nearly completes all of the implementation logic for the program. Most of the remainder is parsing the input and writing the output. So next up, I need a function to convert strings (like "Kc") into Card objects (like Card(Suit.Club,Rank.King)). let MakeCard (s:string) = if s.Length <> 2 then failwith <| sprintf "Not a legal card: '%s'" s let suits = dict [| 'c', Suit.Club; 'd', Suit.Diamond; 'h', Suit.Heart; 's', Suit.Spade |] let ranks = dict [| 'A', Rank.Ace '2', Rank.Two '3', Rank.Three '4', Rank.Four '5', Rank.Five '6', Rank.Six '7', Rank.Seven '8', Rank.Eight '9', Rank.Nine 'T', Rank.Ten 'J', Rank.Jack 'Q', Rank.Queen 'K', Rank.King |] match ranks.TryGetValue s.[0], suits.TryGetValue s.[1] with | (false,_),_ -> failwith <| sprintf "Not a legal card rank: '%c'" s.[0] | _,(false,_) -> failwith <| sprintf "Not a legal card suit: '%c'" s.[1] | (_,r),(_,s) -> Card(s,r) The "dict" function in F# takes a sequence of tuples representing key-value pairs as input and returns an IDictionary<_,_>. This code also takes advantage of the F# feature that turns "out" parameters into result tuples (which Dustin wrote about here). Looking at the problem spec again, I see I need to read in info on a set of players, and then write it back out with extra information (hand rank and whether the player won) for players that did not fold. So I chose the following representation for parsing each line of input that represents a player: type Player = | Folded | Played of Card * Card * Card * Card * Card * Card * Card let MakePlayer (s:string) = let cards = s.Split([|' '|], System.StringSplitOptions.RemoveEmptyEntries) |> Array.map MakeCard if cards.Length > 7 then failwith <| sprintf "Bad input line '%s'" s match cards with | [| c1; c2; c3; c4; c5; c6; c7 |] -> s, Played(c1,c2,c3,c4,c5,c6,c7) | _ -> s, Folded Note that MakePlayer returns a tuple of the input string and the Player; I'm holding on to the input string since I'll need to write it right back out again in a moment. Now here's some sample input as well as code to parse the whole input. let fileContents = " Kc 9s Ks Kd 9d 3c 6d 9c Ah Ks Kd 9d 3c 6d Ac Qc Ks Kd 9d 3c 9h 5s 4d 2d Ks Kd 9d 3c 6d 9h Kh Ks Kd 9d 3c 6d 7s Ts Ks Kd 9d" let ParseFile (s:string) = let lines = s.Split([|"\r\n"|], System.StringSplitOptions.RemoveEmptyEntries) lines |> Array.map MakePlayer I need one more function, to print the hand rank in the format suggested by the problem spec: let ValToString handVal = match handVal with | Nothing _ -> "Nothing" | Pair _ -> "Pair" | TwoPair _ -> "Two pair" | ThreeOfAKind _ -> "Three of a kind" | Straight _ -> "Straight" | Flush _ -> "Flush" | FullHouse _ -> "Full house" | FourOfAKind _ -> "Four of a kind" | StraightFlush _ -> "Straight flush" Finally, my main algorithm, that ties it all together: let evaledPlayers = ParseFile fileContents |> Array.map (fun (s,p) -> s, match p with | Played(c1,c2,c3,c4,c5,c6,c7) -> Some(BestHand c1 c2 c3 c4 c5 c6 c7 |> Evaluate) | _ -> None ) let bestVal = [| for _,v in evaledPlayers do match v with | None -> () | Some(x) -> yield x |] |> Array.max evaledPlayers |> Array.iter (fun (s,v) -> match v with | None -> printfn "%s" s | Some(v) -> printfn "%s %s %s" s (ValToString v) (if v = bestVal then "(winner)" else "") ) First I compute the best hand valuation for each player (as an "option", using "None" for players that folded). Then I compute the best hand valuation among all the players that did not fold. Finally I print the output for each player in the desired format. The whole way through this code the arrays contain tuples whose first element is the input string ("s"), since I need that data as the first part of the output I need to print. That's it! Discussion of the "software engineer" solutionI'll briefly discuss some aspects of this solution strategy, but save some of the discussion until after posting the "hacker" version of the code for comparison. The types I created for the domain objects (e.g. Suit, Card, Hand) helps make the code readable as well as reusable. The structure of the types helps document the intention; for example, the fact that a Hand contains exactly five cards type Hand = Hand of Card * Card * Card * Card * Card makes clearer some aspects of how the data type will be used (if a Hand instead had held a "Card list", the reader might speculate that it only represents a player's two hole cards, or all seven cards - hole plus community). There is little to these types that's custom-tailored to the problem at hand; I expect I could easily lift these types out of this program and use them advantageously in another poker program as well. The data types are explicit; by that I mean choosing to use enums rather than just ints or chars, and creating single-case unions like type Card = Card of Suit * Rank rather than just using tuples. The advantages of these explicit data formats include static type checks enforced by the compiler to prevent misuse as well as making the code and tooling more self-documenting; I'll demonstrate this in more detail in the next blog entry. The disadvantages of explicit data formats are that more effort goes into "conversion of data structures" which also impacts succinctness; an example is let BestHand c1 c2 c3 c4 c5 c6 c7 = let allSetsOf5Cards = ChooseN [c1; c2; c3; c4; c5; c6; c7] 5 let allHands = allSetsOf5Cards |> List.map (fun [c1;c2;c3;c4;c5] -> Hand(c1,c2,c3,c4,c5)) allHands |> List.max_by Evaluate where I needed to pack 7 individual bits of data into a list to hand them off to a function (ChooseN), and then unpack the list back into separate pieces of data to convert it back to one of my data types (Hand). Once again, I'll discuss this in more detail after showing the "hacker" style solution for comparison. As a matter of course, I did some input checking and validation (though not very much - there's only a handful of exceptions) to try to make the code more robust to exceptional conditions. I did so mostly with the intention of providing helpful diagnostics rather than more opaque ones (like IndexOutOfRange or KeyNotFound exceptions), but as I'll demonstrate next time, this error-checking also provides robustness by helping prevent out-of-spec behavior of the program. Next time...In the next blog entry, I'll show a solution using the "hacker" strategy, and draw more specific comparisons between the two strategies, using code from each solution as concrete examples to illustrate my points. October 11 A programming problem, part two (see the flop!)Last time I introduced a programming problem. In this blog entry I'll talk about two different strategies for solving it, and discuss the first half of the first solution. Two strategies for solving the problemThe two strategies I will demonstrate in this blog series are what I shall call the "hacker" strategy and the "software engineer" strategy. These are my own rough characterizations of two different modes of programming that you are probably already familiar with. The programming problem at hand will provide a venue for demonstrating the differences between these strategies. Here is my brief synopsis of the two strategies.
I'll take these strategies to a little bit of an extreme to highlight the differences, but in fact there is a continuum between these two. (Actually, it's not just a linear continuum; another interesting point in the "strategy space" is one I might label the "functional hacker", which emphasizes succinctness and codes mostly using functional composition in a points-free style. This strategy shares some strengths and some weakness with each of "hacker" and "software engineer". Laurent's solution is in this vicinity.) I'll solve the poker problem both ways, so let's start with... A "software engineer" solution, part oneAfter reading the problem specification, it is clear that I need to model the essential entities for representing poker hands and comparing their relative strengths (what-beats-what). Without paying too much attention to the details of the problem specification, I see the obvious nouns in the domain (card, suit, rank, hand), as well as one less-obvious one (hand valuation, e.g. "two pair, kings and nines, with queen kicker"). So let's start there. I can use enums to represent suits and ranks: type Suit = | Club = 1 | Diamond = 2 | Heart = 3 | Spade = 4 type Rank = | Two = 2 | Three = 3 | Four = 4 | Five = 5 | Six = 6 | Seven = 7 | Eight = 8 | Nine = 9 | Ten = 10 | Jack = 11 | Queen = 12 | King = 13 | Ace = 14 (In F#, the syntax for enumerated types looks a lot like the syntax for discriminated unions; the "=<intValue>" is the key difference.) Note that I chose to value an ace as 14 rather than 1, since most poker hands treat aces as high cards. A card is just a combination of a suit and a rank: type Card = Card of Suit * Rank And a hand is just a set of five cards: type Hand = Hand of Card * Card * Card * Card * Card There are a number of ways we could choose to represent hand valuations, but in F#, this is one of the best choices: type HandValuation = | Nothing of Rank * Rank * Rank * Rank * Rank // descending order | Pair of Rank * Rank * Rank * Rank // pair, then kickers in descending order | TwoPair of Rank * Rank * Rank // high pair, low pair, kicker | ThreeOfAKind of Rank * Rank * Rank // trips, kickers in descending order | Straight of Rank // high card | Flush of Rank * Rank * Rank * Rank * Rank // descending order | FullHouse of Rank * Rank // three then two | FourOfAKind of Rank * Rank // quad, kicker | StraightFlush of Rank // high card Like some other functional languages, F# automatically implements a comparison function for algebraic data types (e.g. lists, tuples, discriminated unions) using a lexicographical ordering. In other words, you get operators like "<" and "=" for free, with the right semantics. Witness these example: assert (TwoPair(Rank.King, Rank.Nine, Rank.Queen) < ThreeOfAKind(Rank.Two, Rank.Four, Rank.Three)) assert (TwoPair(Rank.King, Rank.Nine, Rank.Queen) < TwoPair(Rank.Ace, Rank.Three, Rank.Eight)) assert (TwoPair(Rank.King, Rank.Nine, Rank.Queen) < TwoPair(Rank.King, Rank.Nine, Rank.Ace)) In the first line, TwoPair is less than ThreeOfAKind (TwoPair was listed first in the type declaration), so the '<' operator can stop evaluating right there. In the second line, both HandValuations have the same union case (TwoPair), so we start comparing the carried data one piece at a time; King is less than Ace, so we're done. In the last line, the cases are the same (TwoPair), and the first two piece of data are the same (King and Nine), so the final datum (Queen versus Ace) is the tiebreaker. In other words, it's completely analogous to "dictionary order" for strings, where the union case is the first "letter" of the string and the carried data are the subsequent "letters" in the string. Thus my HandValuation type is a nice choice because it clearly represents the information both for classifying an individual hand as well as for comparing two hands (what beats what). With these data types under my belt, I am ready to write the first piece of "real" code for the problem; the hand evaluation logic. I need a function that takes a Hand as input and computes its HandValuation as a result. There are a variety of ways to implement this logic; I chose one that is rather plodding, but is straightforward to read and understand. let Evaluate (Hand(Card(s1,r1), Card(s2,r2), Card(s3,r3), Card(s4,r4), Card(s5,r5))) = // redo ranks in ascending sorted order, so r1 is lowest and r5 is highest let [r1; r2; r3; r4; r5] as sorted = [r1; r2; r3; r4; r5] |> List.sort compare // handy helper function let rec AllSame l = match l with | [] | [_] -> true | h::(i::_ as t) -> h = i && AllSame t // decide up front if hand contains a flush and/or a straight let isFlush = AllSame [s1; s2; s3; s4; s5] let theWheel = [Rank.Two; Rank.Three; Rank.Four; Rank.Five; Rank.Ace] let isStraight = sorted = theWheel // since Ace is valued 14, this is a special case || (sorted |> List.map (fun x -> (int x) - (int sorted.Head))) = [0;1;2;3;4] // all the tedious logic for classifying the hand if isStraight && isFlush then StraightFlush r5 elif AllSame [r1;r2;r3;r4] then FourOfAKind(r1,r5) elif AllSame [r2;r3;r4;r5] then FourOfAKind(r2,r1) elif AllSame [r1;r2;r3] && AllSame[r4;r5] then FullHouse(r1,r4) elif AllSame [r1;r2] && AllSame[r3;r4;r5] then FullHouse(r3,r1) elif isFlush then Flush(r5,r4,r3,r2,r1) elif isStraight then Straight r5 elif AllSame[r1;r2;r3] then ThreeOfAKind(r1,r5,r4) elif AllSame[r2;r3;r4] then ThreeOfAKind(r2,r5,r1) elif AllSame[r3;r4;r5] then ThreeOfAKind(r3,r2,r1) elif r1=r2 && r3=r4 then TwoPair(r3,r1,r5) elif r1=r2 && r4=r5 then TwoPair(r4,r1,r3) elif r2=r3 && r4=r5 then TwoPair(r4,r2,r1) elif r1=r2 then Pair(r1,r5,r4,r3) elif r2=r3 then Pair(r2,r5,r4,r1) elif r3=r4 then Pair(r3,r5,r2,r1) elif r4=r5 then Pair(r4,r3,r2,r1) else Nothing(r5,r4,r3,r2,r1) Blah. No matter how you choose to implement the logic, there are a lot of cases and it feels error-prone. Being a good developer, I wrote some unit tests. I chose to specify a whole lot of tests mostly declaratively. First, for convenience, I named all 52 cards in the deck: let CA = Card(Suit.Club,Rank.Ace) let CK = Card(Suit.Club,Rank.King) let CQ = Card(Suit.Club,Rank.Queen) ... Then I made a big list of hands, starting with the best and evidencing each step of "slightly worse" along the way: // list of hands in intended order (best to worst) // each element is itself another list of hands that 'tie' with each other // these will serve as good test cases of ranking logic let handsInOrder = [ // straight flush [Hand(SA,SK,SQ,SJ,ST); Hand(HA,HK,HQ,HJ,HT)] [Hand(S9,S8,S7,S6,S5)] // worse high // four of a kind [Hand(SA,HA,DA,CA,SQ); Hand(SA,HA,DA,CA,CQ)] [Hand(SA,HA,DA,CA,S4)] // worse kicker [Hand(SK,HK,DK,CK,SA)] // worse quads // full house [Hand(SA,HA,DA,S3,H3); Hand(SA,DA,CA,H3,C3)] [Hand(SA,HA,CA,D2,H2)] // worse low [Hand(SK,HK,CK,DQ,HQ)] // worse high // flush [Hand(SA,S9,S8,S4,S3); Hand(DA,D9,D8,D4,D3)] [Hand(SA,S9,S8,S4,S2)] // worse 5th [Hand(SA,S9,S8,S3,S2)] // worse 4th [Hand(SA,S9,S6,S5,S2)] // worse 3rd [Hand(SA,S8,S7,S6,S5)] // worse 2nd [Hand(SK,SQ,SJ,ST,S8)] // worse 1st // straight [Hand(SA,SK,SQ,SJ,HT); Hand(DA,DK,DQ,DJ,ST)] [Hand(DK,HQ,SJ,CT,S9)] // worse high-card // three of a kind [Hand(SA,HA,DA,DK,SQ); Hand(CA,DA,HA,SK,SQ)] [Hand(SA,HA,DA,DK,ST)] // worse 2nd kicker [Hand(SA,HA,DA,DQ,DJ)] // worse kicker [Hand(S3,H3,D3,SA,DK)] // worse trips // two-pair [Hand(SA,HA,S3,D3,S9); Hand(CA,HA,C3,S3,H9)] [Hand(SA,HA,S3,D3,S7)] // worse kicker [Hand(SK,HK,SQ,HQ,S9)] // worse high-pair [Hand(SK,HK,SJ,HJ,SA)] // worse low-pair // pair [Hand(SA,CA,SK,SQ,SJ); Hand(HA,CA,HK,CQ,DJ)] [Hand(SA,CA,SK,SQ,S2)] // worse 3rd kicker [Hand(SA,CA,SK,SJ,S5)] // worse 2nd kicker [Hand(SA,CA,SQ,SJ,ST)] // worse 1st kicker [Hand(SK,HK,SA,HJ,C6)] // worse pair // nothing [Hand(HA,S9,S8,S4,S3); Hand(CA,D9,D8,D4,D3)] [Hand(HA,S9,S8,S4,S2)] // worse 5th [Hand(HA,S9,S8,S3,S2)] // worse 4th [Hand(HA,S9,S6,S5,S2)] // worse 3rd [Hand(HA,S8,S7,S6,S5)] // worse 2nd [Hand(HK,SQ,SJ,ST,S8)] // worse 1st ] With this data structure, it's easy to write code that walks the structure and ensures that
To implement the last bullet, I want to be able to generate all possible permutations of a hand. So I'll start with a function that generates every permutation of an array. There are lots of ways to write such a function; here is one way that does it with the fewest number of array element swaps: let AllPermutations s = let a = Array.of_seq s let Swap i j = let tmp = a.[i] a.[i] <- a.[j] a.[j] <- tmp let p = Array.init (a.Length + 1) (fun x -> x) seq { yield Array.copy a let i = ref 1 while !i < a.Length do p.[!i] <- p.[!i] - 1 let j = if !i % 2 = 1 then p.[!i] else 0 Swap !i j yield Array.copy a i := 1 while p.[!i] = 0 do p.[!i] <- !i i := !i + 1 } Now it's trivial to take a given hand of 5 cards and generate an array of all the hands containing those 5 cards in any order: let AllHands (Hand(c1,c2,c3,c4,c5)) = let a = [| c1; c2; c3; c4; c5 |] [| for [| c1; c2; c3; c4; c5 |] in AllPermutations a -> Hand(c1,c2,c3,c4,c5) |] And now I can test all the bits I want to ensure: let rec Test handsInOrder = match handsInOrder with | [] -> () | h::t -> let firstValuation = Evaluate (List.hd h) for hand in h do for perm in AllHands hand do assert( (Evaluate perm) = firstValuation ) for lesserHand in List.concat t do assert( firstValuation > (Evaluate lesserHand) ) Test t Test handsInOrder Each recursive call to "Test" tests one row - we ensure that all permutations of all hands on this row tie, and that the valuation of the hands on this row beat all of the lesser hands further down the list. With these tests, I did in fact find a typo in my original version of "Evaluate"; thanks to the tests, I am confident that "Evaluate" works properly. Next time...That's enough for this blog entry. Next time I'll finish off the "software engineer" strategy by adding logic to choose the best hand of 5 cards from 7 cards, parsing the input, and writing the output. After that, I'll show the "hacker" strategy, and draw comparisons between the two. October 05 A programming problem, part one (place your bets!)I was trying to come up with a programming problem to motivate some blog entries, and I found one that I really like. Ruby Quiz #24 requires you to write a short console application that reads in information about Texas Hold 'Em poker hands, evaluates the results, and prints out the results. Follow the link and go check the problem out. I like this problem because
So in the next few blog entries, I will walk through solving this problem. And here's the kicker (pun!) - I intend to show you two different ways to do it. Why? And what differentiates the two ways? You'll find out in due time. In the meantime, try your own hand (not so much a pun) at the problem, using any language or implementation strategy you like. That way you'll have something of your own to compare against the solutions I present. Get crackin'! September 22 How does functional programming affect the structure of your code?I recently listened to Ted and Amanda talking about F# on ".Net Rocks". Ted mentioned something about how with functional programming, some object-oriented (OO) design patterns (like 'Command') just disappear because you don't need them when you have first-class functions. That's a topic near and dear to my heart; back in school I co-authored a paper about this (see "FC++: Functional Tools for OO Tasks" on the FC++ page). It got me thinking about how "code comes out different" in F# versus C#, which in turn got me thinking about a conversation I had with Luke a couple months ago, where Luke argued convincingly that functional programming (FP) differentiates itself most obviously when programming "in the small". So I was thinking about all this stuff and it inspired me to write this blog entry where I try to get down all my thoughts on this. Defining some termsI want to discuss how functional programming techniques affect the structure of your code at three different levels, which today I will call "in the large", "in the medium", and "in the small". By "in the large" I mean a high level that affects and crosscuts multiple classes and functions throughout a program. By "in the medium" I mean the level of a single API or group of related APIs (e.g. a class, an interface, or a couple tightly-coupled classes or functions). By "in the small" I mean the level of individual method/function bodies - the actual code that "does stuff" as opposed to the structural/scaffolding/modularizing organization of that code. Functional programming in general (and F# in particular) affect the structure of code at all of these levels to various degrees, so I'll talk about each level in turn. A note...Though I will cite a number of examples, I'm not showing any code in this blog entry. A catalog of "this is some code in C#, here's the somehow-corresponding code in F#" could be interesting/useful, but is not my purpose today. I just want to talk about how code differs, and try to categorize and describe the essential differences I see, without getting too distracted by the details of any specific examples. So I'll try to use examples "just enough" to get you thinking along the lines I'm thinking; you will need to follow hyperlinks in order to learn more about some examples I mention that you may not be familiar with. In the largeI think that functional programming has the least influence on the structure of programs in the large, simply because when doing architecture or high-level design, you're "too high up" for specific implementation techniques to matter too much. At this level, the strongest influence is the problem-domain itself; a good architecture decomposes a system into a set of modules and interactions that solve the problem under its key constraints (which may include performance/throughput of the system, distribution, reliability, etc.). This is true regardless of whether you're wearing an FP hat or an OO hat; these styles can help shape your thinking about the problem, but don't necessarily affect the final structure of the solution. This is not to say that this level is completely free of FP influence. Though a now a quarter-century old, the oft-cited Why Functional Programming Matters has a great example here: section 5 talks about how laziness is essential to the architecture of a particular performant program and crosscuts whole API. The idea of using on-demand computations to decouple producers of data from their consumers is definitely useful, but it can be realized in myriad ways (coroutines, pipes, streams, IEnumerable<T>, ...), so I'm not sure that FP can stake a complete claim here. But adding FP strategies to your mental bag of tricks can help diversify how you think about problems at a high level. It bears mention that F# is a great tool for realizing a wide range of system architectures: whether your problem lends itself to service-orientation with stateless servers passing messages, or to high-performance computing that must take advantage of multiple cores, or to traditional OO modeling, decomposition, and encapsulation suitable to many desktop applications, the features in F# make for a natural implementation fit. By blending FP and OO, F# has the long reach to straightforwardly implement a wide range of designs, and its deep integration with .Net provides a very rich platform of libraries to build atop. In the mediumRecall that by "in the medium", I mean program structure at the level of classes, interfaces, and individual method APIs. The good news here is that for a great many cases, OO design is just right. OO has dominated for the past couple of decades, and with good reason: decomposing a domain into classes (nouns) and methods (verbs and predicates) associated with those classes is an outstanding way to decompose a problem domain and structure a solution in source code. However there are some cases where the OO strategy of "classes/nouns first" creates inferior solutions. The Command design pattern is a good example of such a case. The purely object-oriented solution realizes this pattern with a Command class or interface with a single method called "Execute". This is clearly just a function dressed up in "class" clothes. Whereas an OO solution requires lots of interacting named entities (a Command class or interface, an Execute method, concrete subtypes that fill in the method implementation and potentially capture extra state), a solution in a language with first-class functions requires none of these. A function type (e.g. "int->unit") is a sufficient description of the interface, and any named function or lambda with the right signature can be used as a concrete implementation. Closures make it trivial to capture any extra state that is needed. In short, all of the "structure" described by this pattern is unnecessary; first-class functions are a direct fit for the domains that "Command" tries to solve, and classes and interfaces are unnecessary. Similar observations can be made for a number of other design patterns, including Observer and Strategy. There are other places where functional programming affects the structure of your code "in the medium". The Visitor pattern is another design pattern that can be handled differently using functional techniques; I discussed folds and catamorphisms at length in a prior blog entry. The availability of F# discriminated union (DU) types create opportunities to structure certain kinds of code more simply; a fixed class hierarchy can often be represented with a single DU type; I showed an example of this in a prior blog entry on DUs. In C# (especially before C# 3.0), there were a number of situations where you would create named delegate types and/or classes (like FooEventArgs) to handle "events" or other customizations to the behavior of classes in a library. Again, these are best handled with function types (and the lambdas and "Func" delegates in C# 3.0 are progress towards reducing the extra needless friction that comes from some such APIs). Finally, sometimes in OO languages you are forced to package functions inside classes, when in fact the functions are happy to float free at the top level. Consider mathematical functions like "sqrt" or "pow" - whereas an OO languages typically forces you to stick these in a class and always qualify calls (e.g. "Math.Pow()"), in a language like F#, you can define functions like these in a open-able module or just at the top-level of your program, and access these by their short names (e.g. just "pow") or by defining operators (like "**"). In the smallBy "in the small", I mean code at the level of individual method and function bodies. It's here where functional programming in general, and using F# in particular, change the structure of your code most obviously. When "variables" are immutable by default, and you usually don't need type annotations, and control is often expressed via expressions (if-then-else, pattern matching) and recursion, and you can define local/nested functions as easily as defining local variables... your code ends up looking pretty different at this level compared to typical code you'd see in other languages. The ability to author higher-order functions (like maps and folds) along with the ease of writing lambdas often means that code which you might typically write with a loop or recursion can be written with just a single call to a higher-order function; see this Joel on Software article for details on how and why this is so important and useful. Examples here abound; just the other day I saw this blog post (check it out), which is a good example of the difference in styles "in the small". Sure, you can write the "List.min_by" function in C# and call it with a lambda, or use a LINQ query, but either of those C# solutions just highlights the FP style of programming. The point is that FP features like higher-order functions and currying are the enablers of this style of programming, and they can dramatically change and simplify the code you write in the small, down at the level of individual functions/methods or portions of method/algorithm implementations. Furthermore, the "in the small" level is arguably the most important level of code, since it's the only level that has to be there. There are plenty of times when you're doing exploratory programming, or scripting, or writing glue code, when you simply won't need to utilize any features for structuring/organizing programs "in the medium/large". Here, F# features, such as the ability to program directly at the top-level, type inference, and higher-order functions are huge wins that enable you to create shorter, simpler code. And most of these advantages still apply in larger programs, inside the bodies of individual functions and methods. The advantages of FP "in the small" accrue to programs of all sizes. Summing upI think that functional programming affects the structure on a number of levels. FP's influence is weakest "in the large"; at this level, the structure of the problem itself dominates, and FP's influence comes mostly shaping one's thinking about architectures or high-level designs. FP's influence is more apparent "in the medium", where the design of some APIs can be simplified - sometimes dramatically in a few specific domains that are especially well-suited to FP. FP differentiates itself the most "in the small" - this is the level where computations happen, this is level where the majority of code (for programs of all sizes) is written, this is where most FP-specific constructs take hold. CodaI think it's difficult to write convincing prose about programming without showing any code, but in this entry I linked to a number of examples that illustrated my points and matched my personal experience, in the hopes of causing you to recall similar examples from your own experiences programming in FP versus OO style. I expect that there are many other good examples out on the web that illustrate "how the code codes out differently" when you have your FP hat on... for those of you who don't yet have much of your own FP experience to draw on, I'd encourage you to seek out more examples to see more of the concrete differences (and consider posting links to the best ones in the comments section of this blog entry, to make them easy for other readers to find). September 16 Reusing F# code libraries with Visual StudioContinuing with the theme of a prior blog entry, I want to discuss two practical ways to reuse code across multiple applications. Suppose I have some general-purpose utility code that I find to be reusable in a number of programs that I'm authoring. Rather than cut-and-pasting the code into various programs (which has all kinds of maintenance issues - if you are cut-and-pasting code within your projects, you are probably doing something wrong!), there are two common techniques in Visual Studio for reusing code. Code library projects, and solutions with multiple projectsPerhaps the commonest way to reuse code is to put it in a library. An F# library project (File>New Project): is a project that compiles down to a DLL (as you can see in the Output Window below): So now I have a library that I can reference to access this functionality. I can reference this functionality from a different program by creating a solution with multiple projects. First, I create a new project for my app: Next, I add an existing project to the solution: and select the library project that I just created. Now my solution contains two projects: Note that the project is "by reference" - Visual Studio hasn't copied anything, the source code and the project file still have their same old location on disk, we are just referencing them from a different solution. To make the library accessible to my application, I add a project reference by doing an 'Add Reference' on the app: and selecting the 'Projects' tab to add a reference to the Library1 project: I see the new reference appear in the solution explorer: And now I can write code in my app that references code from the library, has working Intellisense, etc: That's a project-to-project reference, and it's a common way to reuse code - I can reference Library1 from whatever other applications I write, in whatever language (e.g. I could just as well have referenced the F# library project from a new C# console application project) using this technique. Including individual source code files by reference using 'Add as Link'Another way to reuse source code is to recompile the same code into different applications. I covered the mechanics of how to achieve this ('Add as Link') in a prior blog entry, check it out. I can create a new F# Application project in a new solution, and 'Add as Link' a source code file from the Library1 project, resulting in: The little 'arrow' sub-glyph on the 'Module1.fs' icon shows that this is a linked file. As a linked file, no copying has been done - the source file still just lives in a single place on disk (under the Library1 folder), but that source file is going to get compiled into this project. As a result, again I can reference that code from other code in the current application: This 'code reuse' strategy is probably used less often than project-to-project references. It has a number of disadvantages (functionality often cannot simply be 'lifted out' of a project on a per-file basis - often the code in the file references other files in the project, or has dependencies on references ('add reference') from the original project), but does have some potential advantages as well (the code is re-compiled directly into the referencing project, so with this strategy I just have a .EXE that contains everything, rather than a .EXE and a .DLL that the .EXE references). So I've demonstrated a couple ways to reuse code in Visual Studio without resorting to cut-and-paste. Nothing too earth-shattering here, but I often find that people are blissfully ignorant of lots of useful Visual Studio features (I count myself in this group - until I started working on the F# Visual Studio integration, there were tons of VS features I knew nothing about, despite using VS for years), so I hope this helps demo the mechanics of some features and suggests how you will use them in practice. Next timeWhereas recent blog entries have discussed some pragmatics regarding the physical aspects and tooling aspects of structuring your code (e.g. files and folders on disk, as well as VS projects and solutions), next time I hope to discuss how F# and functional programming affect the structure of actual source code that you write, compared to writing code with OO languages. September 06 Quick aside: F# CTP compiler flags (command-line options)One thing that changed in the CTP release of F# is the names of various compiler options. Below is a brief table that shows the old names and new names of many command-line flags.
As with a number of other changes in the CTP, these changes were to make things more regular and consistent with other Visual Studio languages. The compiler help itself also now displays in a format similar to that of the C# and VB compilers (csc.exe and vbc.exe); here's the output of "fsc.exe /?": Microsoft F# Compiler, (c) Microsoft Corporation, All Rights Reserved
- CODE GENERATION -
By the way, you might notice the version number is 1.9.6.2 - yesterday we released a minor update to the CTP with a few high priority fixes. Thanks again to everyone who has given great feedback on the CTP release! |
|
|