F#, the F# Compiler and the F# Visual Extensions, Version 1.0.0.2

Welcome to F#. F# is a language implementation for .NET with a design based on the core of the OCaml programming language with extensions to access .NET libraries. This release contains

Full details can be found at the F# website. There you can find details about how to join the F# email list.

Requirements

Compiler Installation

Installing F# for use with Microsoft Visual Studio 2005

Four ways to write Hello World in F#

Let's write a program in a file main.ml, e.g.

   let _ = print_endline "Hello world"

and the compile and run it:

   > c:\fsharp\bin\fsc main.ml
   > .\main
   Hello world

Now let's write it another way:

   let _ = 
      List.iter (fun s -> print_string s) ["Hello"; " "; "world"];
      print_newline()

That shows you how to use function values (lambdas) and the list library. List processing is very common and powerful in functional programming. Of course we get the expected result when we compile and run the above program.

Here's still another way, which shows you how to define and use new record types:

   type data = 
      { first: string;
        second: string; }

   let myData = 
      { first="Hello";
        second="world"; }
 
   let _ = 
      print_string myData.first;
      print_string " ";
      print_string myData.second;
      print_newline()

And here's another way, which shows you that you can call the .NET standard libraries instead of the min-functional programming library provided with F#:

   let _ = 
      System.Console.WriteLine("Hello world")

To write components, you will normally need to write interface files (.mli). Here's a very simple component:

   test.mli:
      val double: int -> int
      val four: int

   test.ml:            
      let double x = x + x
      let four = double (double 1)    

Using the Compiler

The command line compiler is bin\fsc.exe. The samples give a guide to using the compiler, both alone and in conjunction with other .NET programming tools. Some of the samples require the Microsoft .NET Framework SDK.

Common switches are:

   -a              build a DLL (an archive)
   -g              generate debugging information
   -O2             maximal optimization
   -I              add a path to search for compiled interface files

Files produced include:

   abc.dll         a compiled .NET assembly (use the -a flag)
   abc.exe         a compiled .NET executable
   abc.pdb         Windows debugging information
   abc.ildb        SSCLI debugging information

Using the Library

F# comes with three libraries.

The source code for 'fslib.dll' and 'mllib.dll' are simple and are included as sample code. MLLib gives a standard functional progrmaming library that lets you write code that will cross-compile as both OCaml and F# code. However, you are not committed to using MLLib, as all the primitives required for building your own functional programming library are provided in 'fslib.dll' (use the source code to MLLib as a guide).

All compilations currently implicitly reference both 'mllib' and 'fslib', though the former can be disabled using the --no-mllib command line option. However, you may also use F# as a 'pure' .NET programming language, without relying on constructs defined in 'mllib.dll'. You don't need to use the libraries to use F#, since you can program directly against the .NET libraries.

The interface files that define MLLib can be found in the lib directory. The most important files are:

The library is also suitable for writing code that can be compiled using either F# or OCaml. This is useful when you are writing utility applications or applications suitable for running on multiple target platforms, including platforms where the CLI is not supported. Cross-compilation may require some conditional compilation, for example to build abstractions that account for the differences between F# and OCaml, e.g. the fact that OCaml strings are not Unicode. See the manual for details on how to write conditional-compilation expressions.

Notes

Recent Changes

Changes between v0.6.6 and v0.7

1. Change the compilation model to compile assemblies in one shot 
   like C#.  This gets rid of ALL the .cno, .cni, .cnx and .cnw files, 
   leaving just a DLL.  The compiler will add a custom attribute to store 
   the F# interface and optimization data.  For this version this will be 
   brittle under changes to the F# compiler, but we will revisit that in 
   later versions to arrive at a stable metadata format.


2. Cleanup code in preparation for the long-awaited source release.  In particular

  * The parser had several of uppercase/lowercase distinctions left over from my 
    initial version of a parser for the Caml syntax.  These don't apply to F# 
    which disambiguates more identifiers at a later stage.

  * Some optimizations have been rearranged, so less is done in the backend
    phase of the compiler.  This greatly simplifies the code. 

  * The treatment of the decision trees that arise from pattern matching was
    too complex.  This has been simplified.

3. Add more support for making F# code highly usable from C# and other .NET 
   languages.  I have the long term aim to make sure that simply no one can tell 
   something is written in F# if you don't want them to.  The design for this is 
   somewhat up in the air, but will almost certainly involve attributing the F# 
   code to indicate how it should look from C# and other .NET languages.

4. Cleanup namespaces.

   All F# stuff is now in Microsoft.FSharp.

   All built-in types like list, option, ref, etc. will also be defined there.  
   From C# they will be called List, Option, Ref etc.  
     Microsoft.FSharp.MLLib.Pervasives
     Microsoft.FSharp.MLLib.String
     Microsoft.FSharp.MLLib.List
  etc.  This has obvious advantages, and allows for an F#-specific library in
  the future, and perhaps even other libraries and source syntaxes to provide 
  some level of mix-n-match for other functional programming languages.

