Some Smaller Features in the Latest Release of F#

Brian has blogged about some of the smaller features in the latest release of F# which weren't explicitly called out in the detailed release notes.

  • Error and warning messages have unique numbers (in particular replacing the ubiquitous "FS0191")
  • Some common error diagnostics have been improved
  • VS2010 Beta2 has more item tempaltes

I'll add a few here as well:

  • A note on version numbers

  • A note on .fsproj file portability

  • PowerPack: Adding "module" declarations to FsLex and FsYacc

  • Power Pack: Unicode Lexing

  • PowerPack: HashMultiMap constructor needs HashIdentity.Structural parameter

  • PowerPack: Explicit "open Microsoft.FShap.Math" needed for "complex"

A note on version numbers

A note on version numbers. In previous releases of F# we've used one version number for everything: language, library, power pack etc. This doesn't make quite so much sense when we now ship F# bits for use with both .NET 2.0 and 4.0. On the whole you won't need to be aware of this difference, but in this release we use:

  • 1.9.7 : the F# language version. This will be the number used at the top of the language specification

You'll also see 1.9.7.4 reported as the F# compiler version number for VS2010, and 1.9.7.8 for the compiler in the CTP ZIP and MSI. These compilers are the same apart from some very minor differences such as this.

FSharp.Core.dll has version number 2.0.0.0 or 4.0.0.0 in this release, depending on whether you're running on .NET 2.0 or 4.0. For .NET 4.0 references to the former are redirected to the latter automatically.

.fsproj files

For various reasons unrelated to F#, Visual Studio project files (.fsproj, .csproj etc.) can't be authored in a way that makes them imediately usable with both VS2008 and VS2010. I personally prefer to edit project files by hand, and if you don't mind doing that, then to make an F# VS2008 project file usable with VS2010 you just have to do two things:

  • Replace ToolsVersion="3.5" with ToolsVersion="4.0" at the top of the file
  • Replace

            <Import Project="$(MSBuildExtensionsPath)\FSharp\1.0\FSharp.PowerPack.Targets" />

with

             <Import Project="$(ProgramFiles)\Microsoft F#\v4.0\Microsoft.FSharp.Targets" />

at the bottom of the file. You may need to adjust some of the contents of the files as well, particularly project references.

PowerPack: Adding "module" declarations to FsLex and FsYacc

The F# Power Pack includes tools fslex and fsyacc, which are lexer generators and parser generators. You can use these in F# projects using an entry like the following in your .fsproj file:

    <FsYacc Include="Parser.fsy">
<OtherFlags>--module Parser</OtherFlags>
</FsYacc>

    <FsLex Include="Lexer.fsl" >
<OtherFlags>--unicode</OtherFlags>
</FsLex>

The "module" argument to FsYacc is recommended because F# now requests that you prefix compiled .fs files with a namespace or module declaration. FsYacc must add this to both generated .fs and .fsi. You can also add "--internal" if you want this module to be internal.

To specify a module declaration for an FsLex file, use a definition at the top of the .fsl file, e.g.

lex.fsl:

    {

        module internal Microsoft.FSharp.Compiler.Lexer

        ....

The different ways of treating this for FsLex and FsYacc are a little non-orthogonal, but this is how the F# Power Pack does work for this release, and we'll continue to support this going forward.

Power Pack: Unicode Lexing

Since we're on the topic of lexing and the power pack, we may as well mention unicode lexing. The "unicode" argument to FsLex is optional, but if enabled generates a unicode lexer.

A unicode lexer works with a LexBuffer<char> rather than LexBuffer<byte>. This means extracting the text from of a lexeme is a little different. There are basically two ways:

lexbuf.Lexeme -- returns a character array

LexBuffer<_>.LexemeString lexbuf -- returns a string

For example, the MegaCalc example in the F# tutorial includes this rule:

| ['-']?digit+ { INT32 (Int32.Parse(LexBuffer<_>.LexemeString lexbuf)) }

In a unicode lexer, you can use Unicode character classes and individual Unicode characters in your rules. For example, the following may be used as definitions in an FsLex file (note, these are definitions in the FsLex domain specific language, and not F# code)

let letter = '\Lu' | '\Ll' | '\Lt' | '\Lm' | '\Lo' | '\Nl'

let surrogateChar = '\Cs'

let digit = '\Nd'

let connecting_char = '\Pc'

let combining_char = '\Mn' | '\Mc'

let formatting_char = '\Cf'

let ident_start_char =

    letter | '_'

let ident_char =

    letter

  | connecting_char

  | combining_char

  | formatting_char

  | digit

  | ['\'']

 

PowerPack: HashMultiMap constructor needs HashIdentity.Structural parameter

The F# Power Pack includes a mutable collection type called HashMultiMap. The "new" constructor for this type now requires an extra argument of type IEqualityComparer<'T>. You can usually fill this in by using HashIdentity.Structural, which is an F# implementation of IEqualityComparer<'T> which works by using F# generic hashing and equality.

PowerPack: Explicit "open Microsoft.FShap.Math" needed for "complex"

The F# Power Pack includes a complex type and a function "complex" for making complex number values from rectangular coordinates. You now need to both reference the F# Power Pack and use "open Microsoft.FSharp.Math" to acccess this function.