Welcome to F#. F# is a programming language for the .NET platform with a design based on the ML 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 F# resources and community sites. You may be interested in tracking Don Syme's F# blog and/or blogging about your experiences with using F#.
Installation:
Using and Learning:
Troubleshooting:
You may run F# programs in conjunction with other CLI implementations such as Mono. Please read the notes below. Some more information is available at the F# Wiki.
F# On Mono
Library
type System.Net.WebRequest with
member x.GetResponseAsync() =
Async.BuildPrimitive(x.BeginGetResponse, x.EndGetResponse)
2033 F# Compiler doesn't work with type forwarders found in .NET Framework 3.5 SP 1 Beta1
Library
2033 Code Dom Error Reporting not working in 1.9.4.15, reported by Tomas Petricek (thanks Tomas!) 2062 Inapplicable error message on attributes on method parameter, reported by David Crocker (thanks David!) 2101 Performance regression with regard to inlining, reported by Stephan Tolksdorf (thanks Stephan!) 2108 Fix intellisense regression in 1.9.4.15 due to mistaken release of experimental code, reported by Howard Mansell (thanks Howard!) 2125 Stack overflow in structural equality test on 64-bit CLR, reported by Stephan Tolksdorf (thanks Stephan!) 2128 Regression: cannot convert the following F# Quotation to a LINQ Expression Tree
Language
Library
Tools
F# uses a form of type-directed operator overloading. (Type-directed operator overloading means that operators such as '+' resolve to different implementations depending on the static types of the two arguments.) Previous releases of F# used asymmetric, type-directed overloading that placed more emphasis on the type of the left argument rather than the type of the right argument. For some time it has been recognized that this form of operator overloading is somewhat unintuitive. This release switches this to use symmetric operator overloading. For example, consider the following cases:
let f1 x y = x + y //: int -> int -> int
let f2 (x:float) y = x + y //: float -> float -> float
let f3 x (y:float) = x + y //: float -> float -> float
let f4 (x:matrix) y = x + y //: matrix -> matrix -> matrix
let f5 x (y:matrix) = x + y //: matrix -> matrix -> matrix
let f6 (x:matrix) (y:vector) = x * y //: matrix -> vector -> vector
These indicate that operator overloading resolves independent of whether the known type information is associated with the left-hand or right-hand argument of the operator.
The two principles that now form the basis of F# operator overloading are
Resolution of an operator such as + is performed against a set of potential overload resolutions derived from the left and right hand argument types. For example, when resolving a constraint
static member (+) : float * matrix -> ?
The relevant operator overloads are drawn from the float and matrix types. At some points in inference (indeed very frequently) we have incomplete information about the types involved, e.g.
static member (+) : float * ? -> ?
In these cases it is important to note that later type information may discover additional nominal information, e.g. to resolve the constraint to
static member (+) : float * matrix -> matrix
In more detail,
open Microsoft.FSharp.Math
let f7 (x:Matrix<_>) y = x + y
Conditional method calls are a .NET feature where a call to particular methods marked with System.Diagnostics.ConditionalAttribute are only executed if a conditional compilation symbol such as DEBUG is defined. One common example of this is System.Diagnostics.Debug.Assert. F# now supports conditional method calls.
As a result of this change, calls to System.Diagnostics.Debug.Assert may no longer "trigger" in your code.
Uses of the assert function are now treated as if they are calls to System.Diagnostics.Debug.Assert. This means expressions such as assert (1=2) will not fire in your code unless --define DEBUG is specified. This follows standard .NET software engineering practice.
One exception is made for the syntactic expression form assert(false). This is given a special type in F# and OCaml, i.e. has variable return type not unit. This allows it to be used as a "cannot happen" signifier. In this case, if --define DEBUG is not specified then an AssertionFailure exception is raised in order to halt execution. If --define DEBUG is specified then System.Diagnostics.Debug.Assert, and if the assertion is ignored and execution continues then the AssertionFailure exception is raised in order to halt execution.
.NET is an object-oriented platform and thus includes the notion of null values for reference types. However, the use of null values is, in general, discouraged in F# programming. While it is possible to create null values for reference types, one of the design aims of F# is that this is not a commonly used technique and that, when used, the programmer is made aware of this.
In previous release of F#, creating null values of F# types was relatively easily, e.g. through the commonly used unbox function. This technique, however, will now raise a NullReferenceException. For example, the following code will now raise a NullReferenceException:
type MyRecord = { f : int }
let x = unbox<MyRecord>(null:obj)
This implemented via the use of efficient helper functions related to the types involved.
This change also eliminates several somewhat subtle inconsistencies with regard to types that use null as a valid representation. For example, the option type uses null to represent the None option. Unboxing a null value to one of these types now correctly succeeds and returns a valid value of the type.
In more detail, there are four kinds of types for F#:
The behaviour of the unbox and type test primitives of F# now treat these different categories appropriately.
Note that null is still used as a representation for some F# values, in particular None option values. In this case, the value doesn't carry runtime type information in the manner of other object values, and so type tests against such a value are inherently imprecise. This is correct and expected behaviour for these types.
If necessary, null and default values may be generated by calling the new library function Unchecked.defaultof<type>, a helper function specifically designed to make uses of arbitrary null and default values for F# types more traceable in code.
type MyRecord = { f : int }
let x = Unchecked.defaultof<MyRecord>
Expressions of the form expr -expr, e.g. x -y now give a deprecation warning asking you to rewrite these as either expr - expr or expr-expr. This is to make room for a future design change.
The keyword global has been reserved for future use by F# code
'base' variables must now be called 'base'.
A deprecation warning is now given if this is not the case. In a future release of F# base variables will necessarily be called 'base'.
Intrinsic members take predence over extension members .
Previously extension members were taking priority over intrinsic members in base classes. This has now been corrected.
Generic Equality now uses Object.Equals
Uses of the generic equality operator (=) and related operators are now implemented via calls to System.Object.Equals.
Downcasting For Interface Types.
The conversion operator expr :?> type can now be used to convert an interface or non-sealed class type to any other interface type. This matches the C# behaviour of this operator, with the exception that conversions from variable types are not permitted: in that case the expression should first be converted to an object using box.
Handle Optional Arguments Correctly when using a method as a first class function value.
As has been reported several times in bug reports, when operations such as Async.Run which take optional arguments are used as first-class values the resulting function value previously required the optional argument be made explicit. This has now been changed, and the optional argument is dropped instead.
Change .[] overload resolution behaviour.
Previously, the resolution of the expr.[expr] operator did not apply operator overloading rules. This led to incompletenessed where the operator could not be used in conjunction with certain C# types. This has now been corrected.
Deprecate the Unicode symbols in the language.
The Unicode symbols for quotations have been deprecated. Instead, the ASCII symbols <@ @> and the prefix operators % and %% should be used instead.
Sealed attribute . This attribute may be added to class types to mark them 'sealed', i.e. no base types.
[<Sealed>]
type C(x:int,y:int) =
member this.X = x
member this.Y = y
member this.Sum = x+y
AbstractClass attribute . This attribute may be added to class types to mark them 'abstract', i.e. missing implementations of some members, and/or with constructors that can't be used directly
[<AbstractClass>]
type C(x:int,y:int) =
abstract X : int
abstract Y : int
abstract GetSum : int -> int
typeof may be used in attributes, deprecate (type ...) syntax
[<SomeAttribute(typeof<int>)>]
type C(x:int,y:int) =
abstract X : int
abstract Y : int
abstract GetSum : int -> int
Decimal literals now implemented. For example, 120.00M. The decimal conversion function is now also supported amongst the standard set of conversion functions, and decimal is no longer a keyword.
let pocketMoney = 0.25M
let GDP = 12416505085952.00M
Supply Named and Optional Arguments to COM methods. It is now possible to use the F# optional argument mechanism to supply arguments to COM methods. This is very important when working with Excel and Word Primary Interop Assemblies. For example,
chartobject.Chart.ChartWizard(Source = range5,
Gallery = XlChartType .xl3DColumn,
PlotBy = XlRowCol.xlRows,
HasLegend = true,
Title = "Sample Chart",
CategoryTitle = "Sample Category Type",
ValueTitle = "Sample Value Type")
Here 4 arguments have been omitted from the programmatic specification of an Excel chart.
Allow construction of delegates taking byref arguments
fold_left performance improvements.
A number of library functions that take binary functions have been optimized. Many thanks to the folk at Morgan Stanley for sugesting these!
Collections that previously threw IndexOutOfRangeException now throw KeyNotFoundException.
The OCaml-compatibility exception type Not_found is now mapped to System.Collections.Generic.KeyNotFoundException, rather than System.IndexOutOfRangeException. This means a number of F# functions now raise KeyNotFoundException instead of IndexOutOfRangeException. In the rare case where you explicitly catch IndexOutOfRangeException in your code you will get a warning and may need to adjust your exception handling accordingly. This change was made because IndexOutOfRangeException is a CLR-reserved exception which should not be raised in user or library code.
Addition of the 'enum' overloaded function.
The enum function can be used to convert integers to enumerations. Likewise, the function int32 can be used to convert back to an integer.
let sunday = System.DayOfWeek.Sunday
let monday = enum<System.DayOfWeek> 1
let tuesday = enum<System.DayOfWeek> 2
Deprecate the Enum.to_int and Enum.of_int functions.
These can be replaced by uses of enum and int32 respectively.
Access control checking for modules and types implemented.
That is, private and internal annotations on modules and types are now implemented. Previously these gave a warning.
Deprecate the use of string.CompareTo in favour of System.String.CompareTo.
This makes room for a planned design change to add a conversion function called string.
Deprecate the IEnumerable module in favour of Seq.
Rename MailboxProcessor.PostSync to MailboxProcessor.PostAndReply, deprecating the old name
Deprecate the CompatArray and CompatMatrix modules when used with .NET 2.0.
Future releases of F# will make .NET 2.0 the default. These modules are only required when using .NET 1.x. When using .NET 2.0 and above, uses of these modules can be replaced by uses of Array and Array2 respectively.
Deprecate the truncate OCaml-compatibility function.
Instead you should use the synonymous for int_of_float or the F# conversion function int, applied to float values. The design of other F# conversion functions and operators means it is much more natural for truncate be an overloaded function applying to a range of numeric types. Thus a deprecation warning is now given on the use of the existing truncate function.
Make 'lock' function safer: may now only take reference types.
Counter Examples from Incomplete Pattern Matches. For example,
let f x =
match x with
| 1 -> 7
| 2 -> 49
stdin(12,14): warning FS0025: Incomplete pattern matches on this expression. The value '3' will not be matched
Note: There is actually one known bug here, where incomplete matches on union types do not always give a valid counter example. This is being addressed.
Implement redundancy checking for isinst patterns. That is, duplicate or redundant type tests in patterns will now be reported as warnigns.
Many Improved Error Messages
Ctrl-C now copies, Ctrl-. used for Interrupt. When used in Visual Studio, it is natural for Ctrl-C to be interpreted as 'copy'. This Ctrl-. ('Control-Stop') is now used for interrupt.
Menus supported. The interrupt, select-all, copy, paste and clear options are now available from the right-click menu.
1171 F# Compiler bug binding to a SOAP dll 1109 F# Compiler Make assert a function 1325 F# Compiler Enums of chars are not accepted by F# Interactive 1316 F# Compiler Throw away invalid paths (#r) in FSI 1341 F# Compiler Compiler should reject explicit class construction when an implicit one is defined 1423 F# Compiler bad error message: The member or object constructor 'Random' takes 1 arguments but is here supplied with 1. 1227 F# Compiler ensure we can supply named and optional arguments to COM-interop methods 1404 F# Compiler optional arguments handled incorrectly when using a method as a first class function value. 1418 F# Compiler Methods on Enums should not be allowed 1457 F# Compiler FParsec test 0.4.2. failing with byref check 1185 F# Compiler change .[] overload resolution behaviour 1244 F# Compiler unnecessarily choosing defaults for variables unconstrained, leading to spurious warnings and true errors being needlessly downgraded to warnings 1430 F# Compiler Compiler spits out duplicate errors when given bogus syntax for named arguments 1462 F# Compiler Poor (and repeated) error message on type mismatch 1034 F# Compiler Downcasting for interface types 151 F# Compiler Cannot construt delegate values that accept byref arguments 1024 F# Compiler bug in type inference allows normal values to be polymorphic (type functions have to be declared explicitly and only at the top level) 1187 F# Compiler problem with object constructors and self references 1476 F# Compiler Setting static field in generic type fails to resolve in typechecker 1365 F# Compiler unexpected Warning 65 in the absence of structural hashing and comparison 1472 F# Compiler double quote breaks comment parsing (F# not fully compatible with OCaml) 338 F# Compiler Incomplete pattern matches should report cases that are not covered. THis could also be used by VS plugin when suggesting completions 1366 F# Compiler Unboxing inconsistencies w.r.t 'null' 1488 F# Compiler Implement redundancy checking for isinst patterns 1322 F# Compiler Unhandled Exception using --clr-mscorlib option 1470 F# Compiler Misleading warning "unit was constrained to FSharp.Core.Unit" 1484 F# Compiler Internal Error when compiling a try-with construct 1342 F# Compiler Bad error messages when constructs can't be quoted 1433 F# Compiler Count of supplied parameters incorrect in error message if named parameters are used. 1060 F# Compiler Quotation error: type varaible not found in environment 1463 F# Compiler quotation of a private value error is not reported until codegen, so is not reported in Visual Studio 1445 F# Compiler Failure when generating code for generic interface with generic method 1390 F# Compiler Pattern matching with bigint literals does not work 1105 F# Compiler params attributes not supported 1279 F# Compiler Constructor call with the object-initialization-expr should error 1278 F# Compiler Unresolved generic constructs in quotations should error instead of warn. 609 F# Compiler not printing explicit type constraints on type declarations 1101 F# Compiler spurious warning:This construct causes code to be less generic than indicated by the type annotations. The type variable 'd has been constrained to be type 'System.IDisposable'. 1502 F# Compiler implement a "sealed" attribute 1533 F# Compiler Support "static let" 1233 F# Compiler cyclic inheritance bug 1452 F# Compiler Complete checks for structs 1529 F# Compiler Incorrect IL generated for call to static method on a valuetype 1490 F# Compiler can't use typeof in attributes 997 F# Compiler Unable to implement interfaces with generic methods 1570 F# Compiler New testcase for "CustomAttributes on Module" failing 1392 F# Compiler Space should not be required between : and > 1437 F# Compiler Assembly attribute w/array parameter fails to build 1497 F# Compiler Quotations 'bindCtor' issue (WebTools & F# 1.3.9.14) 1622 F# Compiler Cannot use "null" in Attributes 1258 F# Compiler Consider design for parser and typechecker that doesn't require exceptions 1050 F# Compiler dot notation on datatype constructors is not resolved 1094 F# Compiler implement internal/public access control escape checks 1160 F# Compiler object should be evaluated eagerly when using a method as a first class function 1304 F# Compiler Explicit program entry point 1500 F# Compiler support conditional compilation (e.g. DEBUG, CODE_ANALYSIS) 1541 F# Compiler finally clause in seq is called out of order, before yield 1590 F# Compiler printf formats should reveal enough information to allow a reasonable implementation of using them in active patterns to scan strings 1644 F# Compiler Generated .fsi is wrong for optional (?-style) parameters 791 F# Compiler OverloadID attributes not in generated .fsi files 1552 F# Compiler Internal error: badly formed Item_ctor_group. 1332 F# Compiler ReflectedDefinition returning null should be allowed 1542 F# Compiler Repeated type argument not being inferred: type Graph <'a> = HashMultiMap<'a,'a> 959 F# Compiler TOp_asm in pattern match 1254 F# Compiler Spurious casts being inserted for upcast operations 1379 F# Compiler Property setter notation be used with mutable .NET fields and mutable record fields 1754 F# Compiler Indexer access should use overloading and not warn on generic constraint 721 F# Compiler suggested undentation from Robert pickering 1398 F# Compiler indentation rule is too strict 1458 F# Compiler Using anonymous type variable in attribute should either not be allowed or should do the right thing 1762 F# Compiler Method name resolution should consult intrinsic methods first 1764 F# Compiler Apply ADJACENT_PREFIX_MINUS rules to '+' as well. 1765 F# Compiler members being printed in reverse alphabetical order in signatures 1766 F# Compiler Treat all the funky operator names like '.[]<-' as single tokens. 1767 F# Compiler Desugaring of computation expressions should make use of operator overloading 1768 F# Compiler Allow the definition of immutable structs using the implicit construction syntax 1526 F# Compiler Possible Regression in FSforScientists sample 1165 F# Compiler Support return attributes? 1660 F# Compiler testcase failure: fsharp\core\verify 1608 F# Compiler Testcase failure: MutateStructFieldOnPropertySet 1112 F# Compiler Bug in definition of generic interface 1625 F# Compiler fsc generates assemblies that don't load/peverify 1683 F# Compiler dispatch slot checking in object expression manages to match non-virtual member 1730 F# Compiler F# allows Enums over string type (Does not PEVerify) 1743 F# Compiler incorrect resolution of overrides 1748 F# Compiler Internal Error: when calling a base member 1749 F# Compiler Interfaces should not allow implicit construction pattern. Bad codegen. 1431 F# Compiler 'end' token ambiguity for interface/class: Incorrect and unactionable error messages when defining class which just implements an interface 1148 F# Compiler class that only implements interface is parsed/recognised as interface (#light) 1275 F# Compiler signature matching is comparing declared interfaces not interface sets 1553 F# Compiler Checks associated with internal and private modules are not yet fully implemented. 1802 F# Compiler Give error messages a "default" number to ensure consistent error message format 1803 F# Compiler Field fails to hide property in parent 732 F# Compiler private modules still appearing in VS object browser 1797 F# Compiler large error range when solving constraint 942 F# Compiler mutable variable escapes its scope when used with an event handler 1505 F# Compiler Need to generate 'GetHashCode' on eception types 1707 F# Compiler MaxInt+1 numeric literals should error 1530 F# Compiler Attributes on properties should not also be put on getter and setter 1077 F# Compiler closing brace following generic type bracket is syntax error without whitespace (lexed into symbolic token). 1831 F# Compiler Finally block called twice for nested sequence comprehensions 1854 F# Compiler TestCase Failure: Peverify error in Adcenter Adpredictor sample 1763 F# Compiler Resolution to extension members should look through the entire hierarchy of a type 1363 F# Compiler Need to apply DefaultMemberAttribute to enable C# to consume F# Indexers 313 F# Tools fsyacc --ml-compatibility: Does not open the Parsing module 1425 F# Library check structural equality on non-zero based multi-dimensional arrays 932 F# Library Fix NaN equality on structured terms and make structural equality go through object.Equals 1059 F# Library "=" doesn't work with 2D array values 1311 F# Library NullReferenceException in StructuredFormat.Display.leafFormatter 1384 F# Library Suggestion: allow explicit exception type definitions to override members - specifically the Message property 975 F# Library Map Exceptions: when a key is not in a map, we get an index out of range exception instead of something like KeyNotFoundException 1572 F# Library support "enum" and "delegate" type decomposition constraints for typesafe generic code over enums and delegates (e.g. conversions and event creation) 1591 F# Library Bug in Async.Generate reported by David M Peixotto [dmp@rice.edu] 1598 F# Library Problem with Array.fold1_left 1571 F# Library Allow "int" and "char" functions to convert to/from int/char 1740 F# Library problem with Lazy.SynchronizedForce() 1760 F# Library Implement Unchecked.defaultof<_> (delete LanguagePrimitives.DefaultValueUnchecked) 1761 F# Library Implement IComparable and Equals on Math.Complex 1374 F# Library compelx number pretty printing broken 1776 F# Library async implementation hits tail recursion problems on 64-bit 1796 F# Library ThreadAbort is causing PostSync to raise exception 1800 F# Library implement decimal literals, "decimal" conversion function 1801 F# Library implement 'sign' and 'round' overloaded functions in library 1804 F# Library sprintf "%A" formats should print decimal literals in "g" format rather than any specific floating point format 1731 F# Library Need a way to cast primitive types to/from enums 1108 F# Library Langauge Specifiation Issue: Enumerations don't convert to int32, uint32 etc. 1861 F# Library lock function can be used on integers 1791 F# Perf Apply fold_left performance improvements to research branch (for Morgan Stanley) 1819 F# Testing Test error in tmptest.mli 1467 F# Language AbstractClass attribute 1599 F# Language Dispose not called in 'use _ = foo()' 1248 F# Language symmetric overloading 339 F# Language Support generic recursion 1558 F# Language Should offside rule be applied to last clause of match? 1633 F# Language Compiler override of Equals should not throw exceptions, per .NET coding guidelines. 1638 F# Language When functions are use/passed as values, we should not insist on optional values. 755 F# Language support marsahlling parameter and return attributes 1395 F# Language parsing of minus (-) 641 F# Language Deprecate (type ty) syntax 1614 F# Language Should classes, unions, exceptions, records etc have a way to _not_ be marked with Serializable? 1535 F# Visual Studio Tooltip for List.combine claims "List.combine is a synonym for List.combine" 1651 F# Visual Studio Public constructors of non-visible types are showing up in top-level completion list 1652 F# Visual Studio Namespaces with no visible members at a given program point should not be included in completion list
This release includes a prototype of access controls, a feature that lets you use the keywords internal and private to mark values, members, record fields and union constructors with restricted visibility. For example:
let internal x = 1
type MyRecord =
{ private x : int }
member obj.TwiceX = obj.x + obj.x
static member Create(n) = { x = n }
CAVEAT: a number of checks are not yet implemented. In particular, if you mark a type or a module with private or internal you will get a warning that the checks for these kinds of constructs are not yet complete.
Type augmentations separated from a main type definition now give a warning if they contain interface implementations or implementations of overrides (see TypeAugmentations). This is because of the unsoundess mentioned as part of the specification, in particular "Augmentations that define interface implementations and override defaults may result in undefined behaviour if the intervening code creates instances of the object at runtime and makes calls via the virtual dispatch slots implemented by these functions (ill-defined recursion cycles can in principle occur)." This feature may be deprecated in a future release of the language.
The "static optimization" language construct now gives a warning it is used outside the implementation of the F# library. Use of this construct requires extreme care and if misused can cause unverifiable to be genreated or lead to the behaviour of code varying under different optimization settings.
F# now permits classes (including those with implicit constructors) to have uninitialized val fields marked with DefaultValueAttribute. This is primarily for codedom codegen. These fields will be initialized to null or the zero-bit-pattern for structs. These may also be marked static val. As a result we also implemented the setting of static F# fields.
Add EDITING define to Visual Studio mode: this is ON as far as Visual Studio editing is concerned, but OFF for compilation and execution. This is useful when mimicking generated codedom code in a partially implemented file
Constructed class types may now be mutually recursive with other types.
Multiple custom attributes can now be specified using repeated uses of [< ... >], as well as via the previous technique where a single [< ... >] is used with semicolon separation.
Ranges such as [ 1.1 ... 100.1 ] over floating point numbers are now deprecated. The floating point computations here are inherently highly sensitive and the resulting sequences often end up having a non-intuitive number of elements under any reasonable specification. For now use an integer range and convert to floating point. We expect to add a 'linspace' operator giving size and number of divisions in a future release.
Add prefix operators "%" and "%%" as ASCII-equivalent for Unicode section marker operator used for splicing into quoted expressions (i.e. for data binding into quotations expressions).
The F# libraries have been renamed: fslib.dll becomes FSharp.Core.dll and mllib.dll becomes FSharp.Compatibility.dll. This renaming has been planned for some time in order to give F# DLLs more standard .NET library names and we believe it will help us to grow the library further as time goes on.
Move some less important collections to FSharp.Compatibility.dll.
Move the Int32, Int64 etc. modules to FSharp.Compatibility.dll, though they currently remain in the Microsoft.FSharp.Core namespace.
Deprecate the undocumented Microsoft.FSharp.Core.Func module.
Some additional identifiers have now been marked with the 'OCaml compatibility' attribute
Added Permute to vector type, PermuteRows, PermuteColumns to matrix type.
Improved Library Documentation. Thanks to Ralf Herbrich for helping us complete minimal documentation for each funciton in the library.
Add Async.Parallel2 and Async.Parallel3 to Microsoft.FSharp.Control
Add more members to BigInt, Add modulus operator to BigInt.
Add INormFloat for generic distance algorithms.
Add WebRequest.GetResponseAsync to Microsoft.FSharp.Control.CommonExtensions.
FxCop: Fix some low hanging fruit so fewer errors are reported
Adjust ConcurrentLife sample so it compiles and runs correctly
Update F# Linq samples to match the Expert F# book and to work with Orcas Beta2
Improved ASP.NET sample help
Add command line option to permit the name of mscorlib.dll to be set. For use with Singularity.
1007 F# Compiler Improve error message for property member without "this" (was internal compiler error).
1061 F# Compiler Two property nodes being generated for get/set metadata
1103 F# Compiler Bad code generation for active patterns from fswebtools example
1104 F# Compiler *** WARNING: basic block at end of method ends without a leave, branch, return or throw. Adding throw
1111 F# Compiler fswebtools code doesn't verify
1112 F# Compiler Cannot define an interface with a generic method
1116 F# Compiler Active pattern example fails where function is defined by matching (Reported by Andrew Kennedy - thanks Andrew!)
1117 F# Compiler Bindings that look like function definitions are interpreted as pattern
matches without warning. Add a warning for this case to allow for later language
design change here.
1121 F# Compiler Allow attribute targets "module", "type", "assembly", "class", "struct", "interface", "delegate", "property", "field"
1126 F# Compiler Unverifiable code generated by TLR and other optimizations when used with
constrained local generic functions
1253 F# Compiler Implement optimizations related to 'when' filters in sequence expressions
1255 F# Compiler Make static optimization construct library-only (give a warning)
1261 F# Compiler CodeDom bug: FieldTest is failing in codedom suite
1263 F# Compiler Nested mutable structs not being mutated correctly
1264 F# Compiler bignum/bigint literals don't meet specification, e.g. f -3N is accepted when it should be f (-3N) like all other integer forms
1265 F# compiler Deprecate #hardwhite and #white (old names for #light)
1266 F# Compiler Internal values are being optimized away in cross-module situations
1271 F# Compiler Internal and Private keywords in 1.9.33
1272 F# Compiler New-ing a sub class with unimplemented abstract members should not be allowed (reported by Keiko Nakata - thanks Keiko!)
1300 F# Compiler [FS 1.9.3.7] Issue with bindMethodBySearch & bindProp in quotations.fs
1324 F# Compiler [FS 1.9.3.7] Bad binary created when implementing COM interop interface. (Gacutil: Method does not have an implementation)
1318 F# Compiler [FS 1.9.3.7] Weird behavior instantiating .NET objects
1317 F# Compiler [FS 1.9.3.7] assembly private internal fields are leaking across assemblies through inline
1238 F# Compiler Bug reported by Tomas Petricek: give error when extension members defined in a namespace
1336 F# Compiler constraints "struct" and "not struct" do not work in #light code, and "not struct" never works
972 F# Interactive FSI reports "error: forceM: - envGetMethB: failed"
982 F# Interactive Visual Studio FSI doesn't function correctly on some machines. Force session to be in UTF8.
This fixes a codepage related bug that rendered input/output invisible.
984 F# Interactive --exec doesn't function correctly
1027 F# Interactive Incorrect parsing of some expressions. Expr interactions were dropping lookahead tokens.
1053 F# Interactive Bug accessing XLinq op_Explicit method from FSI
1198 F# Interactive #time ms printing 2d not 3d
1033 F# Visual Studio Some errors related to DLL references were being swallowed into Visual Studio (reported only once then swallowed into cache).
1037 F# Visual Studio Adjust "incomplete matches warning" so it underlines less intrusively in visual studio.
1100 F# Visual Studio Missing DLLs specified in project arguments not reported correctly in Visual Studio error window
1106 F# Visual Studio VS mode is swallowing some errors that reporting that a DLL can't be found
1303 F# Visual Studio F# addin global keybinding localisation work around - failing on KoreanOS/DefaultVS.
1095 F# Samples Ensure FLinq really works under Orcas Beta2
1267 Samples PersonalWebSite sample is busted (reported by Tomas Petricek)
1268 Samples F# version number not being added to web.config files in samples
1118 F# Library Scaling operator missing from matrix class (reported by Martin Szummer - thanks Martin!)
1017 F# Library Range comprehensions fixes for wraparounds and min/max int conditions. Exact number of steps with floats where possible.
1051 F# Library Calls to F# members should be quoted as MethodCall and PropertyCall nodes in the quotation tree
1127 F# Library foldByCol and foldByRow are incorrectly implemented in F# matrix library
1129 F# Library Add RowVector.zero to the F# matrix library
1080 F# Library Seq.cache_all does not have the properties of cache. Deprecate Seq.cache_all,
add Seq.cache to return a IDisposable handle
1215 F# Library bigint now has properties which are printed by fsi.
1293 F# Library HTML docs hrefs to lower case types not always correct
1052 F# Tools Fix numerous issues with CodeDom code generation: Generate static fields, Remove old hacks
for generating static fields, Generate type code snippets,Fix order of
compilation of files.
The following syntax forms
expr := ...
| e1.[range1]
| e1.[range1,range2]
range := e2..e3
| ..e3
| e2..
| *
represent slicing from a 1D or 2D data structures that supports associative lookup on ordered keys. In practice these forms can be used with
For example:
let s1 = "abcdef"
s1.[*] = s1
s1.[0..] = s1
s1.[1..] = "bcdef"
s1.[2..] = "cdef"
s1.[5..] = "f"
s1.[6..] = ""
let m1 = matrix [ [ 1.0; 2.0; 3.0; 4.0; 5.0; 6.0 ];
[ 10.0;20.0;30.0;40.0;50.0;60.0 ] ]
m1.[*,*] = m1
m1.[0..,*] = matrix [ [ 1.0; 2.0; 3.0; 4.0; 5.0; 6.0 ];
[ 10.0;20.0;30.0;40.0;50.0;60.0 ] ]
m1.[1..,*] = matrix [ [ 10.0;20.0;30.0;40.0;50.0;60.0 ] ]
m1.[*,1..] = matrix [ [ 2.0; 3.0; 4.0; 5.0; 6.0 ];
[ 20.0;30.0;40.0;50.0;60.0 ] ])
The primary restriction is that the syntax can't yet be used to extract a vector from a matrix, e.g.
m1.[1,*]
m1.[*,1]
are not yet valid syntactic forms. These would have to map to different operators.
Technically speaking, the above represent calls to the Microsoft.FSharp.Core.Operators operators
val (.[..]) : ^src -> 'idx option -> 'idx option -> ^res
val (.[..,..]) : ^src -> 'idx1 option -> 'idx1 option -> 'idx2 option -> 'idx2 option -> ^res
i.e.
e1.[e2..e3] == (.[..]) e1 (Some e2) (Some e3)
e1.[e2..] == (.[..]) e1 (Some e2) None
e1.[..e3] == (.[..]) e1 None (Some e3)
The implementation of (.[..]) requires:
member GetSlice : 'idx option * 'idx option -> 'res
member Item : 'idx -> 'elem with get
Similar conditions are used for the 2D lookup operator.
Members (but not let-bound functions) may have optional arguments. These must come at the end of the argument list. An optional argument is marked with a ? before its name. Inside the member the argument has type option<argType>. On the callside the argument typically appears to have type argType, though there is a way to pass a value of type option<argType> if necessary (see below).
let defaultArg x y = match x with None -> y | Some v -> v
type T() =
static member OneNormalTwoOptional (arg1, ?arg2, ?arg3) =
let arg2 = defaultArg arg2 3
let arg3 = defaultArg arg3 10
arg1 + arg2 + arg3
static member TwoOptional (?arg1, ?arg2) =
let arg1 = defaultArg arg1 3
let arg2 = defaultArg arg2 10
arg1 + arg2
In a signature optional arguments appear as follows:
static member OneNormalTwoOptional : arg1:int * ?arg2:int * ?arg3:int -> int
static member TwoOptional : ?arg1:int * ?arg2:int -> int
Callers may specify optional arguments either:
For example:
T.OneNormalTwoOptional(3)
T.OneNormalTwoOptional(3,2)
T.OneNormalTwoOptional(arg1=3)
T.OneNormalTwoOptional(arg1=3,arg2=1)
T.OneNormalTwoOptional(arg2=3,arg1=0)
T.OneNormalTwoOptional(arg2=3,arg1=0,arg3=11)
T.OneNormalTwoOptional(0,3,11)
T.OneNormalTwoOptional(0,3,arg3=11)
T.OneNormalTwoOptional(arg1=3,?arg2=Some(1))
T.OneNormalTwoOptional(arg2=3,arg1=0,arg3=11)
T.OneNormalTwoOptional(?arg2=Some(3),arg1=0,arg3=11)
T.OneNormalTwoOptional(0,3,?arg3=Some(11))
Optional arguments can't be used in member constraints. They can be used in interface and abstract members. The compiled representation of optional arguments is fragile, in the sense that the addition of further optional arguments to a member signature will result in a compiled form that is not binary compatible with the previous compiled form.
Calls to members (but not let-bound functions or function values) may use named arguments. For example
System.Console.WriteLine(format="Hello {0}",arg0="World")
System.Console.WriteLine("Hello {0}",arg0="World")
System.Console.WriteLine(arg0="World",format="Hello {0}")
Named arguments may not be used with the curried arguments of a member (only the initial set of "tupled" arguments).
Named arguments must appear after all other arguments:
System.Console.WriteLine(arg0="World","Hello {0}")
The names of members may be listed in signatures and on the signatures used for abstract members, e.g.
static member ThreeArgs : arg1:int * arg2:int * arg3:int -> int
abstract TwoArgs : arg1:int * arg2:int -> int
Recall that F# automatically implements comparison and hash semantics for tuple, record and discriminated union types (only). Now F# will also implement Object.GetHashCode and Object.Equals for these types. For example:
> let x = box (1,2);;
val x : obj
> x.GetHashCode();;
val it : int = 5
> let x2 = box (1,2);;
val x2 : obj
> x2.GetHashCode();;
val it : int = 5
> x2.Equals(x);;
val it : bool = true
This means System.Collections.Generic.Dictionary etc. will now be usable with tuple, record or discriminated union keys with the expected semantics without supplying a custom comparer. This eliminates a common source of confusing and possible unexpected behaviour.
Bugs fixed:
977 Fix: resx files compiled without change to cwd.
Fix: FSI reflection emit support for constrained callvirt opcodes.
Fix: Hashtbl copying bug.
Fix: nested module/type loading bug.
Fix: performance improvements to BigNat and BigInt.
New keyword. The identifier use is now a keyword.
use bindings for deterministic resources. In expressions the binding form use x = expr in body is equivalent to using expr (fun x -> body). Otherwise the binding form has the same behaviour as let, e.g. the in can be dropped when using the #light syntax option.
Reserve keywords for future syntax extensions. All identifiers ending with ! and ? are now reserved for future language extensions.
Reserve keywords for accessiblity extensions. The identifier internal is now reserved as a keyword.
Deprecate old defaulting scheme for overloaded operators.. Once upon a time all statically-resolved overloading operators used an implicit default of int. THis default can now be explicitly defined using a series of default constraints. The old scheme has been removed. This should result in better error messages in many situations.
Can now use flag1 ||| flag2 as constants in custom attributes. e.g.
[]
Experimental Asynchronous Computation Library. See Microsoft.FSharp.Experimental.Control.
Experimental Workflow/Monadic Syntax. See Microsoft.FSharp.Experimental.Control.
Bugs fixed:
951 11/05/2007 F# Visual Studio Plugin Major intellisense failure
830 11/05/2007 F# Visual Studio Plugin Intellisense should show enum values in hover over or "dot" lookup on an enum typed-value
926 11/05/2007 F# Compiler assertion failure in tc.ml
531 11/05/2007 F# Language Cannot use "A ||| B" in enum flags when specifying a custom attribute (not a recognised constant)
937 10/05/2007 F# Language enums on not int32 types? e.g. int64.
948 04/05/2007 F# Compiler xml docs are getting dropped on properties
946 02/05/2007 F# Compiler comment lexing does not handle quotes and backslashes inside verbatim strings
945 02/05/2007 F# Compiler comment lexing does not handle quotes inside quoted strings
944 01/05/2007 F# Language Need to split IDelegateEvent into IPrimitiveDelegateEvent and IDelegateEvent (for CodeDom)
936 01/05/2007 F# Compiler custom attributes with enum typed properties generate invalid IL code.
934 01/05/2007 F# Compiler undescore and uppercase variables may not be used as arguments to object constructors
935 01/05/2007 F# Compiler name clashes in generated field names (a/a0)
17/05/2007 F# Compiler fix minor bugs preventing F# Interactive from running on Mono
17/05/2007 F# Compiler fix bug with code generation for pattern matching on structs
17/05/2007 F# Compiler make Microsoft.FSharp.Math.Complex a struct
17/05/2007 F# Compiler Check virtual slots are revealed in signatures if the type is revealed to have an object-model representation
17/05/2007 F# Compiler Fix two Visual Studio crashes due to recursive class hierarchies and recursive type abbreviations
17/05/2007 F# Compiler Intellisense for F#-defined enum types
17/05/2007 F# Compiler Fix bad error mark in Visual Studio for missing DLL reference
17/05/2007 F# Compiler Fix long comment parsing
17/05/2007 F# Compiler Fix install on Orcas Beta1
17/05/2007 F# Compiler Fix minor problem with DLinq sample
17/05/2007 F# Compiler Minor fixes for Microsoft.FSharp.Experimental.Control.Async
17/05/2007 F# Compiler Allow access to the types implicity defined by 'exception' declarations
17/05/2007 F# Visual Studio Plugin Auto install for VS versions 7.1, 8.0 and 9.0 (Orcas Beta 1)
Overloaded numeric conversion functions. The functions int, float, float32 etc. now overloaded conversion operators. For example, you can replace Int32.of_float and Int32.of_int64 and all similar operators that convert to int by just int (or int32, which is equivalent). Likewise for sbyte, byte, int16, uint16 int32, uint32, int64, uint64, nativeint, unativeint, float, float32, single, double.
Checked arithmetic Open Microsoft.FSharp.Core.Operators.Checked to get checked arithmetic versions of +, -, * and the above conversion operators.
Updated FLinq sample The FLinq sample has been updated to use the technique outline in Don Syme's ML Workshop LINQ paper from 2006. More details to follow in blog entries.
Bugs fixed:
895 "type" links broken on F# manual pages online
893 unicode lex bug 0x800 - 0x7ff
894 file hashes not being added to assembly resouce
900 --quotation-data flag problems causing problems for many things in F# Interative from Visual Studio
903 catch and report exceptions on user threads without killing fsi
907 quotation API TopDefnData should use an Assembly value.
909 Add Seq.cache_all
910 Seq.filter is broken on 64-bit
911 Fast F# cannot be unset, and should be ignored anyway
898 Invislbe error location information reported in Visual Studio
912 {} still gives tyref_of_stripped_typ
914 Pattern matching code causes NullReferenceException
913 Nested enums not showing up under intellisense, e.g. System.Environment.SpecialFolder
904 explicit instantiation of generic type not found
905 Intellisense failure for static method in generic collection class
918 Poor error when generic type given the wrong number of type arguments
916 Should not be printing to stderr on "fsi --exec"
915 Add updated LINQ sample (updates are on Don’s laptop)
924 structural comparison should fail for incomparable types
923 Add Array2.rebase
922 Use operator overloading for colelction types Tagged.Set, Tagged.Map, Tagged.HashSet, Tagged.HashMultiMap
This release includes a preview version of ``implicit class construction'' or the ``compact class syntax''. An class has an implicit constructor if arguments are present following its type declaration. The arguments to the implicit constructor follow the type name, then a sequence of let-bindings (prior to the members) define the object initialisation. Note, the let bindings are in scope over the members, but they are private to this class. For example:
type File1(path) = class
let innerFile = new FileInfo(path)
member x.InnerFile = innerFile
end
let myFile1 = new File1("file.txt")
Classes with an implicit constructor have zero, one or more arguments such as path after the name of the type constructor. Furthermore the body of the class may contain let bindings, which are always private to the class, indeed private to the object (you can't access the let bindings even for other values of the same type). Above we have also added the a property member InnerFile to reveal the value of the value of the innerFile. Here is a second example:
type Counter(start, increment, length) = class
let finish = start + length
let mutable current = start
member obj.Current = current
member obj.Increment() =
if current > finish then failwith "finished!";
current <- current + increment
end
Logically speaking, this class is equivalent to:
// The above code is equivalent to the following:
type Counter = class
val start: int
val increment: int
val length : int
val finish : int
val mutable current : int
new(start, increment, length) =
{ start=start;
increment=increment;
length=length;
finish = start + length;
current = start; }
member obj.Current = current
member obj.Increment() =
if obj.current > obj.finish then failwith "finished!";
obj.current <- obj.current + obj.increme
end
The first definition of Counter is one third the size of the second, so obviously the syntax has some advantages. Indeed we believe this feature is part of the key to enabling mixed OO/functional programming in practice.
Note this feature is in many ways similar to those found in OCaml and other langauges.
Classes can include both implicit and explicit constructors
When using implicit class construction the call to the base class constructor is specified as part of the inherits declaration itself.
type Base1(state:int) = class
member x.State = state
end
type Sub1(state:int) = class
inherit Base1(state)
member x.OtherState = state
end
let myOtherObject = new Sub1(1)
The types may be generic. Type annotations are generally required:
type Base1<'a>(state:'a) = class
member x.State = state
end
let myObject1 = new Base1<int>(1)
let myObject2 = new Base1<string>("1")
Known Limitation: The F# compiler is free to optimize and represent the let-bindings in anyway it deems fit. However, in this release each ``let'' binding gives rise to a field in the class. This is the main reason why we say this feature is only a ``tech-preview'' - while it is extremely useful even as it stands you have to be a little careful not to put thousands of helper (e.g. closed-form) ``let'' bindings in a critical class. In the above example, the start value is only required during initialization of the object and thus should in principle not be included as a field of the object.
Known Limitation: In this release classes with implicit constructors may not be mutually recursive.
Known Limitation: Patterns may not be used in the arguments to the constructor.
Known Limitation: The bindings are established in order. However base class constructors written in other .NET languages can in principal call virtual members prior to the complete initialization of the object. This means you should be careful about using your ``let'' bindings from override members that may be activated by base classes during base initialization. In this case the behaviour is unspecified and the 'default' or 'zero' values of some of the let bound variables may be observed.
Active patterns give a form of extensible pattern matching on abstract values. F# active patterns allow you to pattern match against .NET object values such as XML, System.Type values and LINQ Expression trees. They allow a function to give a complete decomposition of an abstract type by projecting it into a union type.
Active Decomposition. An active pattern discrimination function declares a ``view'' on a type. It is a function whose name includes surrounding (| ... |) marks. It gives a technique for automatically decomposing the values of a type when the enclosed label(s) are used as pattern discriminator(s). For example:
open Microsoft.FSharp.Math let (|Rect|) (x:complex) = Rect(x.RealPart, x.ImaginaryPart) let (|Polar|) (x:complex) = Polar(x.Magnitude , x.Phase)
These functions declare two unrelated discriminators for viewing the (abstract) type of complex numbers as tuples in rectangular and polar coordinates. Multiplication can now be expressed using either coordinate system:
let mulViaRect c1 c2 =
match c1,c2 with
| Rect(ar,ai), Rect(br,bi) -> Complex.mkRect(ar*br - ai*bi, ai*br + bi*ar)
let mulViaPolar c1 c2 =
match c1,c2 with
| Polar(r1,th1),Polar(r2,th2) -> Complex.mkPolar(r1*r2, th1+th2)
In the first case, the decomposition function (|Rect|) is run when the inputs c1 and c2 are matched.
Because Rect and Polar are simply pattern discriminators they can be used in any position where an existing pattern discriminator can be used:
let mul2 (Polar(r1,th1)) (Polar(r2,th2)) = Complex.mkPolar(r1*r2, th1+th2)
for (Polar(r,th)) in myComplexNumberList do
printf "r = %O, th = %O" r th
Active Discrimination. Active pattern discrimination functions may include multiple active pattern labels. For example, the following defines a function (|Named|Array|ByRef|Ptr|Param|) that discriminates and decomposes System.Type values into one of the five indicated cases:
open System
let (|Named|Array|ByRef|Ptr|Param|) (typ : System.Type) =
if typ.IsGenericType then Named(typ.GetGenericTypeDefinition(), typ.GetGenericArguments())
elif not typ.HasElementType then Named(typ, [| |])
elif typ.IsArray then Array(typ.GetElementType(), typ.GetArrayRank())
elif typ.IsByRef then ByRef(typ.GetElementType())
elif typ.IsPointer then Ptr(typ.GetElementType())
elif typ.IsGenericParameter then Param(typ.GenericParameterPosition, typ.GetGenericParameterConstraints())
else failwith "unexpected System.Type"
You can now use these discrimination labels in pattern matching:
let rec toString typ =
match typ with
| Named (con, args) -> "(" + con.Name + " " + String.Join(";",Array.map toString args) + ")"
| Array (arg, rank) -> "(Array" + rank.ToString() + " " + toString arg + ")"
| ByRef arg -> "(ByRef " + toString arg + ")"
| Ptr arg -> "(Ptr " + toString arg + ")"
| Param(pos,cxs) -> "(Param " + any_to_string (pos,cxs) + ")"
This is by no means the only view that could be applied to this type, but it is a useful one when performing operations that are sensitive to the presence of type variables (Param) and generic type constructors (Named).
Active Patterns in the F# Library The F# library currently only includes active patterns for a few constructs. One is the LazyList type, a cached, lazily-computed list. This allows you to pattern match on LazyList values, including nested patterns, e.g. the following code performs pairwise summation on a lazy list:
open LazyList
let rec pairReduce xs =
match xs with
| Cons (x, Cons (y,ys)) -> LazyList.consf (x+y) (fun () -> pairReduce ys)
| Cons (x, Nil ()) -> LazyList.cons x (LazyList.empty ())
| Nil () -> LazyList.empty ()
Partial Active Patterns. Partial patterns are signified by adding a |_| to the name of the discrimination function. The body of the discrimination function must return a value of type 'option'. They are most useful when dealing with repeatedly recurring queries on very "heterogeneous" data sets, i.e. data sets able to represent a large range of possible entities, but where you're often interested in focusing on a subset of the entities involved. Strings, term structures and XML are common examples. Here is an example when matching on integers:
let (|MulThree|_|) inp =
if inp % 3 = 0 then Some(inp/3) else None
let (|MulSeven|_|) inp =
if inp % 7 = 0 then Some(inp/7) else None
let example1 inp =
match 21 with
| MulThree(residue) -> printf "residue = %d!\n" residue
| MulSeven(residue) -> printf "residue = %d!\n" residue
| _ -> printf "no match!\n"
example1 777
example1 9
example1 10
example1 21
Partial patterns are by their nature incomplete and thus the benefits of completeness checking in pattern matching are almost completely lost when using these patterns.
Parameterized Active Patterns. So far all the pattern discrimination functions have taken one argument, i.e. the input being discriminated. Pattern discrimination functions may also take additional arguments that represent parameters to the pattern:
let (|Equal|_|) x y =
printf "x = %d!\n" x
if x = y then Some() else None
When used in a pattern a parameterized pattern tag may be followed by simple expressions that represent arguments, and then finally followed by the pattern being matched against, e.g.:
let example1 =
match 3 with
| Equal 4 () -> printf "3 = 4!\n"
| Equal 3 () -> printf "3 = 3!\n"
| _ -> printf "3 = ?!\n"
Note: not all expressions can be used in this position. Only identifiers, tuples, applications, lists and array expressions may be written in this position. Here is a second example. Extra parentheses can be useful to distinguish pattern parameters from the variables being bound by the pattern:
let (|Lookup|_|) x map = Map.tryfind x map
let example2 =
match Map.of_list [ "2", "Two" ; "3", "Three" ] with
| Lookup("4")(v) -> printf "4 should not be present!\n"
| Lookup("3")(v) -> printf "map(3) = %s\n" v
| Lookup("2")(v) -> printf "this should not be reached\n"
| _ -> printf "3 = ?!\n"
Values with the names of the form (| ... |) can in theory all be used as parameters, e.g.
let mapQ1 f (|P|_|) = function (P x) -> Some (f x) | _ -> None
However this is not a common technique. Our final example shows the use of a simple set of active patterns to match on the concrete structure of an XML document and extract a recursive algebra from the document:
open System.Xml
open System.Collections
open System.Collections.Generic
let Select (|P|_|) (x: #XmlNode) = [ for P y as n in x.ChildNodes -> y ]
let Select2 (|A|B|) (x: #XmlNode) = [ for (A y | B y) as n in x.ChildNodes -> y ]
let (|Elem|_|) name (inp: #XmlNode) =
if inp.Name = name then Some(inp)
else None
let (|Attr|_|) attr (inp: #XmlNode) =
match inp.Attributes.GetNamedItem(attr) with
| null -> None
| node -> Some(node.Value)
let (|Num|_|) attr inp =
match inp with
| Attr attr v -> Some (Float.of_string v)
| _ -> None
type scene =
| Sphere of float * float * float * float
| Intersect of scene list
let (|Vector|_|) = function (Num "x" x & Num "y" y & Num "z" z) -> Some(x,y,z) | _ -> None
let rec (|ShapeElem|_|) inp =
match inp with
| Elem "Sphere" (Num "r" r & Num "x" x & Num "y" y & Num "z" z) -> Some (Sphere (r,x,y,z))
| Elem "Intersect" (ShapeElems(objs)) -> Some (Intersect objs)
| _ -> None
and (|ShapeElems|) inp = Select (|ShapeElem|_|) inp
let parse inp =
match (inp :> XmlNode) with
| Elem "Scene" (ShapeElems elems) -> elems
| _ -> failwith "not a scene graph"
let inp = "<Scene>
<Intersect>
<Sphere r='2' x='1' y='0' z='0'/>
<Intersect>
<Sphere r='2' x='4' y='0' z='0'/>
<Sphere r='2' x='-3' y='0' z='0'/>
</Intersect>
<Sphere r='2' x='-2' y='1' z='0'/>
</Intersect>
</Scene>"
let doc = new XmlDocument()
doc.LoadXml(inp)
//print_endline doc.DocumentElement.Name
printf "results = %A\n" (parse doc.DocumentElement)
Signatures for Active Patterns The signature for an active discrimination function is given in terms of a function returning a Choice type:
val (|Cons|Nil|) : 'a llist -> Choice<('a * 'a llist),unit>
Notes: Some obvious issues with using active patterns in languages with side effects - how many times are discrimination functions executed? The specification used for F# is that "if pattern matching requires that an active discrimination function be run on a given input, then the pattern matching apparatus is free to run that function on the same input as many times as it wishes". In the presence of active patterns, rules of patterns are searched exhaustively on a left-to-right, top-to-bottom basis. We have chosen this semantics partly because we want to strongly discourage discriminator functions with side effects, in much the same way that side effects are strongly discouraged in code that implements the C# and F# property notations.
Known Limitation: Individual active pattern discrimination functions may decompose using at most 7 labels. Multiple partial active patterns can be used instead. It is planned that this limitation will be lifted in the next release.
Known Limitation: Choice types of size greater than 7 are not implemented in this release.
Much of this work was done by Gregory Neverov in the summer of 2006.
Methods can now be used as first class values without eta-expansion. Context-sensitive type information is used to resolve overloading. For example:
open System.IO
let data1 = List.map File.ReadAllLines ["a.txt"; "b.txt"]
If applied to arguments methods must still be applied to a syntactic tuple of arguments where the number of elements in the tuple is the same as the numebr of arguments expected by the method.
This long-standing problem has now been fixed. This only applies if the type arguments follow immediately after a leading constructor without spaces, e.g. C<D<int>> not C <D <int>>.
Until now, F# followed OCaml and give "comma" in parenthesized tupled patterns higher precedence than type constraints. This has changed. Thus we would previously disallow
let f (samplefreq:int64, s:int64)
and previously parse
let f (samplefreq, s : int64)
as
let f ((samplefreq, s) : int64)
(leading to a type error). We are changing this behaviour for parenthesized patterns, and now
let f (samplefreq:int64, s:int64)
will be accepted and parsed in the same way as
let f ((samplefreq:int64), (s:int64))
and the following current code will almost certainly give an error
let f (samplefreq, s:int64*int64)
since it is now parsed as
let f (samplefreq, (s:int64*int64))
Technically speaking this is a breaking change, though we have encountered only one example of user code affected by this. The readability of the user code was massively improved after taking the above change into account, hence in the balance we have decided the improvement to the language is more important in the long term. In all cases there are still reasonable and simple ways to ensure your code cross compiles with OCaml if necessary.
StructLayout, FieldOffset etc. attributes now supported for C interoperability.
F# Lists support IEnumerable/seq. In previous versions the F# list type was not compatible with the .NET IEnumerable<'a> type, which is called seq<'a> in F#. This was because null was used as a representation for lists. This has now been changed. See further discussion below.
Normalization of class and interface constraints. When constraints are used extensively situations can arise where a single type parameter can be constrained by multiple related constraints. For example,
let f1 (x : #seq<('a * 'b)>) = ()
let f2 (x : #seq<('a * 'b * 'c)>) = ()
let g x = f1 x; f2 x
Here g is constrained to operate over both sequences of pairs and sequences of triples. While it is in principle possible for a .NET type to implement both of these interfaces, in practice this is never used. In prior versions F# was not normalizing such constraints to ensure that any particular nominal type occurred at only one instantiation for a given collection of constraints. This has now been added to the language specification and has been implemented. This gives earlier detection of errors involving incompatible constraints and ensures that multiple related constraints never need to be listed in signatures should one constraint subsume another.
Lexer literals 32u and 32uL now accepted. These are unsigned 32-bit and 64-bit integers.
new now optional. The construct new Type(args) can now optionally be replaced by simply Type(args). This applies when no ambiguity exists as to which type is being constructed and where no type instantiation is given. However, a warning is given if the type supports the IDisposable interface. For these constructs it is felt that the potential use of resources by the construct means that new Type(args) is much clearer
More F# keywords accepted as identifiers in --ml-compatibility-mode.
Enum values now support the ||| and &&& operators. This applies when the Enum type is marked with the FlagsAttribute attribute.
Extend overload inference for (+), (*) etc. to allow return types to propagate to the overload resolution. This reduces the need for type annotations in many circumstances.
Explicit type applications at member calls and path lookups. You can now explicitly apply type arguments in lookups, e.g.
let x = Map.empty<string,int>
// The next is from the Microsoft Research 'Joins' library
let subscribe = Asynchronous.CreateChannel<EventSink<'b>>(client.Join)
Flexible printf integer and floating point format enhancements. %d, %u, %i, %x and %o formats can now be used with any integer types. Many of the other format specifiers have now been deprecated or marked 'for OCaml compatibility'. %f and %g and other floating point specifiers can now be used with both Single and Double precision numbers. The use of the format specifiers is still checked at compile time to ensure static type correctness.
Printf format enhancements. * can now be used as a width and/or precision specifier. This corresponds to a 'computed' specifier and an extra integer argument giving the width is required in the argument list for the specifier. For example:
sprintf "|%*s|%*s|" 10 "hello" 8 "world" ;;
sprintf "|%*s|%*s|" 12 "hello" 6 "world" ;;
Give:
val it : string = "| hello| world|"
val it : string = "| hello| world|"
OCaml Compatibility Warnings. Several constructs in the F# libraries are only present for OCaml compatibility. While OCaml compatibility is a key goal of the language, we have also become aware that users coming to F# from a non-OCaml background get very confused by the presence of 'multiple ways of doing things' and are bemused when the explanation is that 'we need that for OCaml compatibility, but we don't really recommend using it'. As such, we've begun marking some constructs as 'not recommended for use unless you need it for OCaml compativility.' In this relesae this applies to &
Null no longer used as a representation for F# list values. We made this change to allow the F# "List" type to implement the IEnumerable/seq interface. This means we are dropping null as a representation for F# list values (null values cannot implement interfaces), and are indeed abandoning the use of "null" for option values and where an attribute is explicitly attached to a discriminated union with a nullary discriminator, e.g.
[<CompilationRepresentation(CompilationRepresentationFlags.PermitNull)>]
type HashChain<'a,'b> =
| EmptyChain // note: representation is "null"
| Chain of { Key: 'a;
Value: 'b;
mutable Rest: ('a,'b) HashChain }
This is thus a breaking change to the language spec, which previously specified different conditions where "null" is used. Using non-null values for the empty list comes with a small performance penalty for list-intensive code (around 10%), but little overall space penalty. Array, loop, matrix, vector, hashtable, set, sequence and map-dominated code is not affected, and since these are the primary high-performance data structures in F# we have decided that the language clarity of having "list" implement "IEnumerable" is more important than the performance considerations for this case.
This change does mean that C# samples that search for "null" as the empty list will no longer function correctly. They should instead use the IsNil property (now a true instance property) or switch on tags, e.g. as follows:
List<int> x = List>int>.Cons(3, (List<int>.Nil));
switch (x.Tag)
{
case List<int>.tag_Cons:
Console.WriteLine("Cons({0},{1})", x.Head, x.Tail);
break;
case List<int>.tag_Nil:
Console.WriteLine("[]");
break;
}
Representation of the LazyList type is now private. Active patterns can now be used to match on values of type LazyList.
Sparse matrix implementation. See Math.Matrix.init_sparse. You can now create and multiply matrices up to size ~10M x 10M, as long as most elements are zero.
Updated quotations API. The quotations API has been substantially simplified through the use of active patterns. Code using the old quotations API directly will no longer compile but is easy to update. Contact the F# team if you need help you with this.
The F# map type now supports equality and comparison over entire map values. In particular Map<k,v> implements IDictionary<'k,'v>, IEnumerable<KeyValuePair<k,v>> and IComparable. Note: this is a breaking change. In 1.1.13.8 Map supported IEnumerable<'k,'v>. However, this meant that the type could never also support IDictionary. We have decided to make this breeaking change immediately since it is obviously correct for Map values to support IDictionary.
Interactive pretty-printer for IDictionary values.
Pervasive values cleaned up. Many values that are now "officially" part of Microsoft.FSharp.Core.Operators were still being redefined in Microsoft.FSharp.Compatibility.OCaml.Pervasives. These have now been removed from that module. The path Microsoft.FSharp.Compatibility.OCaml.Pervasives is still opened be default but contains very few values.
Overloading of math operations like sin, cos, abs etc. These are now overloaded over basic types, e.g. abs on all floating point and signed types, and sin on the floating point types. They also work with any type supporting corresponding static members, e.g. types supporting the static member Sin or Abs.
Choice types.
Choice types up to size 7 are defined in the F# library and can be used for general purpose programming.
type Choice<'a,'b> =
| Choice2_1 of 'a
| Choice2_2 of 'b
type Choice<'a,'b,'c> =
| Choice3_1 of 'a
| Choice3_2 of 'b
| Choice3_3 of 'c
etc.
F# Reflection library additions to pre-compute faster accessors. The following functions have been added to thee reflection library:
/// Precompute a function for reading a particular field from a record.
val GetRecordFieldReader : Type * field:string -> (obj -> obj)
/// Precompute a function for reading all the fields from a record.
val GetRecordReader : Type -> (obj -> obj array)
/// Precompute a function for reading an integer representing the discriminant tag of a sum type.
val GetSumTagReader : Type -> (obj -> int)
/// Precompute a function for reading all the fields for a particular discriminant tag of a sum type
val GetSumRecordReader : Type * int -> (obj -> obj array)
/// Precompute a function for reading the values of a particular tuple type
val GetTupleReader : Type -> (obj -> obj array)
/// Precompute a function for constructing a record value.
val GetRecordConstructor : Type -> (obj array -> obj)
/// Precompute a function for constructing a discriminated union value for a particular tag.
val GetSumConstructor : Type * tag:int -> (obj array -> obj)
/// Precompute a function for reading the values of a particular tuple type
val GetTupleConstructor : Type -> (obj array -> obj)
/// Precompute a pair of functions for converting between integer discriminant tags
/// the names of the discriminants for the given sum type. The number of tags is also
/// returned.
val GetSumTagConverters : Type -> int * (int -> string) * (string -> int)
F# Reflection library no longer reports F# class types as records. This was a mistake from the early implementation of the reflection library.
Deprecated llist functions. Deprecated some LazyList functions.
LexBuffer.AsNewLinePos() renamed to LexBuffer.NextLine. The old name has been deprecated.
List.concat now accepts a sequence. This brings it into line with Seq.concat.
Notation for complex/matrix/vector/set/dict notation at the top level The following functions are now defined in Microsoft.FSharp.Core.Pervasives and are available for use in the top level:
val complex : float -> float -> complex
val matrix : #seq< #seq<float> > -> matrix
val vector : #seq<float> -> vector
val rowvec : #seq<float> -> rowvec
val set : #seq<'a> -> Set<'a>
val dict : #seq<'a * 'b> -> System.Collections.Generic.IDictionary <'a,'b>
Intelisense on more expressions, including method calls.
Visual Studio ToolsOptionsPage for FSI startup arguments
Visual Studio fixes to allow "ReadLine" calls when using VFSI
Bug fixes to permit printf on binary channels (Reported by Richard Mortier - thanks Mort!) Fixed mod_float to be ocaml compatible (reported by Andrew Phillips - thanks Andrew!) Bug 858: Function types not erased from type constraints on typars of methods or types. Bug 856: no more inlining of protected calls, e.g. out of class defn. Bug 851. Removed ``0 from non-generic member names in xmldoc. Fix base calls to F# abstract members (reported by Ralf Herbrich and Phil Trelford - thanks guys!) XMLDOC changes (suggested by Andyman - thanks Andy) Permit access to nested generic classes (reported by Claudio Russo - thanks Claudio!) Fixed generation of unverifiable code when using the "property bag" syntax with properties of type 'object' and values that are value types, a bug reported by Julien Ortin Bug 880: Type definition bug (reported by Laurent on hubfs - thanks Laurent!) Bug 881: fsi needs a way to specify command line arguments (reported by Dmitry - thanks Dmitry!) Bug 882: StartupCode and PrivateImplemntationDetails types should be private (reported by Robert Pickering - thanks Robert!) Bug 883: Add check for phantom and permuting type abbreviations causing potential problems in type inference Bug 884: Instrumented profiling doesn't work on XP or Vista Bug 889: Excessive 'base' variable usage checks (reported by Tomas Petricek - thanks Tomas!)
Range Comprehensions. e.g. {1 .. 3} and {0 .. 2 .. 10}. The both are IEnumerable<int>, generating [1;2;3] and [0;2;4;6;8;10] respectively, though the operator is overloaded and can be used with other types such as characters, bigint etc. Uses of this syntax correspond to overloaded oeprators (..) and (.. ..) respectively.
IEnumerable, Array and List Comprehensions.
It's been a long time in coming, but yes, finally a version of ML with comprehension syntax built-in right into the language. But what are comprehensions? We all know that aggregate operators are a very powerful way of working with lists, maps, sets and IEnumerable values. However, an even more convenient syntax is also provided for specifying the class of IEnumerable values that can be built using operations such as choose, map, filter, concat. This syntax is compiled down to the use of the aggregate operators above and is called the comprehension syntax. It can also be used to specify the shapes of lists and arrays.
Comprehensions using for
The simplest form of a comprehension is { for ... in ... -> result }, where -> should be read as 'yield'. This is simply a shorthand way of writing IEnumerable.map. As with range comprehensions the parentheses are not optional when using this syntax to generate IEnumerable values. For example, we can generated an enumeration of numbers and their squares as follows:
> let squares = { for i in 0 .. 10 -> i,i*i} ;;
val squares : IEnumerable<int * int> = [ (0,0); (1,1); (2,4); (3,9); ... ]
The more complete form of this construct is (for pattern in enumerable -> expression). The pattern allows us to decompose the values yielded by the input enumerable. For example, if the enumerable yields tuples we can decompose it as follows:
> let cubes = { for i,isquared in squares -> i,isquared,i*isquared };;
val range : IEnumerable<int> = [ (0,0,0); (1,1,1); (2,4,8); (3,9,27); ... ]
The input enumerable may be a list value, any IEnumerable, or a value of any type supporting a GetEnumerator method (some important types from the .NET libraries support this method without directly supporting the IEnumerable construct). Below is an example where the input is a list of options. If the pattern fails to match the element of the enumerable is skipped and no result is yielded.
> { for Some(nm) in [ Some("James"); None; Some("John") ] -> nm.Length };;
val it : IEnumerable<int> = [ 5; 4 ]
An enumerable comprehension always begins with for … in …, but additional clauses can also be given, each of which may be one of:
Secondary iterations iterate in two dimensions. For example, the following function returns all the (row,column) pairs of the lower left triangle of a square matrix, including the diagonal:
let lowerTriangleCoordinates n =
{ for row in 0 .. n
for col in 0 .. row
-> (row,col) }
Filters allow us to skip elements, e.g. the following computes the coordinates of a matrix where the sum is even (i.e. a checkerboard):
let checkerboardCoordinates n =
{ for row in 0 .. n
for col in 0 .. n
when row+col % 2 = 0
-> (row,col) }
Let and match clauses in comprehensions allow us to compute intermediary results and filter results through failing matches. For example, the following code gets the creation time and last access time for each file in a directory.
let fileInfo dir =
{ for file in Directory.GetFiles(dir)
let creationTime = File.GetCreationTime(file)
let lastAccessTime = File.GetLastAccessTime(file)
-> (file,creationTime,lastAccessTime) }
The final yield of a comprehension may be another IEnumerable, signified through the use of the ->> symbol as the yield. The following sample shows how to redefine the allFiles function from the previous section using comprehension syntax.
let rec allFiles dir =
IEnumerable.append
(for file in Directory.GetFiles(dir) -> file)
(for subdir in Directory.GetDirectories subdir ->> allFiles subdir)
Using Comprehension Syntax to Specify Lists and Arrays The comprehension syntax for ranges and generated enumerables can also be used to build list and array values. The syntax is identical except the surrounding parentheses are replaced by the usual [ ] for lists and [| |] for arrays. We discuss arrays in more detail in Chapter 3.
> let squaresList = [ for i in 0 .. 3 -> i,i*i ];;
val squaresList : (int * int) list = [ (0,0); (1,1); (2,4); (3,9) ]
> let squaresArray = [| for i in 0 .. 3 -> i,i*i |];;
val squaresArray : (int * int) list = [ (0,0); (1,1); (2,4); (3,9) ]
Named arguments and Property-setters-masquerading-as-named-arguments
.Named items in object-model member calls are arguments of the form id=expr. Named items have been used for some time in the attribute syntax. These are now given two meanings in constructor calls and regular member calls:
new MenuItem(text="Hello") -- this is a named argument
new Form(Width=300) -- this looks like a named argument, and feels like one, but
-- is actually a "property set" performed after the object has been constructed.
We've been planning this feature for a while, and it is also very close to the C# 3.0 syntax for property setters. Example:
open System
open System.IO
open System.Text
open System.Drawing
open System.Windows.Forms
let clickMenuItem = new MenuItem(text = "hello",onClick=new EventHandler(fun _ evArgs -> printf "click!\n"))
let clickMenuItem2 = new MenuItem(text = "hello",onClick=(fun _ evArgs -> printf "click!\n"))
let rec recursiveClickMenuItem = new MenuItem(text = "hello",onClick=(fun _ evArgs -> printf "self disabling\n"; recursiveClickMenuItem.Enabled <- false))
let form = new Form(Width=500, Height=420,Visible=true,TopMost=true,
FormBorderStyle=FormBorderStyle.FixedSingle,
Text="99 bottles of beer presented in F#" )
let rb = new RichTextBox(Size=new Size(480, 350),
Location=new Point(5, 5))
form.Controls.Add(rb)
let btnClose = new Button(Location=new Point(408, 360),Text = "Close")
btnClose.Click.Add (fun _ -> f4.Close())
f4.Controls.Add(btnClose)
Named arguments cannot be used with let-bound functions.
Fast 'for' loops for Range Comprehensions. Constructs of the form for i in n .. m do ... done have been optimized to ensure they also result in for-loops that are compiled and execute as efficiently as the 'simple' integer for-loops for i = n to m do ... done
Custom Attributes on parameters.
Easier object construction. In particular, then blocks in constructors may now reference the variables bound prior to the object construction..
override now required when implementing abstract and virtual members..
Structs and Enums implemented. See the informal language specification.
New switch --generate-filter-blocks. Generate filter blocks to allow first-chance exception catching for non-matching exceptions. Not on by default because some CLI implementations have problems with filter blocks.
C-style syntax for native functions. Writing PInvoke signatures in F# has been a little awkward since you have to reformat the signature in entirely tedious and boring ways. You can now just use the C syntax for a native signature, e.g.
/// LAPACK/BLAS primitive matrix/matrix multiply routine
[<DllImport(@"blas.dll",EntryPoint="dgemm_")>]
extern void DoubleMatrixMultiply_(char* transa, char* transb, int* m, int* n, int *k,
double* alpha, double* A, int* lda,double* B, int* ldb,
double* beta,
double* C, int* ldc);
/// C := alpha*op( A )*op( B ) + beta*C
let DoubleMatrixMultiply trans alpha (A: FortranMatrix<double>) (B: FortranMatrix<double>) beta (C: FortranMatrix<double>) =
// Mutable is needed because F# only lets you take pointers to mutable values
let mutable trans = trans // nb. unchanged on exit
let mutable beta = beta
let mutable alpha = alpha
let mutable m = A.NumCols
let mutable n = B.NumRows
let mutable k = A.NumRows
let mutable lda = A.NumCols
// Call the BLAS/LAPACK routine
DoubleMatrixMultiply_(&&trans, &&trans, &&m, &&n, &&k, &&alpha, A.Ptr, &&lda, B.Ptr, &&k, &&beta, C.Ptr, &&m)
Pattern matching on arrays. Several people have requested this OCaml feature.
Substantial tightening of #light rules. The #light syntax option was letting through many constructs that were clearly badly formatted. Extra tokens are now inserted based on indentation and column position to ensure that code conforms to the requirements of #light.
Reliable compiled names for parameters.
member syntax for object expressions. It is convenient and regular to support the member syntax used in class expressions in object expressions as well, as this allows you to move member bindings to and from object expressions without any syntactic adjustments, e.g.
{ new session with
member x.Interrupt() = interrupt()
member x.Input = inW
member x.Output = IEvent.filter nonNull outE
member x.Error = IEvent.filter nonNull errE
member x.Exited = exitedE
member x.Alive = not proc.HasExited
member x.Kill() = killProcess proc
member x.Completions(s) = completions(s:string) }
A namespace can now contain a module and type of the same name. An attribute annotation is required - see the F# library for examples (e.g. math/complex.fs). Greatly simplifies F# library design and implementation.
Physical Library Reorganization. After an extensive design review the mapping of F# modules to .NET namespaces and module names has been extensively revised. We've gone to great pains to ensure that almost no F# code will actually break because of this change: Most F# code does not refer to module by their long paths, and even for the code that does we've left lots of "deprecated" warnings in place and the compiler will generally ensure that old code works and will give advice about the new location of a construct so you can update your code at your own pace.
Why did we do this? Above all because the new mapping is very easy to explain, unlike the old one. This is very important as we come to write the F# books, and to expand the F# library over time, adn to set a good standard in library design practice with F#. Furthermore this is a really important step toward clarifying which parts of the previous library are "core" F# and which parts only exist for compatibility with OCaml.
The previous library mapping sort of grew over time: the split between FSLIB and MLLIB was never very clear, and there were just a whole heap of modules cluttered under MLLib, some of them very important indeed (e.g. List and even some things that had nothing to do with OCaml such as IEnumerable). The reorganized library design is, I think you'll agree, much cleaner, and much more along the lines of the .NET design.
The namespace layout is as follows. As part of the redesign we have added an attribute that allows a module and a type to co-exist in the same namespace.
Top level namespaces:
fslib.dll:
Microsoft.FSharp.Core
Microsoft.FSharp.Collections
Microsoft.FSharp.Compatibility
Microsoft.FSharp.Control
Microsoft.FSharp.Math
Microsoft.FSharp.NativeInterop
Microsoft.FSharp.Quotations
Microsoft.FSharp.Reflection
Microsoft.FSharp.Text
Microsoft.FSharp.Experimental
Microsoft.FSharp.Tools.FsLex
Microsoft.FSharp.Tools.FsYacc
mllib.dll:
Microsoft.FSharp.Compatibility.OCaml
Opened by default:
Microsoft.FSharp.Core
Microsoft.FSharp.Core.Operators
Microsoft.FSharp.Core.LanguagePrimitives
Microsoft.FSharp.Collections
Microsoft.FSharp.Control
Microsoft.FSharp.Text
Microsoft.FSharp.Compatibility.OCaml
More detail:
Microsoft.FSharp.Core
type Ref
type Option
module Operators
module LanguagePrimitives
module {Byte,SByte,Int16,UInt16,Int32,UInt32,Int64,UInt64,Float,Float32,String,Char}
module Ref
module Option
module Enum
Microsoft.FSharp.Collections
type List
type SetQ, MapQ, HashSetQ
type LazyList
module {Array,Array2,Array3}
module List
module IEnumerable
module LazyList
module Map
module Set
module ResizeArray
module HashIdentity
module ComparisonIdentity
Microsoft.FSharp.Control
type IEvent
type IDelegateEvent
type ICompatEvent
type Lazy
module IEvent
module Lazy
Microsoft.FSharp.Math
type BigInt
type BigNum
type Complex
type Matrix<_>
type Vector<_>
type RowVector<_>
module Matrix
module Matrix.Generic
module Vector
module Vector.Generic
module Notation
module BigInt
module BigNum
module Complex
module GlobalAssociations
Microsoft.FSharp.Experimental
type IPattern
Microsoft.FSharp.NativeInterop
module NativePtr
type CMatrix
type FortranMatrix
type NativeArray
type NativeArray2
type PinnedArray
type PinnedArray2
Microsoft.FSharp.Quotations
module Raw
module Typed
Microsoft.FSharp.Text
module Printf
Microsoft.FSharp.Text.StructuredFormat
type IFormattable
type Layout
module LayoutOps
Microsoft.FSharp.Text.Compatibility
module CompatArray
module CompatMatrix
Microsoft.FSharp.Compatibility.OCaml
[Arg], [Big_int], [Buffer], [Bytearray], [Filename], [Hashtbl], [Lexing], [Num], [Obj], [Parsing], [Pervasives], [Printexc], [Sys]
Note that this has:
Seq as shorthand for IEnumerable. One of my friends said 'I fall asleep reading IEnumerable'. So we've introduced the type abbreviation
type 'a seq = IEnumerable<'a>
and the module Seq. The latter is identical to IEnumerable except that you can write Seq.empty instead of IEnumerable.empty(). In the long term we may deprecate the module IEnumerable, but it is not yet marked deprecated.
New library functions. truncate and pairwise added to IEnumerable/Seq, pairwise added to IEvent. The function truncate places a maximum on the number of elements returned by the sequence. Pairwise returns a sliding window on the enumerable, i.e. elements (0,1), (1,2), (2,3) etc. For events pairwise does nothing on the first firing of the event and then returns (prior,current) pairs for each subsequent firing.
Optional Safer Collections. A recurring theme in the design of collection classes (in particular immutable ones such as Map and Set) is the desire to use the type system to track information about the comparison and hashing functions involved. Until now F# offered no way to be 'strict' about tracking this information. While this lack of 'strong typing' is standard for .NET collections, many F# and OCaml programmers tend to have a higher standard, where the type system can be used to ensure that values created using one comparison ordering aren't confused with values created with another ordering. This applies especially to Set values which support important binary operations such as union and difference. As such we've now adopted an (optional) type-tagging technique to ensure that users who want to can adopt this level of safety. Existing code will continue to work as normal. However, the Microsoft.FSharp.Collections.Tagged namespace now contains types that carry an extra type parameter, related to the comparison/hash function.
The changes mean you may use types like the following:
Tagged.Set<'a,'compareTag> -- indicates a set using some kind of comparison
or Tagged.Set > -- indicates a set using structural comparison (identical to Set)
or Tagged.HashSet > -- indicates a hash set using reference comparison
Here the tag variables just mark a lack of information about the comparison function.
type SetUntagged<'a> -- a set using some user-specified comparison function that we don't know anything more about
type MapUntagged<'a> -- a map using some user-specified comparison function that we don't know anything more about
type HashSetUntagged<'a> -- a hash set using some user-specified comparison function that we don't know anything more about
Custom tracked comparison tags can be created by defining new class to act as the tag, or by using the Set.MakeTaggged, Map.MakeTagged and Hashtbl.MakeTagged functions.
New Library Modules. ResizeArray - this module is the F# name for System.Collections.Generic.List.
Minor changes to NativeInterop namespace based on user feedback.. NativeArray.Create now called NativeArray.FromPtr. NativeTranspose members on CMatrix and FortranMatrix. New types PinnedArray and PinnedArray2.
UnverifiableAttribute. This attribute can be used to mark code that is potentially unverifiable.
Visual Studio: Goto defintition now works across projects and into the F# library.
Resources on the command line.resx resources may now be added to the F# command-line compiler and as files in the Visual Studio mode.
Cleanup of Parser and Lexer engine APIs. Old API functions deprecated. The two namespaces under Microsoft.FSharp.Tools contain the official F# APIs for using the parsing and lexing tools.
Library addition: Matrix.copy, Vector.copy, Array.copy.
Library addition: F# Immutable Map values now support the map.[i] syntax.
Library addition: Optionally safer collection types. F# Map, Set, HashSet and Hashtbl (HashMultiMap) values now use underlying SetQ etc. types that carry extra type annotation "qualifications" about the comparison and hashing functions assocaited with the collection.
Compiled names for modules now include a "Module" suffix if a RenamedModule attribute is given. Whenever you define a public module in F# code with this attribute, the compiled name of that module now has a "Module" suffix added. This is never visible from F# code unless you use reflection. This allows F# namespaces to contain a module and type of the same name, e.g. a module called List and a type called List. The rules of the F# language disambiguate between these automatically without the Module prefix ever being visible.
Deprecated Microsoft.FSharp.Idioms. Pretty much all the useful operations from this module are now in Microsoft.FSharp.Core.Operators, which is opened by default, or there are other reasonable choices, e.g. just use using instead of Idioms.using.
Removal of some long-deprecated library functions. Idioms.foreachG, List.transform etc.
Simpler OCaml-compatible Channel abstraction. in_channel and out_channel now map to TextReader/Writer, with a hidden BinaryReader/Writer. This leads to more generally usable printf and fprintf functions, and in particular removes the final dependency of the "true" F# library on the OCaml-compatible channel abstraction. This makes "printf" much easier to understand and explain, as it can be explained directly in terms of System.Console.Out.
printf and fprintf functions can now be used in conjunction with any TextWriter streams.
Properties removed from in_channel and out_channel. e.g. Stream, StreamReader, BinaryReader. Necessary in order to simplify the implementation and mapping of the channel abstraction above. Use the functions in the InChannel and OutChannel modules instead.
F#-specific functions and operator definitions removed from Pervasives and now in Microsoft.FSharp.Core.Operators.
New LAPACK sample..
Improved speed of bracket matching in Visual Studio mode..
F# library is now free of C# code. We had a few dangling bits of C# code in the library implementation, but they are now gone.
Remove renaming of F# library from static linking process. The --standalone flag used to rename Microsoft.FSharpp to FSharp, for no particularly good reason. This has been stopped.
F# console now implements TAB completion and history.
752 F# Compiler object model members have lost their argument names 751 F# Compiler type variable names and numbers are all messed up they are the inference type variable names) 724 F# Language permit accurate names on arguments, especially for OO code (reported by Robert Pickering - thanks Robert!) 715 F# Compiler RunClassConstructor XNA on xbox 360 748 F# Compiler unicode chars not supported with FSI 652 F# Samples Samples101 does not compile resources 719 F# Compiler type checking reproted to differ with fscp10.exe 706 F# Compiler custom attributes for fields 754 F# Compiler support "out" parameter attributes 756 F# Language permit attributes on parameters 765 F# Compiler System.Runtime.InteropServices.Out on argument parameters does not generate an out parameter 737 F# Compiler nested constructs (constants) lead to huge memory and time requirements 464 F# Compiler lists, arrays, format strings not reporting error at right location 658 F# Compiler Are we checking generalization conditions when implementing abstract or virtual generic methods (making type variables rigid is not enough! Must check we can generalize) 488 F# Compiler "interface method unimplemented" errors (checked at end of scope) give a range that extends over the entire file 725 F# Library stabilize LanguageServices API 767 F# Library Map type missing a get_Item property for .[] notation 766 F# Library Map module still missing to_list, of_list, to_IEnumerable etc. 774 F# Language #light permitting several obviously incorrectly formatted expression forms 771 F# VS Mode Cant right click and go to definition through to F# library 759 F# Documentation spec and examples needed for high precedence application 508 F# VS Mode Visual Studio mode does not report missing files and allows "builds" when files don't exist 661 F# VS Mode GoTo Definition doesn't work for F# library definitions 772 F# Language pattern matching on arrays requested 770 F# VS Mode we're not showing XML help for .NET enumeration values 662 F# Language Support comprehensions 763 F# VS Mode Can't right click go to defenition 776 F# Compiler uppercase member warning 778 F# Compiler F# does not support C#-style \x1F characters 782 F# Interactive lexer errors upset F# Interactive line error reporting 781 F# Compiler use of "+" with "string" types doesn't detect that only reasonable return type is "string" 780 F# Compiler reasonable indentation of a "with" record update gives a #light syntax error 779 F# Compiler try/finally on a single line gives a #light error 760 F# Compiler #light problems reported by Mort 762 F# VS Mode F# VS mode pauses when scrolling pass a bracket-matching character 736 F# Interactive AutoExpand is missing (except in the Visual Studio PlugIn version where it is mapped to TAB) 798 F# VS Mode WINEXE option not available in Visual Studo 799 F# VS Mode properties box looks kind of messed up in Visual Studio 800 F# Compiler F# exceptions should be filtering rather than catching and rethrowing (Reported by rjblack - thanks Richard!) 720 F# Tools fslex doesn't support \xHH 819 F# Language support __SOURCE_DIRECTORY__ 820 F# Library support more instances of overloaded multiplication operator on Matrix, Vector and RowVector 821 F# Library Floating point numbers such as 1.000000000001 get printed by auto-formatting as just "1" 822 F# Library Redesign the NativeInterop module based on feedback from users and recent LAPACK work 823 F# Library Add String.for_all and String.exists 827 F# Samples Add LAPACK sample to distribution 828 F# VS Mode Double check bracket matching is still working in Visual Studio mode 777 F# Compiler lowercase static member gives an error 815 F# VS Mode Type parameter contraint errors given against wrong file 812 F# Compiler Red squiggly sprinkled randomly like confetti 806 F# Compiler #light;; is not an interaction in fsi 818 F# Language static property is interpretted as a method 802 F# Library Revamp the module locations of the F# Library 833 F# Language some long name lookups of constructors and fields not being handled correctly 835 F# Library set and map values with different comparison functions are too easy to confuse 809 F# VS Mode Installer fails on VS2003 machine - reported by Jan Sacha 837 F# VS Mode another unicode bug using VFSI 836 F# Compiler Jon Harrop's for-loop-in-constructor bug 795 F# VS Mode intellisense not working in #light code 803 F# Language cannot write a comprehension binding continaining "let" on a single line in the hardwhite syntax
Disabled generation of tailcalls on Mono and .NET 1.0. A bug has been reported in Mono's implementation of tailcalls. The fscp10.exe compiler is for use on Mono and we have adjusted this to be a binary that does not itself either make use of nor generate tailcalls (except for immediately recursive functions, where tailcalls become branches). Additionally, the fslib10.dll and mllib10.dll libraries are used when running code on Mono and have been built with tailcall generation disabled. This situation will remain until Mono's implementation of tailcalls is completely robust.
Minor library additions. Added Array.tryfind
Bug fixes.
692 18/09/2006 F# Compiler FSI fails when creating delegate type
694 19/09/2006 F# Interactive delegate invoke (wrong arity?) falls over in FSI
709 20/09/2006 F# Compiler hash on arrays do not detect numberRemaining=0, stack-overflow on circular datastructures
712 25/09/2006 F# Compiler :? error with value types in expr
710 29/09/2006 F# Compiler offside1, offside2 etc.
703 29/09/2006 F# Library hashtable add throwing stack overflow exception
708 30/09/2006 F# Compiler #light interactive bug from Rob
704 30/09/2006 F# Compiler fsi --full-help generates same output as fsc --full-help
716 30/09/2006 F# Visual Studio Intellisense does not work inside ill-formed lists (thanks to Ralf Herbrich)
723 30/09/2006 F# Compiler offside problem (reported by Dennis Hamilton - thanks Dennis!)
728 30/09/2006 F# Library UInt64.to_float and UInt32.to_float sometimes return incorrect results (reported by Dave Wecker - thanks Dave!)
729 30/09/2006 F# Compiler --help and --full-help not showing anything for fsc.exe
738 02/10/2006 F# Library Hashing big integers raises an exception
High Precedence Application. A long-standing problem with the F# syntax is that method applications followed by property/field lookups such as obj.Method1(args).Method2(args).Property1.field2 have had to be written with very non-intuitive parentheses, e.g. ((obj.Method1(args)).Method2(args)).Property1.field2.
To fix this, this release incorporates a minor change in the F# syntax (with and with the #light syntax option). In particular, applications id(args) now have higher precedence (i.e. bind more tightly) than the dot-notation. This only applies when no spaces or other whitespace separate the identifier and the arguments.
--no-tailcalls now binary-format neutral. In prior versions the --no-tailcalls option was a global setting, hence requiring the use of special libraries that had tailcalls removed. Systems such as Mono now correctly support the .tail IL annotation and so a global version of this option is no longer required. The option is still supported, but will only affect the code being generated in the assembly currently being compiled and will not result in the selection of different runtime libraries.
Revert change to operator overloading made in 1.1.11.12.2 release.
The change to operator overloading in 1.1.11.12.2 was incorrect, as it disallows the use of legitimate .NET overloads. The upshot is that the basic operators now have the following signatures. These indicate that the two argument types and the return type may indeed all be different, and knowledge of the return type and the second argument type are not sufficient to resolve the overloading - a type annotation may be required to give the precise type of the first argument.
val inline (+) : ^a -> ^b -> ^c when ^a : (static member (+) : ^a * ^b -> ^c) val inline (-) : ^a -> ^b -> ^c when ^a : (static member (-) : ^a * ^b -> ^c) val inline ( * ): ^a -> ^b -> ^c when ^a : (static member ( * ) : ^a * ^b -> ^c) val inline (/) : ^a -> ^b -> ^c when ^a : (static member (/) : ^a * ^b -> ^c) val inline (%) : ^a -> ^b -> ^c when ^a : (static member (%) : ^a * ^b -> ^c) val inline (mod): ^a -> ^b -> ^c when ^a : (static member (%) : ^a * ^b -> ^c)
We are considering a design revision which would allow more restricted specifications of permitted overloads, but are currently erring on the side of generality, even at the cost of occasional additional type annotations.
Bug fixes.
700 F# Language undentation should be allowed when () and {} immediately follow an "="
695 F# Compiler record building construct - not checking records only not classes
702 F# Compiler unbound type variable problems for inner constrained polymorphic definitions
Lightweight syntax option. Are you sick of writing in? The #light option makes the use of certain keywords such as in optional by using indentation. See the informal language specification for details, as well as the ConcurrentLife sample and the Samples101 tutorial. Enable using #light.
First experimental cut at the Active Patterns. More details to follow on Don Syme's blog.
More modules in MLLib. Modules UInt8, Int8, Int16, UInt16 have been added.
More collections in Microsoft.FSharp.Collections. The Set and Map collections are now defined as object-oriented abstractions in Microsoft.FSharp.Collections. The corresponding MLLib modules are defined in terms of these OO abstractions.
Removed deprecated Stream module from MLLib. Minor updates to the LazyList module as a result.
--gnu-style-errors flag no longer accepts spurious integer argument.
Slight modification to overloading for +,*,/,mod.
In version 1.1.11 a slight change was made to the default overloaded signature for - operator to allow the return type to be unassociated to the two input types, as is required for overloading on the System.DateTime subtraction operator. This change was mistakenly applied to other operators, resulting in situations where type inference would report unexpected inference errors for fairly straight-forward floating point code.
Bug fixes.
--- F# Compiler -R clobbers DLLs with PDBs
--- F# Compiler no properties being generated for top level values
605 F# Visual Studio VFSI scroll to caret does not always show input position
643 F# Compiler internal warning when unpickling override of abstract member
655 F# Compiler interface implementing methods marked private but included in modul_typ
656 F# Compiler Runtime exception TypeLoadException method 'Specialize'... tried to implicitly override a method with weaker type parameter constraints
645 F# Debug problems setting breakpoints in inner functions (reported by Jack Palevich - thanks Jack!)
647 F# Compiler lowercase constructors are incorrectly permitted
654 F# Interactive cannot declare delegate types interactively
672 F# Visual Studio Unapplied methods should give signature of method overloads in error message
671 F# Compiler -R feature overwrites .dll file with .pdb file
670 F# Compiler protected access not permitted via member 'this' variables
668 F# Language L-R type inference with (fun x -> x * x * 1.0)
667 F# Language exceptions to carry line numbers?
663 Fix broken codegen for generalized constrained polymorphic functions
659 F# Visual Studio Intellisense does not work in a for .. to .. do line
676 F# Visual Studio Inappropriate popup
644 F# Language execution and inference for record expressions is not always left-to-right
533 F# Release proper uninstaller
517 F# Compiler fsi.exe does not process #r/#I directives for files on command line
678 F# Library delete very old obsolete functionality fro the 'Set' module
679 F# Library Add object-oriented version of immutable 'Sets' to Microsoft.FSharp.Collections
681 F# Visual Studio hardwhite intelisense
682 F# Compiler field and property names with same name - allowed
680 F# Visual Studio intelisense bugs
665 F# Language exprs ending in semi-expr sequences cause confusion when ending constructs which are themselves semi separated.
Copy-Local reference options DLLs that are not in the GAC must be copied to an application's directory prioer to execution. This is not currently well-supported by the F# Visual Studio mode. Thus the following options are now supported by the fsc.exe compiler and are especially recommended for use from Visual Studio:
-R DLL both reference the given DLL and copy it to the output directory at the end of compilation --copy-local FILE copy the given file to the output directory at the end of compilation
Note that -R = -r + --copy-local. Also these switches are not required by fsi.exe which is able to resolve and load DLLs from any location.
New Installer InstallFSharp.msi. This currently always installs to the Program Files directory.
New library module Microsoft.FSharp.MLLib.Native Helpers for native interop. See library documentation.
Minor breaking change for native pointers. The F# "'a nativeptr" is now compiled as the .NET type System.IntPtr for all 'a. .NET pointers such as "int*" are now represented by "ilsigptr<int>" types. This cange is because although .NET has a notion of a "pointer type", used in some .NET signatures, these are not "real" types, since they can't be used within generic instantiations. This is very bad for C-interop F# code, which generates generic instantiations for function and tuple values. Thus, the F# 'a nativeptr type is now always compiled as System.IntPtr, regardless of 'a (it is not type equivalent as far as F# is concerend - this is just how the type is compiled. The pseudo-type 'a ilsigptr (IL Signature Pointer) is provided if you need to call a .NET signature using a pointer type.
COMPILED and INTERACTIVE supported as standard --define in F# Interactive and compiled code This is useful as some code fragments such as Application.Run() are only needed in compiled code. Also accessing things such as resources can vary between interactive and compiled code.
Type Inference corrections for fields and records
It is implicit in the F# informal specification that record constructions should use contextual left-to-right type information to help determine the type being constructed. This is now implemented, and makes it easier to use record syntax when record member names overlap.
Types are no longer inferred from uses of class field labels alone. Previously, defining a class "C" with a value field called, say "f" meant that "f" became a scoped record label. This meant that "expr.f" would infer the type of "expr" to be "C". This is still done for _record_ labels, but is no longer done for class field labels, and instead an annotation may be needed to constrain the type of "expr" based on left-to-right type inference. A helpful warning about the deprecation of this language feature is given when this occurs. This was always meant to be the intended treatment of inference for these constructs - it was an artefact of the initial implementation that inference for record field labels was treated in this way.
Various .NET generic constraints implemented .NET generics supports a number of somewhat adhoc constraints on the structural properties of types. It is necessary for F# to support these in order to emit correct and valid generic code and make sound use of F# libraries. The syntax of the constraints is:
when 'a : struct // any struct, with the exception of Nullable when 'a : not struct // any reference type - note - this syntax is under revision when 'a : (new : unit -> 'a) // default constructor
The following F#-specific constraint has also been added:
when 'a : null // any reference type that supports null according to the F# pseudo-enforcement rules for prohibiting the use of null with F# types when default 'a : <type> // the variable will take the given value if not otherwise instantiated or generalized
Default constructors are called using the syntax:
new 'a()
Where 'a should be related to another annotation in the same definition, e.g. an argument of the enclosing function. This constructs is compiled as a call to System.Activator.CreateInstance<'a>().
Minor improvements and Bug Fixes
573 F# Compiler list equality is not tail recursive. 613 F# Library List.combine and List.split are not tail recursive (reported by Ralf Herbrich - thanks Ralf!) 615 F# Interactive FSI reflection code throws TypeLoad error for type reference within the same interaction. 602 F# Compiler name of type not reported in "member required" error 120 F# Compiler Things stored in public static fields should only be accessible via properties 495 F# Compiler SQL cannot load F# assemblies due to publically writable statics 625 F# Compiler Poor error location for error messages related to 'new' in signatures 626 F# Library Add 'generate' methods to IEnumerable. 628 F# Compiler nested ifdefs not always handled correctly (Reported by Jack Palevich - thanks Jack!) 630 F# Compiler Error writing assembly with F# 1.1.11.7 (reported by Lewis Bruck - thanks Lewis!) 631 F# Compiler System.MethodAccessException thrown by FSI.EXE (reported by Pierre Dangauthier - thanks Pierre!) 634 F# Compiler object expression limitations: let bound object expressions not generalized (reported by Greg Neverov - thanks Greg!) 640 F# Compiler record fields should be inferred from the known context type of the expression 639 F# Compiler class fields are contributing to the record field environemnt 638 F# Compiler multiple constraints on type parameters not being correctly printed 636 F# Compiler simple object expressions implementing interfaces should be allowed in "let rec" without generating an iniitalization graph warning 632 F# Debug smoother debugging needed for inner recursive functions 648 F# Library Documentation for printf codes for 64-bit integers is incorrect (reported by Richard Mortier - thanks Richard!) 650 F# Compiler incorrectly permitting the declaration of interfaces that contain fields (reported by Robert Pickering - thanks Robert!) 649 F# Compiler bug in quotation template filling for typed quotations (Reported by Tomas Petricek - thanks Tomas!) 646 F# Compiler attributes on top level values not propagating to generated static fields, e.g. ThreadStatic (reported by Robert Pickering - thanks Robert!) 645 F# Debug setting breakpoints in inner functions sort of broken (reported by Jack Palevich - thanks Jack!)
Minor improvements and Bug Fixes
-- Fix to permit the use of lambdas taking multiple tupled arguments within quotations.
-- Fix integer formats 0b101001 and 0o101030 in fsi.exe
-- Fix inlining of composition operator
-- Add signature to 'prim-types', hiding the presence of the "Basics" module
-- Fix optimization of integer keys for hash tables
F# Language: Namespaces.. Multiple namespaces fragments now permitted in a single file. Multiple fragments can also be constrained by a single signature. Multiple different files within an assembly may also contribute to the same namespace. For example:
/// Put the concrete type definition under 'Types'
namespace Microsoft.FSharp.Math.Types
type BigComplex = { r: bignum; i: bignum }
/// Now add a type abbreviation and module under the main namespace
namespace Microsoft.FSharp.Math
type bigcomplex = Microsoft.FSharp.Math.Types.BigComplex
module BigComplex = begin
open Microsoft.FSharp.Math.Types
let complex r i = { new BigComplex with r=r;i=i }
end
F# Language: Use of null values no longer require type annotations. null values previously required immediate type information. Instead, null constraints have now been incorporated into the inference process, meaning that the type associated with the use of the null value must simply be resolved at some point in the type inference scope. This means far fewer type annotations are needed when passing 'null' values to .NET.
F# Language/Library: Implementation of Structural comparison, equality and hashing now in F# code (hence easier to understand and debug). See the file prim-types.fs in the library for the implementation of the definition of structural and physical equality, used if all other optimization techniques fail.
F# Language: More General Type Checking Rule for Class Field Access and Setting. Accessing and setting a class field previously required the object being accessed to have precisely the type of the class containing that field. This has been liberalized so that the object can have any subtype of the class containing the field. This change may affect code that uses signatures, because the inferred type of a function may be more general. For example, given
type MChan =
class
val mutable sndLst : MChan list
end
let linkMChan src dstLst = src.sndLst <- append src.sndLst dstLst
the inferred type of linkMChan was previously
val linkMChan : MChan -> MChan list -> unit
but is now the more general
val linkMChan : #MChan -> MChan list -> unit
where as usual the # indicates that any subtype is accepted as the first argument. If no subtyping is required then a rigid type annotation may be used in the implementation:
let linkMChan (src : MChan) dstLst = src.sndLst <- append src.sndLst dstLst
F# Language: Overload Resolution when Multiple Overloaded Operators Exist. Some .NET types support multiple overloads for the same operator, which must be resolved according to a process similar to the resolution of overloaded methods. F# uses constraints to handle operator overloading, and now resolves the choice between multiple overloads using essentially the same technique as is used to resolve method overloading. For example, the following overloads now resolve correctly:
let f1 (x:DateTime) (y:TimeSpan) : DateTime = x - y let g1 (x:DateTime) (y:DateTime) : TimeSpan = x - y // Return type is also sufficient: let f2 (x:DateTime) y : DateTime = x - y let g2 (x:DateTime) y : TimeSpan = x - y // Just argument types are also sufficient: let f3 (x:DateTime) (y:TimeSpan) = x - y let g3 (x:DateTime) (y:DateTime) = x - y
F# Language: Type Qualified Disciminator Names. Ambiguity between constructors of a discriminated union can now be resolved by using the type-qualified path to the discriminator, for example:
type XY = X | Y
type YZ = Y | Z
let y1 = XY.Y
let y2 = YZ.Y
let f xy =
match xy with
| XY.X -> "X"
| XY.Y -> "Y"
let g yz =
match yz with
| YZ.Y -> "X"
| YZ.Z -> "Y"
The same is true of record field names, though this has been the case for some time now.
New F# Samples: DirectX 3D Visualization, WebCrawl. See the 'samples' directory.
F# Library: Warnings now given that 'Stream' will be renamed. This module has been renamed 'LazyList'.
F# Library: BigNum performance improvements. Major implementation improvements and tuning the cross-over between the multipliers.
F# Library: Additional Math.Complex operations.
F# Interactive and Library: Default floating point format for generic printing now 'g10'. i.e. for print_any, output_any, etc. and F# Interactive.
F# Interactive: --codepage switch now accepted by fsi.exe. This controls the codepage used to read the input files. The switch does not yet apply to fsc.exe.
F# Library: Primitive structural comparison and hashing routines moved. These were in Microsoft.FSharp.Primitives.CompilerPrimitives but are now under Microsoft.FSharp.LanguagePrimitives. After a review of the library and as part of the re-implementation of structural comparison and hashing in F# code (see below) the primitive functions used for polymorphic recursive calls in structural comparison and hashing have been moved to a new module Microsoft.FSharp.LanguagePrimitives. These functions may have been called recursively from some user code. The section in the language specification has been updated to reflect this.
F# Compiler: Optimizations and Code Quality. Fewer locals are now produced in many situations where inlining occurs. This improves the quality of the end x86 code, allows the JIT to inline more often and reduces the size of the metadata in generated assemblies.
Extensible expr.[idx] syntax for string, array, dictionary and other access operations.. The syntax expr.[idx] is now shorthand for accessing the Item property on a type. This means that expr.[idx] can be used to perform lookups on essentially any .NET collection type.
Note: As with overloaded operators on integers, the types string and the array types do not in reality support Item properties in the underlying .NET metadata. However F# arranges things to give the appearance that they do.
F# for Visual Studio: Minor improvements
F# Interactive: Suffixes .fsx and .fsscript now accepted.. These are useful for F# Interactive scripts.
F# Interactive: Formatting options may now be specified. There is an fsi object, of type InteractiveSession, available in the top-level.
namespace Microsoft.FSharp.Compiler.Interactive
type InteractiveSession
with
member FloatingPointFormat: string with get,set
member FormatProvider: System.IFormatProvider with get,set
member PrintWidth : int with get,set
member PrintDepth : int with get,set
member PrintLength : int with get,set
member ShowProperties : bool with get,set
member ShowIEnumerable: bool with get,set
member PrintIntercepts: (StructuredFormat.IEnvironment -> obj -> StructuredFormat.Layout option) list with get,set
member AddPrinter: ('a -> string) -> unit
...
end
Here's an example of it's use:
> fsi;; > fsi.FloatingPointFormat <- "%.3";; > fsi.PrintWidth <- 80;; > fsi.AddPrinter(fun (x:System.DateTime) -> sprintf "%Ld" x.Ticks);; > System.DateTime.Now;; > fsi.ShowIEnumerable <- false;; > fsi.ShowProperties <- false;;
F# Compiler: The --base-address flag. Base addresses indicate the default loading address for DLLs within a memory space. Loading a DLL at a default location can reduce the need for 'fixups' that occur when a native DLL gets relocated. Native DLLs occur with F# code if you use NGEN with your F# DLLs, and it is recommended that you use an appropriate base address if rebasing conflicts occur when using NGEN. Various tools and debuggers are available on the web to help determine if rebasing is occuring.
F# Compiler and F# Interactive: Use F# with Microsoft internal or self-built versions of the CLI. Some Microsoft internal or self-built implementations of the CLI have unusual, non-standard names such as v2.0.x86chk. The --cli-version flag can now be used to specify such a version.
F# Interactive: Minor improvements
Minor improvements and Bug Fixes
574 F# Compiler issue with top level mutables (fsi.exe), reported by Andrew Fitzgibbon
389 F# Perf Printf implementation allocated too many closures
594 F# Compiler tyvar lookup failed in ilreflect
595 F# Interactive F# Interactive code generation bug when closures used inside interface implementations
596 F# Interactive F# Interactive code generation bug: Implementing generic interfaces does
not always correctly work around Reflection.Emit limitations
586 F# Compiler local mutables spilled into other locals prior to use
588 F# Compiler expr of constructor argument is not typed-expr
587 F# Compiler poor error message on for i = 0 to 10 do .. done expr
590 F# Compiler match exprA,exprB with .... allocates tuples
592 F# Compiler poor error message when a constructor is too generic
582 F# Compiler fsi prints types of the latest interaction with full path
581 F# Compiler Problem with pickling: Quotation <@ 1.3 @> gives NaN
576 F# Perf Reduce number of generated IL locals
566 F# Compiler interface inheritance/extension not being printed correctly
471 F# Compiler Eliminate unnecessary .cctors
--- Fixes to printing and Array2 module for non-zero-bounded multi-dimensional arrays.
--- Instance members now permitted on types that may use null as a representation. They
are compiled as static members.
--- Fields in super classes not accessible (reported by Ralf Herbrich - thanks Ralf!)
The 'a nativeptr type. The unverifiable type constructor nativeptr is now supported for C/C++/C# pointer types, e.g. sbyte* becomes sbyte nativeptr. In principle this is a breaking change, as previously .NET pointer types were mapped to the F# type nativeint, and are now mapped to nativeptr instead. The new behaviour is, however, consistent with .NET and necessary to permit methods that overload by pointer type (e.g. the unverifiable System.String constructors accepting byte pointers) to be resolved correctly.
Minor improvements and Bug Fixes
F# Interactive for Visual Studio. It rocks! See the section above.
F# website now at http://research.microsoft.com/fsharp
Unified, first-class, composable events. .NET events can now be accessed directly through their real name (e.g. form.Click) rather than through their helper functions (form.add_Click etc.). They can also be used in a first-class way, i.e. form.Click can be passed around as a value. The type of such a value is Idioms.IDelegateEvent, which extends Idioms.IEvent. F# published delgate types should have type Idioms.IHandlerEvent. An MLLib module Microsoft.FSharp.MLLib.IEvent includes some basic polymorphic operations over IEvent types.
Quotation processing over raw quoted expressions. New quotation operators such as <@@ @@> are supported for quoting terms (expressions) in their raw form. More details can be found in the documentation on the Quotations module and the F# informal language specification.
Removed Drop-Down VS Discrimination Menus. Temporarily disabled discrimination drop-down Intellisense in VisualStudio, due to poor completions.
Minor improvements and Bug Fixes
Minor improvements and Bug Fixes
Minor syntax extension related to struct. The syntax module X = begin ... end can now be used in addition to the OCaml-compatible syntax module X = struct ... end. The use of the word struct is potentially ver confusing to .NET-savvy newcomers, who will confuse this with a C# struct. Likewise module X : begin ... end is now the recommended way of writing module X : sig ... end in signatures.
Address-of operator. Occasionally a need arises to pass a byref parameter on to a function. This can now by done using the '&expr' address-of operator. A warning will be given whenever this is used.
Source cleanup. Various cleanup work items completed.
ExportAs deprecated. ExportAs was an old, somewhat half-baked technique to export functions as classes. Now that the object model has been implemented it is no longer needed.
Matrix library redesign and cleanup. Microsoft.FSharp.Math has been reorganised.
Expression quotation library redesign and cleanup. Now called Microsoft.FSharp.Quotations.
HTML library manual pages now included in the release and on the Microsoft Research website.
HTML documentation generation with fsc.exe. Look for the --html* flags in the advanced flags. Documentation is given using "///" comment markers prior to modules, types, values and exceptions.
Fix some problems with the Visual Studio mode. Some files were missing.
Expression Quotation. Microsoft.FSharp.Experimental.Lifted (NOTE later renamed to Now called Microsoft.FSharp.Quotations) contains a range of functionality related to "lifted expressions", i.e. expression quotation, which is a form of meta-programming. This is still under development, and some important functionality is missing or incomplete, but is extensively used in the LINQ sample that is also available in the release.
LINQ Sample. The sample samples\fsharp\FLinq shows how F# can work with the Language-Integrated-Query libraries currently under development at Microsoft.
Source Release. source/... now includes the source code to the Abstract IL, ILX, the F# compiler, F# interactive, the library and the tools, as long promised.
Compiling: To compile it up you us the Makefile and the F# compiler from the distribution itself, and you currently need .NET 2.0, and there is some C/C++ helper code to compile which requires the use of the Microsoft Visual Studio 2005 C/C++ compiler. However you do not really need to compile the C/C++ code, which only enables debugging support etc. (and indeed you can reuse the absilsuppc.dll from the F# distribution itself instead of compiling it up afresh). It should be fairly straightforward to compile with .NET 1.0/1.1 (--cli-version 1.0, change define GENERICS to NOGENERICS etc.) and should also be possible to compile on Mono using 'fscp10.exe', the portable bootstrapped compiler.
General comment: The source has its many quirks and there are many things in we will be cleaing up - if it's ugly then please be merciful and ignore it. Anyway, have fun with it!
Visual Studio mode: (The source for the VS plugin is not yet included, though a crucial file 'fsharp/vs/service.ml' is - this has the key functionality that implements the line-by-line lexing, typechecking cache etc.)
Argument name annotations for documentation purpose in signatures. Arguments can be labelled for documentation purposes, in signature files (.mli/.fsi) only. Note this is not the same os OCaml labelled arguments (which permit labels to be used at the callsite). For example:
val open_in_gen: flags:open_flag list -> permissions:int -> filename:string -> in_channel
First class uses of the 'unit' type now compiled to Microsoft.FSharp.Unit. Previous versions of F# compiled the unit type to System.Object. This has been changed to give better fidelity for runtime types, especially of function values. Note this will break C# 2.0 code that has not been using delegates of type System.Action as the way of creating function types.
Library Updates.
1.
Adjust the
signature of Idioms.using.
The current signature of
Idioms.using is
val
using: (_ :> System.IDisposable) -> (unit -> 'a) ->
'a
giving somewhat awkward usage
patterns such as
let
ts = new TransactionScope()
in
using ts (fun () ->
<do something with
ts>
)
In this release the signature
becomes
val
using: ('a :> System.IDisposable) -> ('a -> 'b) ->
'b
giving considerably more C#-like
usage patterns such as
using (new
TransactionScope()) (fun
ts ->
<do something with
ts>
)
When translating code from C# we
have found ourselves defining a new version of “using” to match the above, so it
seems preferable, and something we should switch to sooner rather than
later.
2.
Standardize on
the frequent use of “|>”
The operators “|>” and “>>”
are already defined in MLLib.Pervasives as follows:
let
(|>) x f = f x
let
(>>) f g x = g (f x)
Over time it has become clear that
use of these operators, and the “|>” operator in particular, is key to
succinct expression of functional programming when using left-to-right type
inference to resolve some name access base on type information (the technique F#
uses to resolve method overloading and property accesses). Thus we will be using
this operator far more extensively in F# code, tutorials and samples, and will
assume that it’s use one of the first things an F# programmer learns.
For example, note how “a” and “ty”
do not require type annotations in the following code to resolve the use of the
“.” notation.
This is because type information is propagated from the result
type of GetAssemblies through to these binding
sites.
let allMembers =
System.AppDomain.CurrentDomain.GetAssemblies()
|> Array.to_list
|> List.map (fun a -> a.GetTypes()) |> Array.concat
|> Array.to_list
|> List.map (fun ty -> ty.GetMembers()) |> Array.concat;;
(Now write that program in any other
.NET language in 4 lines!)
Assuming familiarity with “|>”has
some ramifications for library design, leading to some of the changes. In
particular:
·
Delete ‘transform’, ‘foreach’ etc. in MLLib.List, MLLib.Array
etc.
These functions were added in an attempt to give left-to-right type
inference, in the style above. However, they were never terribly effective at
doing this.
Furthermore the use of the name “foreach” clobbered the
corresponding name in Idioms. They are best
forgotten.
3.
Include decent
support for IEnumerable-related functions
·
Add the following modules to MLLib (NOTE: not all functions are supproted in this release)
module IEnumerable
// The following functions work over the
System.Collections.Generic.IEnumerable type
val length : #IEnumerable<'a> ->
int
val hd : #IEnumerable<'a> ->
'a
val tl : #IEnumerable<'a> ->
IEnumerable<'a>
val nth : #IEnumerable<'a> -> int
->
'a
val nonempty: #IEnumerable<'a> ->
bool
val empty : unit -> IEnumerable<'a>
val init : (int -> 'a
option) ->
IEnumerable<'a>
val unfold : ('b -> ('a
* 'b) option) -> 'b
->
IEnumerable<'a>
val append : #IEnumerable<'a> ->
#IEnumerable<'a> ->
IEnumerable<'a>
val concat : #IEnumerable< #IEnumerable<'a> > ->
IEnumerable<'a>
val exists : ('a ->
bool)
->
#IEnumerable<'a> ->
bool
val for_all : ('a ->
bool)
->
#IEnumerable<'a> ->
bool
val filter : ('a ->
bool)
->
#IEnumerable<'a> ->
IEnumerable<'a>
val choose : ('a -> 'b
option) ->
#IEnumerable<'a> ->
IEnumerable<'b>
val first : ('a -> 'b
option) ->
#IEnumerable<'a> -> 'b
option
val find : ('a ->
bool)
->
#IEnumerable<'a> ->
'a
val tryfind : ('a ->
bool)
->
#IEnumerable<'a> -> 'a
option
val iter : ('a ->
unit)
->
#IEnumerable<'a> ->
unit
val iteri : (int -> 'a
->
unit) ->
#IEnumerable<'a> ->
unit
val fold : ('b -> 'a
-> 'b)
-> 'b
->
#IEnumerable<'a> ->
'b
val map : ('a -> 'b)
->
#IEnumerable<'a> ->
IEnumerable<'b>
val mapi : (int -> 'a
->
'b)
->
#IEnumerable<'a> ->
IEnumerable<'b>
val of_array: 'a array -> IEnumerable<'a>
val of_list : 'a list -> IEnumerable<'a>
val to_array: #IEnumerable<'a> -> 'a
array
val to_list : #IEnumerable<'a> -> 'a
list
// The following functions work over the
System.Collections.IEnumerable type
// and are available on .NET
1.0/1.1
val untyped_fold : ('b -> 'a -> 'b) -> 'b -> #IEnumerable -> 'b
val untyped_iter : ('a -> unit) -> #IEnumerable -> unit
val untyped_map : ('a -> 'b)
-> #IEnumerable -> IEnumerable
val untyped_filter: ('a -> bool) -> #IEnumerable -> IEnumerable
val untyped_to_list:
#IEnumerable -> 'a list
·
Mark the following as obsolete.
Idioms.foldeach (replaced by
IEnumerable.fold_untyped)
Idioms.transform (replaced by
IEnumerable.map_untyped)
Idioms.foldeachG (replaced by
IEnumerable.fold)
Idioms.transformG (replaced by
IEnumerable.map)
Idioms.foreachE (never needed – all relevant
types implement IEnumerable)
Idioms.foldeachE (never needed – all relevant
types implement IEnumerable)
Idioms.transformE (never needed – all relevant
types implement IEnumerable)
Idioms.foreachEG (never needed – all relevant
types implement IEnumerable)
Idioms.foldeachEG (never needed – all relevant
types implement IEnumerable)
Idioms.transformEG (never needed – all relevant
types implement IEnumerable)
This leaves the
following in Idioms:
val foreach :
#System.Collections.IEnumerable
-> ('a
-> unit)
->
unit
val foreachG:
#System.Collections.Generic.IEnumerable<'a> -> ('a -> unit) -> unit
Rationale: The
purpose of Idioms is to hold F# representations of idioms in .NET, C# and other
languages. It should be comprehensible to beginner F# users. The above
functions were added in a bit of a hurry and simply shouldn’t be in Idioms,
since their purpose is to offer a consistent set of folding and mapping
operations over both the generic and non-generic (untyped) IEnumerable and
IEnumerator types. Much preferable is a module in MLLib that holds these
operations using the consistent MLLib naming scheme (iter, fold, map etc.).
Note: the LINQ
initiative will offer further platform-standard functionality similar to the
above, and when the final version of LINQ is released we will support a
namespace such as Microsoft.FSharp.Bindings.Linq which maps the Linq operators
into F#. Having a half-baked version of this stuff in Idioms doesn’t do anyone
any good. However we can’t wait for the release of Linq to fix this sort of
thing, and in any case Linq uses naming conventions which are different to F#
(select for map, where for filter etc.).
·
Mark as obsolete the very thinly
populated and undocumented
Idioms.IEnumerable, Idioms.IEnumerator. These were again added in a
hurry leading up to the last release and are again best
forgotten.
4.
Include
consistently named support for Enum-related functions
·
Add the following module to MLLib
module Microsoft.FSharp.MLLib.Enum
///Convert an enumeration value to an
integer.
The argument type is inferred from
context.
val to_int: 'a ->
int
when 'a
:> System.Enum
///Convert an integer to an enumeration
value.
The result type is inferred from context.
val of_int: int ->
'a
when 'a
:> System.Enum
///Combine enum values using 'logical
or'. The relevant enumeration type is inferred from
context.
val combine: 'a list -> 'a
when 'a
:> System.Enum
///Test if an enumeration value has a
particular flag set, using 'logical and'.
///The relevant enumeration type is
inferred from context.
val test: 'a -> 'a
->
bool
when 'a
:> System.Enum
·
Mark the following as obsolete.
Idioms.EnumToInt (replaced by
Enum.to_int)
Idioms.IntToEnum
(replaced by
Enum.of_int)
Idioms.CombineEnumFlags (replaced by
Enum.combine)
Idioms.TestEnumFlag (replaced by
Enum.test)
Rationale: The
purpose of Idioms is to hold F# representations of idioms in .NET, C# and other
languages. The above functions are not particularly idioms in any other .NET
language – they just represent things where you have to be a bit more explicit
in F#. They date from the day when Idioms was a sink for “anything which you
needed to do with a runtime check”. Their naming is not particularly consistent
with any other style. Nor are they particularly easy to
find.
It is much preferable to add a
module to MLLib that holds these operations using the consistent MLLib naming
scheme (to_int, of_int etc.).
Note: A future
version of F# may support + etc. on enum types.
Bug Fixes. Various minor fixes.
511 F# Interactive 1 0 errors raised during optimization exit fsi.exe 522 F# Interactive 1 1 fsi bug with operator names 523 F# Interactive 1 0 Automatic binding to a relative path (or the current directory) fails 532 F# VS Plugin 1 1 VS -I and -r relative paths are relative to somewhat random working directoy of VS process rather than the project/file working directory 534 F# VS Plugin 2 1 off-by-one error in VS mode balloon tips 525 F# VS Plugin 1 1 visual studio prior inputs with unicode signature are not being parsed correctly 537 F# Docs 1 1 Abbreviated types appearing in XMLDoc files, also 'unit' 543 F# Language 1 1 printing "List" and "Option" for types generated by uses of constructors looks gross 433 F# Compiler 2 2 Represent "unit" as a real type rather than abbreviating to "obj" 453 F# Compiler 2 2 print_any - no printing of repeated terms - no print depth/width controls 505 F# Language 1 0 implement a way to name arguments - crucial documentation 529 F# Compiler 1 0 differing orders of fields for records in signatures and implementations cause problems for record constructors and "with" 549 F# VS Plugin 1 0 VS redirecting stdout to Output window interferes with stdin 552 F# VS Plugin 1 1 VS mode show 2 resolutions for .NET types 553 F# VS Plugin 1 1 VS Mode method tips bounce back to first entry every time the "down" key is pressed (reported by Artem - thanks Artem!) 554 F# VS Plugin 1 1 Balloon Tips not showing XMLDoc help text for methods and types 555 F# VS Plugin 1 1 Intellisense not showing signatures and overloads for .NET constructors. 556 F# Documents 1 1 Incorrect XMLDoc signatures being generated for generic methods and some other generic gadgets 539 F# Interactive 1 0 compile F# Interactive on .NET 1.0 560 F# VS Plugin 1 1 TAB in VS mode doesn't activate completion 561 F# Language 1 1 Module abbreviations not permitted in signatures 563 Abstract IL 2 2 AbstractIL library contains duplicate hashtable modules etc. 562 F# Library 1 1 printf %s formats do not permit padding specifications 564 Abstract IL 1 1 Abstract IL library module names need to be much more sensibly organized
Matrix Library. Microsoft.FSharp.Math.Matrix<_> has been added as a generic matrix type, with extensive MATLAB-like operations at Microsoft.FSharp.Math.MatrixOps<_> and Microsoft.FSharp.Math.MatrixOps.Generic;. The former are for floating point matrices Matrix<float> = matrix, and the latter are generic over all matrix types. The interface to this library is likely to be stable. Vector and RowVector types are also defined - their status sill undergo revision after a few releases.
Very Preliminary Linear Algebra. Microsoft.FSharp.Math.LinearAlgebra<_> contains a handful of basic linear algebra functions.
Compositional, Customizable Structured Printing. A preliminary but powerful approach to user-definable structured display of terms has been implemented in this release. The solution is different to the OCaml-style "Format" library and is instead based on the generation of intermediary "layout" objects. So far, a layout describes how words will fit next to each other and where the breaks (and indentations) will/can be.
A layout engine typically constructs most layouts using a generic algorithm based on the term structure of F# data accessed via Microsoft.FSharp.Experimental.Reflection. Types that wish to customize their structured format specification can implement the StructuredFormat.IFormattable interface, which must provide a function that generates a StructuredFormat.Layout value. An environment is passed to the object that provides a function to use to generate layout for recursive calls. Leaf objects such as numbers and strings can be left unformatted, which gives a formatting engine control over how these appear (e.g. culture specific formatting of numbers). A default formatting engine is provided in Microsoft.FSharp.MLLib.Pervasives.LayoutOps for formatting layouts to strings, channels and text buffers. This engine can be customized to some extent (e.g. by print width, depth, culture and floating-point number formatting) and is used by thw following functions:
as well as the F# Interactive pretty printer. The end result is that objects are converted to textual formats consistently and in a customizable way. Here is and example of the output generated, here for a matrix holding further matrices:
> open Math;;
> open MatrixOps.Generic;;
> let m = matrix [[1.0;2.0;3.0]];;
val m : Matrix<float>
> m;;
val it = matrix [[1.000000; 2.000000; 3.000000]]
> let m = matrix [[m];[m];[m]];;
val m : Matrix<Matrix<float> >
> m;;
val it = matrix
[[matrix [[1.000000; 2.000000; 3.000000]]];
[matrix [[1.000000; 2.000000; 3.000000]]];
[matrix [[1.000000; 2.000000; 3.000000]]]]
Here is an example of customization of the structured layout to format complex numbers, without actually specifying the formats of the constituent components:
open StructuredFormat.LayoutOps
type Complex = { real: float; imaginary: float }
with
member x.r = x.real
member x.i = x.imaginary
interface StructuredFormat.IFormattable with
member x.GetLayout(env) =
objL (box x.r) ++ rightL "r" ++ sepL "+" ++ (objL (box x.i) $$ rightL "i")
end
Named arguments for attributes. Attribute specifications can now take named arguments, e.g.
[<DllImport("KERNEL32.DLL", EntryPoint="MoveFileW", SetLastError=true,
CharSet=CharSet.Unicode, ExactSpelling=true,
CallingConvention=CallingConvention.StdCall)>]
let MoveFile ((src : string), (dst: string)) : bool = failwith "extern"
Abstract properties. Interfaces and classes may now define abstract properties and specify overrides and defaults for these. This is functionality that was not completed in the first release of the object model. e.g. in an interface definition:
Abstract properties and properties in interfaces. Interfaces and classes may now define abstract properties and specify overrides and defaults for these. This is functionality that was not completed in the first release of the object model. e.g. in an interface definition:
type IEnvironment =
interface
/// A property indicating the maximum number of columns
abstract MaxColumns : int
/// A property indicating the maximum number of rows
abstract MaxRows : int
end
And in an implementation by a class:
type MyEnvironment =
class C
interface IEnvironment with
method x.MaxColumns = 3
method x.MaxRows = 4
end
end
And in an implementation by an object expression:
{ new IEnvironment
with MaxColumns = 3
and MaxRows = 4 }
Rename 'MLLib.Vector' to 'MLLib.ReadonlyArray'. 'Vector' and 'vector' are now used for Microsoft.FSharp.Math.Vector, mutable column vectors whose element type typically support certain element operations.
Bug Fixes.
470 F# Compiler Constructors and method can't be overloaded betweeen 0/1 arguments 473 F# Compiler Operator overloading bug 474 F# Visual Studio Pattern hints for lists showing operator names, also no testing for these 475 F# Visual Studio Pressing BAR causes poor menus to pop up in Visual Studio too often 478 F# Compiler #use only processes one interaction per file 479 F# Compiler fsi - ctrl-C during command line arg processing unhandled. 481 F# Compiler fsi - syntax error recovery... 482 F# Language any_to_string doesn't print arrays 483 F# Compiler internal type variable error (reported by Karthik) 484 F# Compiler overloaded indexer properties not correctly resolved (from F# Mailing list) 485 F# Compiler uppercase non-constructor names used in patterns do not give a warning 486 F# Doc Fix documentation bug (reported by Greg Chapman - thanks Greg!) 491 F# Library Equality not implemented on matrices 492 F# Compiler imperative type vars and type var bindings not being shown in error messages (reported by Karthik) 391 F# Compiler F# not automatically usable on x64 boxes 372 F# Compiler F# gives syntax error for OCaml top level expressions 349 F# Compiler Inferred constraints of the form "x :> obj" should be ignored (e.g not required in signatures) 250 F# Visual Studio Load on-the-fly XML documentation into Visual Studio, or connect to VS interfaces that will do this for us 309 F# Compiler import C# constrained polymorphism as F# constrained polymorphism 315 F# Visual Studio output does not go to console window by default 490 F# Library Consistent approach to structured print layout needed
Bug Fixes. Various minor fixes to F# Interactive, e.g. large bytearrays. F# Interactive now works on .NET 2.0 Relase Candidate versions. Additional warnings on some minor incomplete features.
Visual Studio. Now supports "Go To Definition" and "Go To Declaration"
MLLib.Printf. Now supports '%M' for decimal values and '%O' for any 'any' object value. These are currently printed using Object.ToString() but may in the future be printed using any_to_string.
Bug Fixes. Visual Studio fixes for '|' triggers.
Core Language. Integer constants for the types 'bignum' and 'bigint' are now supported, e.g.
do Printf.printf "%O\n" 3N do Printf.printf "%O\n" 3I do Printf.printf "%O\n" (3N / 4N) do Printf.printf "%O\n" (3N / 400000000N) do Printf.printf "%O\n" (3N / 3N) do Printf.printf "%O\n" (-3N) do Printf.printf "%O\n" -3N do Printf.printf "%O\n" (-3N / -3N) do Printf.printf "%O\n" -30000000000000000000000000000000000000000000000000000000000000N
The following operartors are now supported and can be used for multi-dimensional array lookup/assignment.
arr.(i,j) -- Look up a rectangular (non-jagged) 2D array of type 'ty[,]' arr.(i,j) <- x -- Assign into a rectangular (non-jagged) 2D array of type 'ty[,]' arr.(i,j,k) -- Look up a rectangular (non-jagged) 2D array of type 'ty[,]' arr.(i,j,k) <- x -- Assign into a rectangular (non-jagged) 2D array of type 'ty[,]'
The MLLib modules Array2 and Array3 provide basic operations for 2 and 3 dimensional arrays. .NET operations on the System.Array type can also be used directly.
Library. The Compatibility.CompatArray and Compatibility.CompatMatrix module now give better results (no polymorphism restrictions apply) if inadvertantly used from .NET 2.0. Use of these modules is not recommended from .NET 2.0 but sometimes occurs when code is copied from cross-compiling samples.
Attributes. Specification clarifications for attributes. Attributes now give warnings when used inappropriately. Attributes can now be referenced with or without the Attribute suffix, e.g. [<Obsolete("this function is obsolete")>] or [<ObsoleteAttribute("this function is obsolete")>].
Compilation Speed Optimizations. Improved compilation speeds, especially when using the --standalone flag.
VS Mode. Better response as now compacts less often. Now accepts all fsc.exe flags within the argument window: those irrelevant to type-checking are still used when the command line compiler is invoked.
Minor renamings. The .NET compiled names of some exceptions have changed to follow .NET library design guidelines
AssertFailure --> AssertionFailureException.
MatchFailure --> MatchFailureException.
Undefined --> UndefinedException.
The names from F# code are now either the above names or, when using MLLib, the equivalents Assert_failure, Match_failure and Undefined.
Turning off default augmentations for discriminated unions. By default F# dsicriminated unions are augmented with properties and methods such as member IsRed : bool,member Red : int -> Color and Red1 : Color -> int for a constructor Red of int in a type Color. Now that augmenetations are supported directly in the F# language it is often more convenient to manually design these augmentations. The default augmentations can now be suppressed by using the [<DefaultAugmentation(false)>] attribute. For example, the Option<'a> type in the F# library is defined as:
[] /// The type of optional values. When used from other .NET languages the /// empty option is the 'null' value. type Option<'a> = None | Some of 'a /// Augmentation type Option<'a> with member x.Item = match x with Some x -> x | None -> op_Raise (new System.IndexOutOfRangeException()) static member IsNone(x : Option<'a>) = match x with None -> true | _ -> false static member IsSome(x : Option<'a>) = match x with Some _ -> true | _ -> false static member None : Option<'a> = None static member Some(x) : Option<'a> = Some(x) end
Initial support for Microsoft.FSharp.Experimental.Collections With the completion of the F# support for members and augmentations we are moving the functionality of the MLLib collections to be co-designed libraries for functional and object oriented programming. The means that a functional programming API to the collection types will be offfered in MLLib, and a mixed object-oriented/functional API within FSLib. This will greatly improve the usability of the collection types from C# and other .NET languages, without losing the essence of OCaml-compatible ML programming. The first class we have applied this treatment to is Microsoft.FSharp.Experimental.Collections.HashTable and the related HashSet, CHashTable and CHashSet.
Generic Recursion support temporarily withdrawn. Some bugs were found in the support for generic recursion added in 1.1.0.4 (unverifiable binaries could be produced in some situations). In particular, full signatures need to be given to make a function eligible for generic recursion, and this is not yet enforced. Functions and values may still be given explicit type parameters, but recursive uses of explicitly paramaterized values must at invariant instantiations, as was always the case for versions prior to 1.1.0.4.
Bug fixes. Several bug fixes related to attributes, generalization, enumerators and exception abbreviations, Arg.usage. Thanks to Martin Churchill, Dominic Cooney, SooHyoung Oh, Ondrej Rysavy, Robert Pickering, Greg Lee and Adam Granicz among others for reporting these bugs. Some other bugs recently recorded as fixed in out database are as follows:
443 F# Library MLLib.Stream incorrect behaviours 442 F# Compiler print_any raises exceptions on singleton constructor values 452 F# Compiler Visual Studio and fsc.exe both have problems with unicode, reported by DOminic Cooney 440 F# Tools lex/yacc - partial parses of stdin require extra token before succeeding and discard buffered input 441 F# Compiler uncaught exceptions are not reported in user friendly way (no details of what they carry...) 444 F# Compiler records compile to classes with duplicate members names - a problem for debugging 445 F# Compiler serialisation of nil list fails 426 F# Compiler "end of file in string or comment" error doesn't report start-of-string-or-comment 459 F# Compiler Undefined type variable problem 458 F# Compiler typechecker doesn't decode all attributes correctly (decode_simple_cattr_data) 371 F# Compiler Support adding managed resources to .NET DLLs and EXEs 422 F# Compiler VideoPlayer sample gives error 406 F# Library Bignums package 470 F# Compiler Constructors and method can't be overloaded betweeen 0/1 arguments 467 # Library any_to_string on char fails on 1.1
Compiler for use with Mono.
Later note: as of F# 1.1.12 when used with Mono 1.1.17 the comiler for Mono is fscp10.exe and tailcalls appear to be correctly supported by Mono.
Old note: The binary fscp10ntc is a version of the F# compiler that is reported to work to some extent in conjunction with the Mono CLI implementation. Tailcalls have reported to cause problems on Mono, hence this is a "no tailcall" (ntc) version of the compiler, which leads to changes in performance. The matching "ntc" versions of the libraries are also included. This is also a CLI 1.0 binary, again changing the performance.
This version of the compiler is reported to be sluggish, so a reasonably fast machine may be required. It may also be worth investigating the use of pre-compilation (mono --aot) in conjunction with this binary to improve startup times (pre-compilation is pretty much essential for any compiler).
The F# Object and Encapsulation Extensions. F# types can now be augmented with properties, members and operators. Furthermore, .NET-style class and interface types may also be defined in F# itself. Fairly complete documentation is provided in the language specification.
Big integers and arbitrary sized rational arithmetic. The types under Microsoft.FSharp.Math.* are the implementations of the F# arbitrary precision integer and rational arithmetic types. A partially-OCaml-compatible version of this functionality is included in MLLib, i.e. use the functionality available via 'open Num'. The types support overloaded operators. The naturals are used to build arbitrary sized integers and rationals. The implementation aims to for a lower garbage cost and provides multiplication that scales effectively up to huge numbers.
The F# Language Specification (Preliminary). A work-in-progress language specification is now included in the manual.
Specification clarifications.
Attributes attached to values in F# signatures (.fsi and .mli files) are incorporated into any F#-specific interface metadata associated with the generated assembly and the .NET IL metadata for the generated assembly. Attributes attached to values in F# implementations (.fs and .ml files) are only saved into the .NET IL metadata. Thus attributes that are relevant to F# type checking (e.g. Obsolete attributes, which generate warnings at compile time when constructs are used) must be placed in signatures. Attributes from signatures need not be duplicated in implementations.
Managed and Unmanaged Resource Linking. The command-line flags --resource, --link-resource and --win32res are now supported by the F# compiler for embedding native and managed resources (text files, icons, bitmaps, audio files etc.) into executables. They have the same meanings as the corresponding C# flags.
New in Microsoft.FSharp.Idioms. The following are new in this module of useful .NET idioms:
val foreachE: (_ :> System.Collections.IEnumerator) -> ('a -> unit) -> unit
val foldeachE: (_ :> System.Collections.IEnumerator) -> 'acc -> ('acc -> 'a -> 'acc) -> 'acc
val transformE: (_ :> System.Collections.IEnumerator) -> ('a -> 'b) -> System.Collections.IEnumerator
val foreach: (_ :> System.Collections.IEnumerable) -> ('a -> unit) -> unit
val foldeach: (_ :> System.Collections.IEnumerable) -> 'acc -> ('acc -> 'a -> 'acc) -> 'acc
val transform: (_ :> System.Collections.IEnumerable) -> ('a -> 'b) -> System.Collections.IEnumerable
#if GENERICS
val foreachG: (_ :> System.Collections.Generic.IEnumerable<'a>) -> ('a -> unit) -> unit
val foldeachG: (_ :> System.Collections.Generic.IEnumerable<'a>) -> 'acc -> ('acc -> 'a -> 'acc) -> 'acc
val transformG: (_ :> System.Collections.Generic.IEnumerable<'a>) -> ('a -> 'b) -> System.Collections.Generic.IEnumerable<'b>
val foreachEG: (_ :> System.Collections.Generic.IEnumerator<'a>) -> ('a -> unit) -> unit
val foldeachEG: (_ :> System.Collections.Generic.IEnumerator<'a>) -> 'acc -> ('acc -> 'a -> 'acc) -> 'acc
val transformEG: (_ :> System.Collections.Generic.IEnumerator<'a>) -> ('a -> 'b) -> System.Collections.Generic.IEnumerator<'b>
#endif
type 'a sizeof = { result: int }
val inline sizeof: unit -> $a sizeof
Bugs fixed.
438 F# Compiler Mixed null and string matches bypassed pattern simplifier
441 F# Compiler Uncaught exceptions wrapping a string report their message.
442 F# Compiler Experimental.Reflection failed on singleton constructor values.
F# VS Mode Type inference variables appearing in the displayed hover-text for F# values
F# Library open_in now opens in ASCII encoding. Use stream_reader_to_in_channel to open in other encodings
Local names. Improved naming of locals to help during debugging.
Additional Overloading Strings now support overloaded '+'.
Customizable Debugger Views for F# Types. F# types can now be augmented in a a number of ways to customize how the values appear in a debugger. Firstly, the ToString member may be adjusted for each F# concrete type (i.e. record, discriminated union and object types). Secondly, the .NET 2.0 standard DebuggerDisplay attribute can be used in conjunction with member augmentations to customize the simple textual display associated with a type. For example:
type [] MyIntList = | MyNil | MyCons of int * MyIntList with member x.Length = let rec length x acc = match x with MyNil -> acc | MyCons(a,b) -> length b (acc+1) in length x 0 end
Finally, for sophisticated structured collections the .NET 2.0 standard DebuggerTypeProxy can be used in conjunction with member augmentations to specify a class that represents the visual display of an object. For example:
type [] MyIntList = MyNil | MyCons of int * MyIntList and MyIntListDebugView = class val v: MyIntList new(x) = { v = x } [ ] member x.Items = let rec length x acc = match x with MyNil -> acc | MyCons(a,b) -> length b (acc+1) in let len = length x.v 0 in let items = Array.zero_create len in let rec go n l = match l with MyNil -> () | MyCons(a,b) -> items.(n) <- a; go (n+1) b in go 0 x.v; items end
Custom Attribute Extensions Custom attributes now accept 'type' arguments. Double parantheses (to disambiguate the start and finish of the extra argument) and the keyword type must currently be used:
[]
Library additions: Option. The Option module is now a standard part of MLLib. It has a set of functions similar to List.
Library additions: Printf.failwithf and more. The Printf module now supports the failwithf function, which uses structured formatting to print to a string and then raise a Failure exception for this string. The new printer bsprintf is also supported: this prints to a string but intermediary functions print to string buffers. More general compositional forms of Printf operators are also included that let you specify a 'final action' for the printig such as flushing or raising an exception. Finally the OCaml-style 'format4' printer specifications are now also supported - these enable overall return types to be distinct from the types generated by intermediary printers.
Inclusion of a very preliminary release of a top-level command-line interactive environment for F#. The top-level environment will be fsi.exe. This is work in progress, and is included only for testing purposes.
Inclusion of a very preliminary release of FSharp.Compiler.dll, a hostable F# compiler. This is work in progress, and is included only for testing purposes.
Defining Events in F# Events should be defined using new definitions in Microsoft.FSharp.Idioms. For example:
open System.Windows.Forms
open Idioms
type MyCanvas =
class
inherit Form
val redrawListeners: EventListeners
member x.Redraw = x.redrawListeners.Event
override x.OnPaint(args) = x.redrawListeners.Fire(args)
new() = { inherit Form(); redrawListeners= new EventListeners() }
end
let form = new MyCanvas()
do form.Redraw.Add(fun args -> Printf.printf "OnRedraw\n")
do form.Activate()
do Application.Run(form)
Note we are using a property of type Idioms.IEvent<PaintEventArgs> to represent the event. The object returned by this property has Add, AddHandler and RemoveHandler methods (see below). In a future release of the compiler properties of type Idioms.IEvent<PaintEventArgs> will automatically result in appropriate .NET metadata for the event being inserted in the generated assembly. In the current release events defined using this mechanism may still be used from C# and other .NET by using AddHandler and other methods on themediating object.
type Idioms.SimpleEventArgs<'a> =
class
inherit System.EventArgs
member Data: 'a
new: 'a -> SimpleEventArgs<'a>
end
type Idioms.SimpleEventHandler<'a> = System.EventHandler>
type Idioms.IEvent<'a> =
interface
inherit IDelegateEvent
// The inheritance gives:
// abstract AddHandler: SimpleEventHandler<'a> -> unit
// abstract RemoveHandler: SimpleEventHandler<'a> -> unit
// We add this one, which from F# code this is very simple to use:
abstract Add: ('a -> unit) -> unit
end
type Idioms.event<'a> = IEvent<'a>
type Idioms.EventListeners<'a>
with
member Fire: 'a -> unit
member Event: IEvent<'a>
new: unit -> EventListeners<'a>
end
Renamed fslib10ng.dll to fslib10.dll, since there was a bug with using F# with Visual Studio 2003, and also the "ng" (non-generic) suffix was redundant and clumsy.
Stabilized string hash codes across .NET v1.1 and v2.0. That is, F#'s structural hash function no longer hashes strings by calling String.GetHashCode, since the hash codes returned were different between version 1.1 and 2.0.
Fixed a bug with the debug marks being attached for the entrypoint of executables.
A special function Pervasives.rethrow is now supported. This rethrows the exception for the current "try/with" block. However, it may only be used in catch blocks. Using it in a first class way or outside a catch block will result in a binary that cannot be verified. The correct use of this function is not checked in this version of F# but will be checked in a later version.
Fixed a bug that prevented the generic EventHandler type from being used (or indeed any generic type that was in the same namespace as a non-generic type with an identical name).
F# .EXEs that do not use function values, list types, option values or any other fslib or mllib no longer pick up a dependency on fslib.dll. DLLs incorporating interface data or optimization data still acquire a dependency.
Welcome James Margetson to the F# team!
F# now works with Whidbey Beta 2 releases of .NET (EDITOR: the latest releases no longer support Beta 2). F# can continue to be used with .NET 1.0 and 1.1, but can no longer be used with Whidbey Beta 1. If you are still using Whidbey Beta 1 and don't want to upgrade to Whidbey Beta 2 then add --cli-version 1.1 to your compilation switches to compile for .NET 1.1 (likewise 1.0) instead.
Change to Library Naming. The F# libraries fslib and mllib now come in two flavours: one for use with .NET 1.x (no generics) and one for use with .NET 2.0 Beta 2 and beyond (this is to ensure that the library can take advanatage of new features of the platform). The .NET 1.x version of the library has the suffix "10" attached. Thus you will see both fslib.dll and fslib10.dll in this release. F# will automatically reference the correct DLL. When compiling C# code with .NET 1.x you will need to reference fslib10.dll and mllib10.dll.
Rename some internal functions. Some internal functions such as GenericCompare have been renamed appropriately, e.g. to StructuralCompare.
Performance improvements.do Console.WriteLine("res = {0}\n",Decimal.op_Addition(new Decimal(10), new Decimal(10)))
do Console.WriteLine("res = {0}\n",(new Decimal(10)) + (new Decimal(10)))
do Console.WriteLine("res = {0}\n",(new DateTime(1970,10,1)) + (new TimeSpan(1000000000L)))
do Console.WriteLine("res = {0}\n",(new DateTime(1970,10,1)) - (new TimeSpan(1000000000L)))
do Console.WriteLine("res = {0}\n",(new Decimal(20)) / (new Decimal(10)))
do Console.WriteLine("res = {0}\n",(new Decimal(20)) - (new Decimal(10)))
do Console.WriteLine("res = {0}\n",(new Decimal(20)) * (new Decimal(10)))
do Console.WriteLine("res = {0}\n",(new Decimal(20)) mod (new Decimal(7)))
Bugs fixed
351 F# Compiler Use of invalid format specifier such as %l in a Printf string gives a poor error message
381 F# Library input_char cause exception to be thrown
318 F# Compiler F# lets two constructors have the same name and gives error when emitting binary
321 F# Compiler compiler error reported by Greg Lee
332 F# Compiler F# reports error when a "for" variable is used within an inner closure, complaining it is mutable
333 F# Compiler Cannot hide exception declarations
252 F# Perf fsyacc parser is allocating a lot of list and option nodes
399 F# Perf Move generation of comparison and hash methods earlier (to typechecker) so that the code can be fully optimized (and inlined!!)
281 Abstract IL implement output of debug symbols for Abstract IL and bootstrapped compiler
175 F# Tools Implement error recovery in fsyacc generated parsers
Restricted operator overloading to built-in types only for the time being. This is simply an implementation incompleteness.
Added float32 and other float32-related operations to Pervasives.
Constrained Type Parameters
F# now allows type parameters to be constrained to specify the minimum functionality the instantiating type must support.
You may be familiar with constrained type parameters from elsewhere. For example, C# and .NET generics support 'subtype' constraints on generic type variables. OCaml supports structural 'object-type' constraints and an additional kind of variable known as a 'row' variable. Standard ML supports a two minor forms of constrained polymorphism in the form of record types (which must be locally resolved) and equality types.
Constrained polymorphism affects both type checking and type inference. In this release, F# supports coercion constraints (on any type variables) and overloaded operator constraints (on pseudo type variables).
Coercion constraints are of the form typar :> type, and also arise from the constructs expr :> type and pattern :> type. For example:
val throw: 'e -> unit when 'e :> System.ExceptionThe same declaration can be written using the following more convenient syntactic forms:
val throw: (_ :> System.Exception) -> unit
class C { static void SomeMethod(IComparable x) }
Then calling this with the F# code:
C.SomeMethod(x)
will induce a constraint that x is coercable to IComparable, i.e. ty :> IComparable when ty is the static type of x.
C# 2.0 and other .NET 2.0 code may use coercion constraints to specifying that a type parameter should support functionality such as IComparable. However, this pattern is not so common in F# code, where dictionaries of functionality are typically passed around by using tuples or records of function values.
Overloaded operator constraints arise when using overloaded operators +, - etc. For example, the operator + may be used on any two .NET values supporting the overloaded operator op_Addition (written static operator +(...) in C#). (They may also be used on built-in integer and floating point types, which are considered by F# to implicitly define operators such as op_Addition). Overloaded operators are generally only defined within the F# library. Overloaded operator constraints can only be placed on pseudo type variables.
(Aside: pseudo type variables are type variables that occur only within the type checking of a single file. These type variables arise primarily from the use of pseudo-functions such as overloaded operators.)
Examples
In a signature a value declaration may be annoated with constraints. The most primitive way to do this is to use a when annotation on a value declaration. We saw an example of this above. The same declaration can be written using the following more convenient syntactic forms:
val throw: 'e -> unit when 'e :> System.Exception
val throw: (_ :> System.Exception) -> unit
val throw: ('e :> System.Exception) -> unit
As with types, constraints will be inferred from the definition of a method. For example
open System.IO
let to_binary_writer s = new BinaryWriter(s)
will infer the type
val to_binary_writer: (_ :> Stream) -> BinaryWriter
That is, because the constructor for System.IO.BinaryWriter accepts any subtype of System.IO.Stream, F# has also inferred that the derived function should accept any subtype of System.IO.Stream as its argument. You could also write this explicitly using:
let to_binary_writer (s :> Stream) = new BinaryWriter(s)
Here the pattern (s :> Stream) means 's should match a value whose type can be coerced to Stream'.
Type Inference and Checking
Type inference and checking of constraints is fairly straight-forward: each use of a value or type whose specification involves constrained type parameters will induce a constraint on the actual type parameters associated with the use of that item. (Aside: each time an ML value is used a fresh set of actual type parameters is generated - for example each time you write List.length a fresh inference type parameter is implicitly used as the actual type parameter for the value.)
Constraints are solved, or partially solved, as they are generated. For example:
The following limitations currently apply:
Extensions to the Grammar for Constrained Type Parameters
The extensions to the grammar are as follows:
<val-type> :=
| <type> -- unconstrained type
| <type> when <constraints> -- constrained type
The following syntactic forms are for convenience. They imply constraints at the binding site related to the type variable (see below).
<type> :=
| <typar> :> <type> -- the same as <typar>, with an implied constraint
| <typ> when <constraints> -- constrained type
The constraints can be of the following forms:
constraint :=
| <typar> :> <typ> -- the type parameter converts to the type
| $<typar>.<method-name> : <method-type> -- overload constraint
Aside: Binding sites for type variables are inferred in the usual way for ML languages of the OCaml family. This binding site is either a value declaration, a type declaration. Inference variables will be bound at the value declaration where they are generalized, or if not generalized will have the scope of the entire file.
Extensions to the Semantics of Coercion Operators
The operator expr :> typ now means 'expr can be coerced to typ'. This includes the use of representation-changing conversions such as boxing.
Uses of Constrained Polymorphism in the F# Library
Pervasive Operators:
Overloading is supported for the following operators. The operators all default to operating over the int type should there be no other type information in the file to further constrain the use of the operator.
val (+): $a -> $b -> $a when $a.op_Addition : ($a, $b) -> $a
val (-): $a -> $b -> $a when $a.op_Subtraction : ($a, $b) -> $a
val ( * ): $a -> $b -> $a when $a.op_Multiply : ($a, $b) -> $a
val (/): $a -> $b -> $a when $a.op_Division : ($a, $b) -> $a
val (mod): $a -> $b -> $a when $a.op_Modulus : ($a, $b) -> $a
val (~-): $a -> $a when $a.op_UnaryNegation : ($a) -> $a
val (~+): $a -> $a when $a.op_UnaryPlus : ($a) -> $a
val (land): $a -> $a -> $a when $a.op_BitwiseAnd : ($a,$a) -> $a
val (lor): $a -> $a -> $a when $a.op_BitwiseOr : ($a,$a) -> $a
val (lxor): $a -> $a -> $a when $a.op_ExclusiveOr : ($a,$a) -> $a
val lnot: $a -> $a when $a.op_LogicalNot : ($a) -> $a
val (lsl): $a -> int -> $a when $a.op_LeftShift : ($a,int) -> $a
val (lsr): $a -> int -> $a when $a.op_RightShift : ($a,int) -> $a
val (asr): $a -> int -> $a when $a.op_RightShift : ($a,int) -> $a
List, Stream, Vector, Array, Set:
The following functions are for transforming F# collections to and from .NET collections and now accept coerced arguments at F# call-sites:
List.of_IEnumerable: (_ :> IEnumerable<'a>) -> 'a list
List.of_ICollection: (_ :> ICollection<'a>) -> 'a list
Array.of_IEnumerable: (_ :> IEnumerable<'a>) -> 'a[]
Array.of_ICollection: (_ :> ICollection<'a>) -> 'a[]
Vector.of_IEnumerable: (_ :> IEnumerable<'a>) -> Vector<'a>
Vector.of_ICollection: (_ :> ICollection<'a>) -> Vector<'a>
Stream.of_IEnumerable: (_ :> IEnumerable<'a>) -> Stream<'a>
Stream.of_ICollection: (_ :> ICollection<'a>) -> Stream<'a>
Idioms:
The following functions now accept coerced arguments at F# call-sites:
Idioms.foreach: (_ :> IEnumerable) -> ('a -> unit) -> unit
Idioms.foldeach: (_ :> IEnumerable) -> 'acc -> ('acc -> 'a -> 'acc) -> 'acc
Idioms.foreachG: (_ :> IEnumerable<'a>) -> ('a -> unit) -> unit
Idioms.foldeachG: (_ :> IEnumerable<'a>) -> 'acc -> ('acc -> 'a -> 'acc) -> 'acc
Idioms.using: (_ :> System.IDisposable) -> (unit -> 'a) -> 'a
Idioms.lock: (_ :> System.Object) -> (unit -> 'a) -> 'a
The following functions are now checked more strictly.
Idioms.EnumToInt: 'a -> int when 'a :> System.Enum
Idioms.IntToEnum: int -> 'a when 'a :> System.Enum
Idioms.CombineEnumFlags: 'a list -> 'a when 'a :> System.Enum
Idioms.TestEnumFlag: 'a -> 'a -> bool when 'a :> System.Enum
Fixed the following bugs:
282 fsyacc doesn't like // comments
267 interface data being attached to assemblies includes is bigger than it should be
286 NGEN of bootstrap compiler fails due to multiple mscorlib references.
291 bug in the implementation of stable_sort
292 Compiler bug - cannot find fslib library automatically
295 --standalone doesn't fold in debug symbols of the assemblies that have been read
293 alternative-install.bat gives a spurious error while loking for NGEN
296 multiple mscorlib references are appearing in --standalone assemblies (fscbng.exe)
302 VS plugin is not reloading referenced DLLs as they are recompiled (this forced users to restart VS to see changes)
303 Sys.time is returning Ticks not TotalSeconds
305 Implementing IEnumerator on .NET v2.0 beta 2 is difficult due to inclusion of parent interfaces with identical method names
Fixed a bug related to inner polymorphic closures reported by Nikolaj Bjoerner (thanks Nikolaj!)
Fixed a bug related to over-applied polymorphic functions reported by Dominic Cooney (thanks Dominic!)
Implemented intellisense for further long-name lookups in VS integration, e.g. val.field.field or val.property.field
Fixed the following bugs:
272 Fixed: AV in VS Plugin when endlessly loading & unloading large F# projects 274 Fixed: A failure "stelem" occurred when compiling a test for .NET 2003 247 Fixed: test and document hashq operator 232 Fixed: verify non-generic assemblies using v1.0 and v1.1 peverify's 223 Fixed: Change test procedure to generate config files in order to test on various versions of the clr 275 Give better error messages when passing a value to a Params C# method 276 Give better error message when a CompatArray is needed
Added another DirectX Tutorial (Tutorial 1)
Fixed installer problems on VS 2003 - Babel package was still being registered with VS 2005
Reduce size of optimization information attached to F# DLLs.
Minor fixes to the Visual Studio installer.
Minor performance improvements for the command line compiler.
Fixed this bug:
268 F# Compiler: not all type definitions were being checked for cyclic abbreviations
Fixed one bug with intellisense where extra text on the line after the cursor was interfering with intellisense. Some glitches remain in this area.
Reduced the number of match-bracket calls to improve reponsivity of VS. Some bugs remain in this area.
Minor fixes to the Visual Studio installer.
Performance improvements for the command line compiler.
Fixed minor bugs with the recent additions to MLLib.
New reserved keywords after review of keyword policy: atomic, checked, class, decimal, event, pure. In addition the existing reserved word interface is now actually used as a keyword, and will hence give errors if used in your program. The others will give warnings.
Intellisense is now supported in the Visual Studio integration. Essentially all features are complete, though incorrect or slightly misleading information is occasionally be shown, and the correct context is not always available to allow information to be shown. You can turn off Intellisense globally by setting the environment variable FSharp_NoIntellisense=1.
Extended Object Expressions are now supported. This means objects created via object expressions can support multiple interfaces, which also makes F# a CLS Extender language according to the official definition of such things. The syntax is:
{ new with
interface with
...
interface with }
e.g.
{ new Object()
with Finalize() = cleanupFunction(false);
interface IDisposable
with Dispose() = cleanupFunction(true); }
Nested modules within a top-level module are now supported, e.g.
type ident = Id of string
module Ident = struct
let OfString(s) = Id(s)
let ToString(Id(s)) = s
end
and in the interface file
type ident
module Ident : sig
val OfString: string -> ident
val ToString: ident -> string
end
The atomicity of dynamic initialization is on the granularity of top-level modules, i.e all the bindings in a top-level module are executed for side-effects if any values in the file are required.
Patterns can now refer to .NET literals.
More .NET related functionality in the ML compatibility library. Modules Float, Float32, UInt32, UInt64, Stream. A much more systematic treatment of conversions between various integer and floating point types. Conversion functions to allow MLLib collections to be used as .NET collections (ICollection etc.). More efficient implementations of some functions.
Visual Studio for .NET will now work with Visual Studio 2003. See the installation instructions elsewhere in this file.
Controlling F# for Visual Studio if it starts to misbehave. The following global environment variables can be used to selectively control some of the features of F# for Visual Studio. They can also be set within the command shell where you execute devenv.exe if you run it explicitly.
set FSharp_Logging=1
set FSharp_LoggingVerbose=1
set FSharp_NoParsing=1
set FSharp_NoChecking=1
set FSharp_NoPriorInputParsing=1
set FSharp_NoConfigBuilding=1
set FSharp_NoPriorInputTypeChecking=1
set FSharp_NoTypeChecking=1
set FSharp_NoLexing=1
set FSharp_NoIntellisense=1
Documentation:
-- Revised grammar documentation in manual -- Revised interop decumentation in manual
Various bug fixes:
The following bugs were recorded as fixed in the F# bug database:
_ F# Compiler Implement setting of fields and properties on .NET value types for the simpe cases of mutable locals and byref arguments 196 F# Compiler Poor error message for signature mismatch when an abbreviation is hidden 211 F# Compiler too many long paths printed when using -i 204 F# Compiler fsyacc: newline missing 200 F# Compiler Newline or similar needed between errors 197 F# Compiler Can access hidden constructors and fields using long path names 137 F# Compiler Implement accessing generic methods 210 F# Compiler --standalone bug for winforms reported on f# list 259 F# Compiler Fixed a bug with generalizing variables: not all generalized type variables were being marked as rigid 255 F# Compiler The representation of discriminated unions that uses static fields and unique objects for unary constructors does not work for deserialized data 263 F# Compiler X-module optimization bug related to incorrectly fixed-up optimization data 183 F# Compiler Error messages from failed overloading can be poor (e.g. Text3D sample) 187 F# Compiler Error message when attempting to access a protected method from outside a subclass needs work 218 F# Compiler Add error when module name declaration is missing from intf or impl when filenames match e.g a.ml & a.mli 227 F# Compiler Signature checking of modules should be able to unify inference type variables 242 F# Language support #else in #if/#endif 194 F# Library Ensure float32, float etc. and other conversions are all complete and orthogonal in MLLib 249 F# Library Sys.time not correctly implemented 256 F# Library Added functions to Set, List and Stream to relate MLLib collections to .NET collections 206 F# Documentation export interop documentation needs work 212 F# Documentation Add 'differentiate' and other samples to the sdk 260 F# Documentation Update docs in parsing sample to reflect the presence of fsyacc and fslex 231 F# Visual Studio Plugin 'UncontrolledError' appears in error box when using VS 261 F# Release Visual studio mode fails to install if user has never started up visual studio since installing it
Various bug fixes: 33 26/11/2004 Abstract IL Generic constraints not correctly read/emitted in binary reader/writer 157 26/11/2004 F# VS VS should take into account the include path 180 02/12/2004 F# Compiler Private constructors may be visible to importing modules 185 10/12/2004 F# VS Problem when loading a F# project where a file did not exist 193 10/12/2004 F# Compiler Abstract IL and F# bug: errors when accessing fiels and methods where types have custom attributes 192 10/12/2004 F# Compiler upcasting from .NET array types to object reported a bogus warning about boxing, 191 10/12/2004 F# Compiler Errors are not reported at right location when argument types are wrong 186 10/12/2004 F# Language Cannot access protected methods on .NET objects 178 19/11/2004 F# Compiler Declaring a field of a given name blocks out any ability to access members of that name regardless of type annotations 177 19/11/2004 F# Compiler Some value recursive declarations incorrectly being labelled as "recursive data"
1. New compiler switches:
--all-warnings: Print all warnings.
--no-warnings: Do not print any warnings.
--warn <int>: Report the given specific warning.
--no-warn <int>: Do not report the given specific warning.
--all-warnings-as-errors: Treat all warnings as errors.
--warn-as-error <int>: Treat the given specific warning as an error.
Warning numbers are printed as part of error messages and the less obvious
ones will have further documentation in the manual including links to tutorials.
2. Better and fewer error messages for uses of value recursion.
3. Fixed a number of bugs:
- Pretty much all uses of data constructors within value recursion declarations were incorrectly
being labelled as "direct recursion" instead of "value recursion".
- Field lookup was preferring ML-style field lookup over adhoc-name field lookup based on
inferred type. This meant that declaring an F# field such as "Text" anywhere in your
program meant that no adhoc lookup on "Text" would ever be resolved.
- Type information was not being propagated correctly from outside-in for "let rec" bindings.
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 "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<int>.Cons(3,null)
Option<int>.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<int> x = List<int>.Cons(3,(List<int>.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<A,B>. This
will not change, though the details of the implementation of the
Microsoft.FSharp.FastFunc class may be revised. FastFunc<A,B> 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<A,B> 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<T,U> f) producing FastFunc<T,U>
...(System.Action<T> f) producing FastFunc<T,object>
...(System.Predicate f) producing FastFunc<T,bool>
Additionally, there is an implicit conversion from System.Converter<T,U> to FastFunc<T,U>,
and thus you can omit the call to FuncConvert.ToFastFunc() but ONLY when reating a delegate
of type System.Converter<A,B> (for some A,B).
For example, the following are equivalent:
List.map(FuncConvert.ToFastFunc((Converter<int,string>) delegate(int x)
{ return x.ToString() + x.ToString(); }),
myList);
and
List.map((Converter<int,string>) 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,A2>(A1 x, A2 y);
delegate void System.Action<A1,A2,A3>(A1 x, A2 y,A3 z);
delegate B System.Converter<A1,A2,A3,B>(A1 x, A2 y,A3 z);
and Microsoft.FSharp.FuncConvert.ToFastFunc(...) method supports
the following overloads that produce "curried" functions:
ToFastFunc(System.Converter<A1,B> f) producing 'A1 -> B', i.e. FastFunc<A1,B>
ToFastFunc(System.Converter<A1,A2,B> f) producing 'A1 -> A2 -> B', i.e. FastFunc<A1,FastFunc<A2,B>>
ToFastFunc(System.Converter<A1,A2,A3,B> f) producing 'A1 -> A2 -> A3 -> B', i.e. FastFunc<A1,FastFunc<A2,FastFunc<A3,B>> >
ToFastFunc(System.Action<A1> f) producing 'A1 -> unit', i.e. FastFunc<A1,object>
ToFastFunc(System.Action<A1,A2> f) producing 'A1 -> A2 -> unit', i.e. FastFunc<A1,FastFunc<A2,object> >
ToFastFunc(System.Action<A1,A2,A3> f) producing 'A1 -> A2 -> A3 -> unit', i.e. FastFunc<A1,FastFunc<A2,FastFunc<A3,object> > >
For example:
using System;
using Microsoft.FSharp;
using Microsoft.FSharp.MLLib;
List<int> myList = List.of_array(new int[] { 4, 5, 6 });
string joined =
List.fold_right<int,string>
(FuncConvert.ToFastFunc((Converter<int,string,string>) 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<A1,B> f) producing 'A1 -> B', i.e. FastFunc<A1,B>
ToTupledFastFunc(System.Converter<A1,A2,B> f) producing 'A1 * A2 -> B', i.e. FastFunc<A1,FastFunc<A2,B>>
ToTupledFastFunc(System.Converter<A1,A2,A3,B> f) producing 'A1 * A2 * A3 -> B', i.e. FastFunc<A1,FastFunc<A2,FastFunc<A3,B>> >
ToTupledFastFunc(System.Action<A1> f) producing 'A1 -> unit', i.e. FastFunc<A1,object>
ToTupledFastFunc(System.Action<A1,A2> f) producing 'A1 * A2 -> unit', i.e. FastFunc<A1,FastFunc<A2,object> >
ToTupledFastFunc(System.Action<A1,A2,A3> f) producing 'A1 * A2 * A3 -> unit', i.e. FastFunc<A1,FastFunc<A2,FastFunc<A3,object> > >
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 ML'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 <expr> finally <expr> -- always execute an exit block, even if an exception occurs
topdecl := ...
| module <long-identifier> -- specify the namespace/class for the generated bindings
| do <expr> -- execute the given expression
bindings := ...
| do <expr> -- 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 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 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.fsi 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.