5. Generate generic code by default.  Non-generic code for 
   use with versions of the CLR prior to Whidbey will need a 
   command line option, e.g. "-no-generics"

6. Revisit subtyping, especially w.r.t. overloading, upcast, downcast etc.

  Casting and nulltest operations for .NET types are now built-in 
  as primitive syntactic forms in F#.  

     expr == 
      | e :? ty      -- dynamically test if 'e' has type 'ty'.  A compile-time error
                        will occur if local type inference does not
                        infer types such that this is a valid downward type test. 
 
      | e :> ty      -- statically upcast 'e' to type 'ty'.  A compile-time error
                        will occur if local type inference does not
                        infer types such that this is a valid upcast. 
 
      | e :?> ty     -- dynamically downcast 'e' to type 'ty'.  A compile-time error
                        will occur if local type inference does not
                        infer types such that this is a valid downcast. 
 
      | downcast e   -- runtime checked downcast from 'e' to an arbitrary type 
                        inferred from the context.  A compile-time error
                        will occur if local type inference does not
                        infer types such that this is a valid downcast. 
 
      | upcast e     -- statically checked upcast from 'e' to an arbitrary type
                        inferred from the context.  A compile-time error
                        will occur if local type inference does not
                        infer types such that this is a valid upcast. 
  
      | e1 ?? e2     -- dynamically test if 'e1' is null, and if so evaluate e2.
                        A compile-time error will occur if local type inference
                        does not infer types such that e1 is a .NET type.  Equivalent to
                           (match e1 with null -> e2 | freshv -> freshv)
 
      | null         -- generate a null value of an arbitrary type inferred
                        from the surrounding context.  A compile-time error
                        will occur if local type inference does not guarantee that
                        the type of the value is definitely a .NET reference type.

    pat ==           
      | null         -- the pattern corresponds to a null test. A compile-time error
                        will occur if local type inference does not ensure that
                        the value being matched against is a .NET reference type.

      | :? ty        -- the pattern corresponds to a .NET type test.  A compile-time error
                        will occur if local type inference does not
                        infer types such that this is a valid downward type test. 

      | :? ty as id  -- the pattern corresponds to a .NET type test, and if 
                        successful the variable 'id' is bound to the value at the given
                        type.

Examples: 

a. Doing a null test in a pattern match:
                   
       let d = new OpenFileDialog() in 
       match d.OpenFile() with 
       | null -> Printf.printf "Ooops... Could not read the file...\n"
       | stream -> ...
            let r = new StreamReader(stream) in 
            Printf.printf "The first line of the file is: %s!\n" (r.ReadLine());

b. Doing a null test in an expression:
                   
       let myReader = new StreamReader(new FileStream("hello.txt")) in 
       while true do Console.WriteLine(myStream.ReadLine() ?? raise End_of_file); done;


Valid casts are those between .NET types related by class extension or interface
inheritance, and also between F# reference types and the type 'obj' (i.e. System.Object).
Thus F# values can be stored in heterogeneous collections such as 
System.Collections.ArrayList.

Local type inference is underspecified in this version of F#. 
In a future version of F#  this will be adjusted to correspond to the 
process of using only "definite" type information in order to make a 
compile-time assessment, i.e. type information from external libraries and modules, from
user type annotations, from uses of F# discriminated unions and F# record labels,
and from other similar type information that arises directly from F# syntactic
forms.  

In this version of F# local type inference applies applies all type information
available to the left of a term, including the use of type equivalences inferred
via Hindley-Milner style unification.  


(TODO) 7. Allow attributes to be declared.  Syntax proposed is "[]"
   in various places.  This is not yet settled and is certainly up for discussion.

8. Typesafe OCaml-style 'printf' is now supported.  See the Printf library module.

9. Object expressions are now supported.  


  9a.  Basic object expressions.

   An object expression declares an implementation and/or extenstion of a class or interface.
   For example, 
              "{new IComparer with Compare(a,b) = if a < b then -1 else if b < a then 1 else 0 }"

   In each example below the "{new ... with ... }" expression generates a new class 
   underneath the hood that implements/extends the given type.  
   Note how little type information you need: the required signatures for OnPaint, 
   Compare, ToString etc. are inferred by looking at the unique virtual method that 
   we must be overriding.  Note too how the anonymous classes close over free variables 
   (e.g. capture the variable "n") behind the scenes.

     open System
     open System.Collections
     open System.Windows.Forms
     let myComparer = {new IComparer with Compare(a,b) = compare a b}
     let myFormattable = {new IFormattable with ToString(fmt,fmtProvider) = ""}

     let myForm title n =
       let res = 
        {new Form() 
         with OnPaint(paintEventArgs) = Printf.printf "OnPaint: n = %d\n" n
         and  OnResize(eventArgs) = Printf.printf "OnResize: n = %d\n" } in
       res.Text <- title;
       res

   You may only override/implement methods in anonymous classes.  You may not declare fields
   or new methods.  To override/iumplement virtual properties you should override the "get_PropertyName" and
   "set_PropertyName" methods that represent the property under-the-hood.  Likewise to override
   virtual events you should override the "add_EventName", "remove_EventName" and "fire_EventName"
   methods that represent the event under-the-hood.

 
 9b. Accessing "this" in object expressions.

   There is no "this" keyword, and for good reasons: 
     1. In object-oriented languages an object may not be sucessfully constructed 
        at many points where "this" can be used.  These leads to inherent weaknesses
        in the initialization-soundness guarantees of these languages.

     2. The natural typing for "this"/"self" would reveal the anonymous type
        of the implementation.  Object expressions are for defining implementations, 
        not types, and it is not desireable to mix type-generation with object expressions
        unnecessarily.  This is similar to the way the discriminants of discriminated
        unions are not types in F# (though they may be types in the underlying IL).   

     3. Sometimes you want to access not "this"/"self" but another object in a self-referential 
        graph of objects.  There is nothing fundamentally different between doing that
        and accessing "this" or "self".
 

   However, you can access "this" by using the "reactive recursion" feature described elsewhere in these
   notes.  This feature results in a compiler warning that the initialization guaranteed for the object
   expression may not be as strong as you wish, and in particular that (in theory) the constructor
   for the object may invoke a virtual method which uses "this" before the object is initialized.  For
   example

       let rec obj = {new System.Object() 
                      with GetHashCode() = (obj.ToString()).Length}

   Here the identifier "obj" plays the role of "self" or "this".  This example makes it plainer
   why "let rec" must be used: obj is certainly defined in terms of itself, i.e. its definition is
   self-referential or recursive.

   Note that mutually-self-referential objects can be defined via the same mechanism:

       let rec obj1 = {new System.Object() 
                       with GetHashCode() = (obj2.ToString()).Length}

       and     obj2 = {new System.Object() 
                       with GetHashCode() = (obj1.ToString()).Length}

   Thus the primitive is self-referentiality via "reactive recursion" rather than allowing all
   object expressions to access "this".

  9c.  How to access the base class members, e.g. C#'s base.OnPaint()

   An inescapable part of the design of .NET object-oriented libraries is that they
   require extensions of some class types to use the implementations of overriden methods
   as part of the definition of the extension.   This is seen in C#'s "base" identifier.

   F#'s permits object expressions that extend classes to be defined partly in terms 
   of the base functionality of that class.  This is done be labelling that functionality 
   as part of the object expression:

        {new Form() as base
         with ... }

   Here "base" is not a keyword, just as "this" and/or "self" are not keywords.  Any identifier
   can be used for base, and if object expressions are nested then different identifiers
   should be used at different points.

   In the example, the variable "base" has type "Form", and can only be used to perform
   method invocations, e.g. as follows:

     let myForm =
        {new Form() as base
         with OnPaint(args) = base.OnPaint(args);  Printf.printf "OnPaint\n" n
         and  OnResize(args) = base.OnResize(args); Printf.printf "OnResize\n" n } 


 9d. Implementing multiple interfaces

  This is not supported in this release.



10. Allow F# exceptions to be mapped to/from .NET exceptions, especially
    in cases like Out_of_memory and Stack_overflow.

11. Further optimizations:

  - Standard functional language optimizations for expressions known to be 
    strings, constructors and tuples
  - Lift additional closed expressions to the top level
  - Optimize away inner polymorphism when functions are only used at one type

13. Extensive testing for all optimizations (a number of bugs were fixed 
    which meant optimizations weren't always firing.)

14. Fix a bunch of minor bugs
* Too much stuff was being made public.  This was hurting abstraction and interop.
* Precedence bug with infix operators such as "&&&&" and "||"
* Improved various error messages
* Minor stuff with calling methods on structs
* A bug with Flush on StreamWriters reported by Dominic Cooney (thanks Dominic!)
* Some bugs with error reporting reported by Alain Frisch (thanks Alain!)
* A bug meant that we weren't turning tailcalls into loops for recursive public functions
* A bug meant that an obscure internal error such as "undefined type variable: 'a567" was sometimes being reported.  Appears to be the same as a bug reported by Dominic Cooney (thanks Dominic!)
* Robert Pickering reported various bugs, including one involving delegates (thanks Robert!)
* Creation of delegates taking no arguments (e.g. ThreadStart) had a bug 
* Fixed a typechecker bug with indexer properties
* A couple of error messages weren't being printed, resulting in messages such as 'Tc.Fields_from_different_types(_, _, _)'
* Fixed a couple of bugs with parsing floating point numbers
* int_of_float now truncates the floating point number toward zero, rather than
  rounding.  This is in line with the OCaml specification.  While it's not
  clear that this is the desired behaviour, it seems appropriate that the
  items in Pervasives should follow the semantics of OCaml as closely as possible.
* Fixed many bugs associated with F# values accessed using long paths, e.g. 
  Microsoft.FSharp.Some("3") is a valid way to refer to Some("3").
* The number of compiler generated names appearing in the output has been reduced, and the
  internally generated identifiers that are produced have been made simpler, with fewer
  numbers appearing.
* Can now reference multi-module assemblies. 
* Fixed a bug with the shift operators reported by Dominic Cooney (thanks Dominic!)
* Fixed a bug with the ConcurrentLife sample's repainting behaviour reported by Dominic Cooney (thanks Dominic!)


15. Support 64-bit, 16-bit, 8-bit constants, and unsigned versions of the same,
    62y: 8-bit signed byte
    62uy: 8-bit unsigned byte
    62s: 16-bit signed
    62us: 16-bit unsigned
    62l: 32-bit signed
    62ul: 32-bit unsigned
    62L: 64-bit signed
    62UL: 64-bit unsigned 

   The use of 'l' is a little unfortunate for 32-bit integers, since in C/C++-land
   it means "long", i.e. 64-bit.  However the above is consistent with OCaml's
   use of constants, and there is no point being needlessly inconsistent.

    Literals of type 'bytearray' are now supported, with syntax B"abc\n" etc.
    Literals with syntax "abc\n" are unicode strings as previously.

    Literals of type 'byte' are now supported, with syntax B'\n', B'0', B'\t', B'a', B'\212' etc.
    Literals with syntax '\n', '0', '\t', 'a' '\212' etc. are unicode characters as 
    previously.

16. Greatly improve debug support by getting more accurate sequence points.

17. Unicode escape sequences in identifiers and strings, ala C# style, i.e. \uXXXX and \UXXXXXXXX
    Somewhat crude support for authoring files in UTF-8 encoding is also supported.
    Unicode UTF-8 input may be used, where unicode characters are only currently allowed to appear in strings.
    Unicode characters in identifiers will also currently parse, but no true support is offered here: in particular
    error messages will be garbled, and we do not restrict identifier characters to the expected set of
    alpha-numeric equivalent characters.

18. Support for commercially use by permitting deployment of the F# library if it
    is statically linked into an application. 

    The --standalone switch statically links the F# library and all referenced DLLs
    that depend on that library into the assembly (normally a .EXE) being produced.
    A verbatim copy is made of all the types and other definitions in all these
    DLLs and the copy is added to the assembly produced.  Although these types
    may have the same name as the original types in the C# library, they are 
    logically distinct.

19. Operators.  The following operators have always been supported by F#, but are now
    user definable, rather than being tied to arrays and unicode strings.  
       .[]  .()   .[]:=   .():=    

    This can help with porting OCaml code to F#, since the operations .[] and .[]:= 
    can now be redefined to act on bytearrays rather than unicode strings.
    e.g. 
        let (.[]) s n = Bytearray.get s n
        let (.[]<-) s n m = Bytearray.set s n m
        let (.()) s n = Microsoft.FSharp.Compatibility.CompatArray.get s n
        let (.()<-) s n = Microsoft.FSharp.Compatibility.CompatArray.set s n

   The operators ~- and ~-. have always been available in OCaml but not previously in F#.
   These let you redefine the unary "-" and "-." operators respectively, e.g. 
        let (~-) n = Int64.neg n

20. Accessing .NET: Indexer properties.  Indexer properties can now be accessed with the following
    natural syntax:
      let s = "abcdef" in 
      s.Chars(2)  // returns 'c'

    and for properties with C# syntax 'x[n]' use:

      x.Item(n)

    e.g

       open System.Collections;
       let f (x:ArrayList) = x.Item(0)

21. F#'s version of OCaml's "recursion through data types using 'let rec'" 
    to create "infinite" (i.e. self-referential) data structures is now slightly 
    more restricted.  You can't use recursive 'let rec' bindings through immutable fields 
    except in the assembly where the type is  declared.  This means

       let rec x = 1 :: x

    is not supported.  This was required to make sure the head/tail fields of lists are
    marked "private" and "initonly" in the underlying assembly, which is ultimately more
    important than supporting all variations on this rarely-used feature.  However note that

       type node = { x: int; y: node}
       let rec myInfiniteNode = {x=1;y=myInfiniteNode} 

    is still supported since the "let rec" occurs in the same assembly as the type definition,
    and

       type node = node ref
       let rec myInfiniteNode = { contents = myInfiniteNode } 

    is supported since "contents" is a mutable field of the type "ref".


22. Nice-Compiled-Forms: Access of discriminated unions from other .NET languges has been improved.

    F# data types are compiled to C# classes with additional support to access the information carried by
    the data type.

    Constructing values of F# discriminated unions
    ----------------------------------------------

    A static method is supported for each discriminant, e.g.
           List.Cons(3,null)
           Option.Some(3)

    Discriminating on F# discriminated unions
    -----------------------------------------

    The following section applies if the type has more than one discriminant.

    The support depends very marginally on when "null" is used by the F# compiler as 
    a possible representation of value of the data type.  This is because types where "null" is used as
    representation cannot support some instance members (they would result in a null pointer exception
    when used from C#).

    "null" will ONLY be used by the F# compiler in EXACTLY the following situations:
       - For the single value of the "unit" type
       - For discriminated unions with exactly 2 constructors, where exactly one of
         those constructors is nullary - of course 'null' is then used for
         as the representation for the nullary constructor. Thus "null" may be 
         used for the "list" and "option" types, and types very similar to these,
         but will rarely be used for other datatypes.

    If "null" is NOT used as representation then a type will support
       (a) a Tag property and several tag_... compile-time constants.  These can be used for discrimination
           by switching.
       (b) a series of IsXYZ() instance methods, one for each constructor.  These can be used for discrimination
           by predicates.

    If "null" IS used as representation then a type will support
       (a) a GetTag() static method, and several tag_... compile-time constants.  These can be used for switching
    In the latter case discrimination by predicates can be performed by comparing values to "null",
    since the null value is then guaranteed to be used for the single nullary constructor of the type.

    Thus if the C# value x has type MyType and the F# definition of MyType is:
         type MyType = A of ... | B of ... | C of ...

    then the following C# code is valid:

      Console.WriteLine("{0}", x.IsA());
      Console.WriteLine("{0}", x.IsB());
      switch (x.Tag) 
      {
          case MyType.tag_A: 
              Console.WriteLine("A");
              break;
          case MyType.tag_B: 
              Console.WriteLine("B");
              break;
          default:
              Console.WriteLine("Must be a C");
              break;
      }
       

23. Nice-Compiled-Forms: Names for tuple types have changed

   The compiled form of tuple type names and tuple member names has been improved, e.g.
         Tuple<_,_>.Item1
         Tuple<_,_>.Item2

         Tuple<_._,_>.Item1
         Tuple<_._,_>.Item2
         Tuple<_._,_>.Item3

         Tuple<_._,_,_>.Item1
         Tuple<_._,_,_>.Item2
         Tuple<_._,_,_>.Item3
         Tuple<_._,_,_>.Item4

         ... 

         Tuple<_._,_,_,_,_,_>.Item1
         ...
         Tuple<_._,_,_,_,_,_>.Item7

    The compiled forms for tuples of size > 7 are under-specified.  The above names change slightly
    when targetting .NET 1.0 or 1.1, i.e. a non-Whidbey release, because we then can't use the arity
    of the generic type to disambiguate the various "Tuple" names.  So the names become
    Tuple2, Tuple3 etc. to Tuple7.

24. Nice-Compiled-Forms: Data fields compiled as properties, not fields

    Properties are now used to compile all memebers of F# record types, i.e. 
         type recd = { Name: string; Size: int }
    will support
         recd.Name  (a property, not a field)
         recd.Size  (a property, not a field)

25. Nice-Compiled-Forms: Fields of alternatives can have names.

    F# discriminated unions can now have named fields, e.g.

         type 'a list = 
             Nil
           | Cons of { Head: 'a; Tail: 'a list } 

     Currently this information is ONLY present for describing the .NET view of such a type.
     The use of such a name leads to the creation of a .NET property with the given name.

     Thus there are strict limitations:
       - The names may not currently be repeated amongst different alternatives.
       - These fields may not be selected from F# code
       - Pattern matching against this form is not yet supported.  
       - That is, for all other purposes the declaration is treated as 
         if the fields were declared sequentially as normal, i.e.

           | Cons of 'a * 'a list

      These restictions may be lifted in a future release.
      The inbuilt list and option types are treated as if they have this form, i.e.

         type 'a list = 
             Nil
           | Cons of { Head: 'a; Tail: 'a list } 

         type 'a option = 
             None
           | Some of { Item: 'a }

     and thus C# code can use

      List x = List.Cons(3,(List.Nil));

      Console.WriteLine("x.Head = {0}", x.Head);
      Console.WriteLine("x.Tail = {0}", x.Tail);
      Console.WriteLine("x.Tail - IsNil = {0}", x.Tail);


26.  (This section only applies when targeting a CLR that supports generics, i.e. when the 
      --no-generics switch is NOT used. )
 
     The compiled form of function types has been finalized to be Microsoft.FSharp.FastFunc.  This
     will not change, though the details of the implementation of the 
     Microsoft.FSharp.FastFunc class may be revised.  FastFunc is not a 
     delegate type (which may be what some users expect).  This option has been finally rejected
     for both interoperability and performance grounds.  

     Creating function values that accept one argument
     -------------------------------------------------

     It it important to be able to create and use values of this type from C# in a
     fashion that is as easy and natural as possible. 

     One option is to create function values by using subclasses of 
     Microsoft.FSharp.FastFunc that override the "Invoke" method.  However this
     is not the recommended way of creating such values, since it is then not so easy to 
     use C#'s anonymous delegate feature when creating delegates.  

     The most uniform way to create a FastFunc is to use an anonymous delegate.  You simply 
     create an appropriate .NET function-like delegate (e.g. System.Converter) and then 
     call Microsoft.FSharp.FuncConvert.ToFastFunc.  In particular, 
     FuncConvert.ToFastFunc(...) supports the following overloads:

           ...(System.Converter f)  producing  FastFunc 
           ...(System.Action f)       producing  FastFunc 
           ...(System.Predicate f)    producing  FastFunc 

     Additionally, there is an implicit conversion from System.Converter to FastFunc,
     and thus you can omit the call to FuncConvert.ToFastFunc() but ONLY when reating a delegate
     of type System.Converter (for some A,B).

     For example, the following are equivalent:
         List.map(FuncConvert.ToFastFunc((Converter) delegate(int x) 
                                                         { return x.ToString() + x.ToString(); }),
                              myList);

     and 
         List.map((Converter) delegate(int x) 
                                   { return x.ToString() + x.ToString(); },
                              myList);

     Creating curried function values that accept multiple arguments
     ---------------------------------------------------------------

     The above techniques works well when creating F# function values that expect one argument.  
     However the above can be awkward when creating F# function values that accept multiple
     values, whether by "currying" or by "tupling".  Thus the F# library defines
     additional similar types in order to support additional conversions.  In particular it defines

         delegate void System.Action(A1 x, A2 y);
         delegate void System.Action(A1 x, A2 y,A3 z);
         delegate B System.Converter(A1 x, A2 y,A3 z);

     and Microsoft.FSharp.FuncConvert.ToFastFunc(...) method supports
     the following overloads that produce "curried" functions:

       ToFastFunc(System.Converter f)       producing  'A1 -> B',             i.e. FastFunc 
       ToFastFunc(System.Converter f)    producing  'A1 -> A2 -> B',       i.e. FastFunc> 
       ToFastFunc(System.Converter f) producing  'A1 -> A2 -> A3 -> B', i.e. FastFunc> >

       ToFastFunc(System.Action f)            producing  'A1 -> unit',             i.e. FastFunc
       ToFastFunc(System.Action f)         producing  'A1 -> A2 -> unit',       i.e. FastFunc>
       ToFastFunc(System.Action f)      producing  'A1 -> A2 -> A3 -> unit', i.e. FastFunc>>

     For example:

      using System;
      using Microsoft.FSharp;
      using Microsoft.FSharp.MLLib;

      List myList = List.of_array(new int[] { 4, 5, 6 });

      string joined = 
        List.fold_right
          (FuncConvert.ToFastFunc((Converter) delegate(int i,string acc) 
                                    { return i.ToString() + "-" + acc; }),
           myList, 
           "");



     Creating function values that accept multiple arguments as tuples
     -----------------------------------------------------------------

     To create F# function values that accept their arguments as tuples use
     Microsoft.FSharp.FuncConvert.ToTupledFunc.

       ToTupledFastFunc(System.Converter f)       producing  'A1 -> B',           i.e. FastFunc 
       ToTupledFastFunc(System.Converter f)    producing  'A1 * A2 -> B',      i.e. FastFunc> 
       ToTupledFastFunc(System.Converter f) producing  'A1 * A2 * A3 -> B', i.e. FastFunc> >

       ToTupledFastFunc(System.Action f)            producing  'A1 -> unit',           i.e. FastFunc
       ToTupledFastFunc(System.Action f)         producing  'A1 * A2 -> unit',      i.e. FastFunc>
       ToTupledFastFunc(System.Action f)      producing  'A1 * A2 * A3 -> unit', i.e. FastFunc>>


27. Added List.of_array and List.to_array.

28.  Initialization semantics for toplevel bindings have been changed to be
     more suitable for a multi-language, dynamic loading setting.
        -  .EXEs:  The only top-level bindings that are immediately evaluated on startup are those
           in the last module specified on the command line when building a .EXE.  

        -  .DLLs: All bindings in a DLL are executed on demand, at most once each time a module is loaded into
           a .NET application domain.  The execution may be triggered by the access of any of 
           the fields or methods of a module.  The granularity is guaranteed to imply that all the 
           top level bindings in a single F# source file are evaluated sequentially if 
           any are evaluated.  

29.  The compiled type name for the type of hashtables is now 
         Microsoft.FSharp.MLLib.Hashtbl.Hashtbl
     rather than 
         Microsoft.FSharp.MLLib.Hashtbl.t
     This looks better in the debugger and from other .NET langauges.
     The latter (or equivalently Hashtbl.t) is still valid from F# code, and 
     is a F# synonym for the former.  In the future the compiled name of the type may
     be changed to be simply Microsoft.FSharp.MLLib.Hashtbl.
   
     The same applies to Lazy.t

30.  The Buffer module has been implemented in MLLib and is a trivial wrapper for Caml's Buffer.t 
     type to .NET'd StringBuilder type.


31. Type operations

     The expression "e :? ty" is equivalent to a dynamic type test.  A warning
     will be emitted if the type of e cannot be statically determined to be
     a subtype of ty (statically determined == using the inference
     information available at this point in the typechecking of the program, where
     inference proceeds left-to-right through the program).  An error will
     be reported if the type test will always succeed.

     This is especially useful for testing for classes of .NET exceptions, e.g. 

      try  
          ... 
      with
       | e when (e :? System.Net.Sockets.SocketException) -> ...
       | e when (e :? System.OutOfMemory) -> ...

     The expression "e as ty" is equivalent to an upcast.  An error
     is given if the compiler cannot statically

32.  Subsumption can now be used at method call sites where this disambiguates 
     a method overload.

That is, upcasts will now be allowed for arguments when calling .NET methods.  The rule for resolving overloading will be:
o	we only consider overrides that match by name and arity (since we always know the number of arguments being applied)
o	if there is only one such method then each actual/formal argument must either match by an upcast or by unification
o	if there are multiple such methods then:
-	if the argument types of only one such method match by type equivalence then that one is used
-	otherwise if the argument types of only one such method match by type equivalence and/or upcasts then that one is used
-	otherwise report an error

Here upcasts and type equivalence are performed in the sense of "local type inference" as described below.  Thus the overload resolution is less aggressive than C# (no automatic boxing/implicit-conversions, less aggressive resolution of ambiguity between methods based on "best overload") but you can always specify the overload you want.


33. Runtime-checked reactive 'let rec' recursion is now supported.

   This means you can write values (and not just functions) whose
   specifications appear to refer to themselves, but where the
   self-references are hidden inside delayed values such as inner functions,
   other recursive functions, anonymous 'fun' lambdas, lazy computations,
   and the 'methods' of object-implementation expressions.  A much
   broader class of expressions can now be used in 'let rec' bindings,
   and in particular the expressions can be applications, method calls,
   constructor invocations and other computations.

   The recursion is 'runtime checked' because there is a possibility that
   the computations involved in evaluating the bindings may actually take
   the delayed computations and execute them.  The F# compiler gives
   a warning for 'let rec' bindings that may be ill-founded (i.e. bindings which
   it can't convince itself are well-founded), and inserts
   delays and thunks so that if runtime self-reference does occur then
   an exception will be raised.  In the future the exception raised will
   be augmented to carry useful information such as line numbers and
   the dependencies in the bindings.
   
   The recursion is 'reactive' because it only really makes because
   it really only makes sense to use this when defining automaton such
   as forms, controls and services that respond to various inputs
   and make self-referential modifications as a result, e.g. GUI
   elements that store and retrieve the state of the GUI elements
   as part of their specification.  A simple example is the following
   menu item, which prints out part of its state as part of its action:

let rec menuItem : MenuItem = 
  new MenuItem("&Say Hello", 
               new EventHandler(fun sender e ->
                    Printf.printf "Hello! Text = %s\n" menuItem.Text), 
               Shortcut.CtrlH)

A compiler warning is given when compiling this code because
in theory the "new MenuItem" constructor could evalute the callback
as part of the construction process, in which case a self-reference
would have occured - and F# can't prove this won't happen.  It is an
current research topic in the language design community to
design type systems to catch these cases, but in the context of
.NET a relatively non-restrictive construct is needed since stateful
components are unavoidable, and it would be difficult (if not impossible)
to design libraries such as WinForms in such a way that a type system
would prove the well-foundedness of the self-referential accesses.



34. Additional syntax forms supported:
      expr :=  ...
            |  try  finally  -- always execute an exit block, even if an exception occurs

      topdecl := ...
            | module    -- specify the namespace/class for the generated bindings
            | do                   -- execute the given expression

      bindings := ...
            | do                   -- execute a statement as part of a recursive binding

35. New keywords

  For .ML, .MLI, .FS and .FSI files:  finally, upcast, downcast, null, :>, :?>, :?

  Reserved for .FS and .FSI files:
      base   constraint   default   namespace   return   switch   
      enum   extern  fixed   functor   include   inherit   module
      object   virtual  sig   using   interface   class  volatile
      process   method   


36.  Namespaces and module names can be specified with an initial
     declaration at the head of a file, e.g.

         module Microsoft.FSharp.MLLib.Pervasives
         module MyLibrary.MyModule

     The final identifier is treated as the module name, the former
     identifiers as the namespace.

     By default there is no namespace and the existing OCaml rule is used
     for the module name (i.e. the first letter of the filename is
     capitalized).  A default namespace can be specified via the --namespace
     command line option.  If any module ddeclaration is given it overrides
     both the default namespace and the OCaml rule for naming modules.

37. 'try-finally' blocks are supported

38. The Game of Life sample has been thoroughly revised
    to be a Multi-threaded GUI application showing how
    to control the progress of underlying computations as
    they execute.

39.  C#/C++-style "//" comments-to-end-of-line are now supported.
     "(*" and "*)" have no special meaning inside this comment text.

     This is technically an incompatibility with OCaml code, however it
     is usually trivial to simply change the name of the "//" operator
     to something else.


40.  An extra compiler switch --minimal-cli-version is supported by
     which you can specify the minimal .NET CLI required to run
     the generated binary.  For example, even if you are developing
     using v2.0 (Whidbey) you can generate a bnary for use on V1.1
     by using a combination of "--minimal-cli-version 1.1.4322" and
     "--no-generics", likewise "--minimal-cli-version 1.0.3705".

     The generated binary may, of course, still require library
     features from later versions.  You should certainly run peverify
     from the appropriate version of the .NET SDK on the binaries to
     ensure they are correct.

     As an alterntaive to all of this you may also alternatively
     be able use a configuration file for fsc.exe to ensure
     the correct runtime is used when compiling - see examples such
     as ilasm.exe.config in your
     C:\WINDOWS\Microsoft.NET directory.

41.  F# now supports C#-style #if/#endif conditional compilation.  The
     command line switch is --define.  The conditional compilation syntax to 
     support mixed OCaml/F# programming has also changed a little (the old syntax
     was universally regarded as gross and was non-uniform).  The syntax how is simply
     that text surrounded by 
         (*IF-FSHARP  ... ENDIF-FSHARP*)
     and (*F#         ... F#*)

     are included when compiling with the F# compiler, and  text surrounded by

         (*IF-CAML*)  ...  (*ENDIF-CAML*)
         (*IF-OCAML*)  ... (*ENDIF-OCAML*)

    is excluded when compiling with the F# compiler.  Of course the converse holds when 
    compiling programs using the OCaml compiler.
    


42.  F# now supports generation of retargetable .NET binaries.  Retargetable binaries
     are neutral w.r.t. the publisher of particular referenced binaries.  For example, 
     a truly portable .NET program will be neutral w.r.t. the publisher of mscorlib - 
     rather than picking up a dependency against the publisher of mscorlib used at 
     compile-time. This means the program will bind to ANY assembly called "mscorlib",
     which is OK for mscorlib but is not necessarily such a good idea for other strong
     named assemblies.  

     You can tell if you have generated retargetable references by using the ILDASM
     tool that comes with the CLR.  If you have you will see:

.assembly extern retargetable mscorlib
{
  .publickeytoken = (96 9D B8 05 3D 33 22 AC )                         // ....=3".
  .ver 2:0:3600:0
}
.assembly extern retargetable System
{
  .publickeytoken = (96 9D B8 05 3D 33 22 AC )                         // ....=3".
  .ver 2:0:3600:0
}

     and so on.  Public key tokens are used to help name a referenced assemblies.
     The particular public key token used above is the unique "neutral" key token as
     specified by the .NET ECMA spec.

     I have been told that Microsoft's Compact Framework (CF) counts as a second set of "published" assemblies,
     and so if you want to make binaries that can be executed on the CF and other versions of the
     CLR then you should use this option.
     The --retargetable option is used to indicate a particular assembly reference to 
     make retargetable in the produced binary.  There is no way to make all assembly references
     retargetable - you have to do it on a case-by-case basis.  Furthermore the reference
     to "fslib" is not retargetable, since you have to use the fslib provided in the F#
     distribution.


43.  F# now supports funcitons Map.Make and Set.Make that accept comparison functions and
     return record expressions that act as components.  These are akin to
     OCaml's Set.Make and Map.Make functors.  The release also includes Map,
     Set and Hashtbl implementations that use polymorphic comparison.  Hashtbl.Make is
     yet to be done.

44.  F# now supports "forall" types on fields. That is, fields can have types that logically
     speaking correspond to generic methods.  This is useful when records are used to
     represent modules, e.g. with Map.Make and Set.Make's fold functions.


45.  F# field names may now be used as part of the "." notation even when the field names
     have not been brought into the top level scope via an "open".  For example if
     a module contains
           type recd = { Name: string }
     then you may use
           x.Name
     if x is determined by local type inference to be of type "r".  This is subject to the
     same rules as .NET member lookups, i.e. the type of the value to the left of the "."
     must be determined by local type inference using annotations and other
     information available left-to-right, outside-to-inside.

46.  Optimization improvements to "==" and polymorphic comparison.

47.  A Visual Studio integration is now supported, with syntax
     highlighting, automatic parsing, automatic typechecking 
     and a simple project system.
      
48.  --target-winexe, --target-exe and --target-dll are now supported.

49.  Pervasives now supports string-named versions of all the Caml-style
     operators defined in that file, e.g. op_GenericEquality for '='.  See
     pervasives.mli for the full list of names used.

50.  A lexer generator along the lines of ocamllex/mosmllex is now supported.  
     Input files identical to ocamllex files are supported, with the following exceptions:
       - using 'as' to label internal portions of matched strings is not supported
       - '#' regular expressions are not supported
       - 'shortest' matching is not supported
       - Command line options -o, -ml, -q are not supported

     The Lexing library module is supported with a specification similar to the specification
     of OCaml's Lexing module.  This was coded from scratch.  Most of the fields 
     of the lexing state are hidden, adn thus differ from OCaml, with the exception 
     of Lexing.lex_start_p and Lexing.lex_curr_p.

51.  A parser generator along the lines of ocamlyacc/mosmlyacc is now supported.  
     Input files identical to ocamlyacc files are supported.  See the notes in the Parsing
     module in MLLib for some compatibility issues.

Changes between v0.6.5 and v0.6.6

Changes between v0.6.4 and v0.6.5