The F# 2.

0 Language Specification (April 2010)
Note: This documentation is a release candidate of the specification of the 2.0 release of F# made by Microsoft Research and the Microsoft Developer Division in April 2010. Discrepancies may exist between this specification and the 2.0 implementation. Some of these are noted as comments in this document. If you find further discrepancies please contact us and we will gladly address the issue in future releases of this specification. The F# team is always very grateful for feedback on this specification, and on both the design and implementation of F#. You can submit feedback by emailing fsbugs@microsoft.com. The latest version of this specification can be found at www.fsharp.net. Many thanks to the F# user community for their helpful feedback on the document so far. Certain parts of this specification refer to the C# 4.0, Unicode, and IEEE specifications. Authors: Don Syme, with assistance from Anar Alimov, Jomo Fisher, Michael Hale, Luke Hoban, Dmitry Lomov, James Margetson, Brian McNamara, Joe Pamer, Penny Orwick, Daniel Quirk, Chris Smith, Matteo Taveggia and others. Notice © 2005-2010 Microsoft Corporation. All rights reserved. Microsoft, Windows, and Visual F# are either registered trademarks or trademarks of Microsoft Corporation in the U.S.A. and/or other countries/regions. Other product and company names mentioned herein may be the trademarks of their respective owners. Document Updates: Updated with glossary, index and style corrections, August 2010

1

Table of Contents
1 1.1 INTRODUCTION .....................................................................................................................................................10 A FIRST PROGRAM......................................................................................................................................................... 10 Lightweight Syntax ........................................................................................................................................................ 10 Making Data Simple ...................................................................................................................................................... 11 Making Types Simple ..................................................................................................................................................... 11 Functional Programming ............................................................................................................................................... 12 Imperative Programming .............................................................................................................................................. 13 .NET Interoperability and CLI Fidelity ............................................................................................................................ 13 Parallel and Asynchronous Programming ..................................................................................................................... 13 Stronger Typing for Floating-Point Code ....................................................................................................................... 14 Object-Oriented Programming and Code Organization ................................................................................................ 15 1.2 2 3 3.1 3.2 3.3 3.4 3.5 3.6 3.7 3.8 NOTATIONAL CONVENTIONS IN THIS SPECIFICATION .............................................................................................................. 16 PROGRAM STRUCTURE..........................................................................................................................................18 LEXICAL ANALYSIS .................................................................................................................................................20 WHITESPACE ................................................................................................................................................................ 20 COMMENTS ................................................................................................................................................................. 20 CONDITIONAL COMPILATION ............................................................................................................................................ 20 IDENTIFIERS AND KEYWORDS ............................................................................................................................................ 21 STRINGS AND CHARACTERS .............................................................................................................................................. 22 SYMBOLIC KEYWORDS .................................................................................................................................................... 23 SYMBOLIC OPERATORS ................................................................................................................................................... 24 NUMERIC LITERALS ........................................................................................................................................................ 24 3.8.1 3.8.2 3.8.3 3.9 3.10 3.11 4 4.1 4.2 4.3 4.4 Post-filtering of Adjacent Prefix Tokens ......................................................................................................... 25 Post-filtering of Integers Followed by Adjacent “..” ....................................................................................... 26 Reserved Numeric Literal Forms .................................................................................................................... 26 HIDDEN TOKENS ...................................................................................................................................................... 26 IDENTIFIER REPLACEMENTS ......................................................................................................................................... 26

LINE DIRECTIVES ............................................................................................................................................................ 26

BASIC GRAMMAR ELEMENTS.................................................................................................................................28 OPERATOR NAMES ........................................................................................................................................................ 28 LONG IDENTIFIERS ......................................................................................................................................................... 30 CONSTANTS ................................................................................................................................................................. 30 OPERATORS AND PRECEDENCE.......................................................................................................................................... 31 4.4.1 4.4.2 Categorization of Symbolic Operators ........................................................................................................... 31 Precedence of Symbolic Operators and Pattern/Expression Constructs ........................................................ 32

5 5.1

TYPES AND TYPE CONSTRAINTS .............................................................................................................................34 CHECKING SYNTACTIC TYPES ............................................................................................................................................ 35 5.1.1 5.1.2 5.1.3 5.1.4 5.1.5 Named Types ................................................................................................................................................. 36 Variable Types ............................................................................................................................................... 36 Tuple Types .................................................................................................................................................... 36 Array Types .................................................................................................................................................... 37 Constrained Types ......................................................................................................................................... 37

2

5.2

TYPE CONSTRAINTS ........................................................................................................................................................ 37 5.2.1 5.2.2 5.2.3 5.2.4 5.2.5 5.2.6 5.2.7 5.2.8 5.2.9 5.2.10 Subtype Constraints ....................................................................................................................................... 37 Nullness Constraints ...................................................................................................................................... 38 Member Constraints ...................................................................................................................................... 38 Default Constructor Constraints .................................................................................................................... 39 Value Type Constraints .................................................................................................................................. 39 Reference Type Constraints ........................................................................................................................... 39 Enumeration Constraints ............................................................................................................................... 39 Delegate Constraints ..................................................................................................................................... 39 Unmanaged Constraints ................................................................................................................................ 40 Equality and Comparison Constraints ............................................................................................................ 40

5.3 5.4

TYPE PARAMETER DEFINITIONS ......................................................................................................................................... 41 LOGICAL PROPERTIES OF TYPES ......................................................................................................................................... 41 5.4.1 5.4.2 5.4.3 5.4.4 5.4.5 5.4.6 5.4.7 5.4.8 5.4.9 5.4.10 Characteristics of Type Definitions ................................................................................................................ 41 Expanding Abbreviations and Inference Equations ....................................................................................... 42 Type Variables and Binding ........................................................................................................................... 43 Base Type of a Type ....................................................................................................................................... 43 Interfaces Types of a Type ............................................................................................................................. 43 Type Equivalence ........................................................................................................................................... 44 Subtyping and Coercion ................................................................................................................................. 44 Nullness ......................................................................................................................................................... 44 Default Initialization ...................................................................................................................................... 45 Dynamic Conversion Between Types ............................................................................................................. 46

6 6.1 6.2 6.3

EXPRESSIONS ........................................................................................................................................................47 SOME CHECKING AND INFERENCE TERMINOLOGY .................................................................................................................. 49 ELABORATION AND ELABORATED EXPRESSIONS ..................................................................................................................... 50 DATA EXPRESSIONS ........................................................................................................................................................ 51 6.3.1 6.3.2 6.3.3 6.3.4 6.3.5 6.3.6 6.3.7 6.3.8 6.3.9 6.3.10 6.3.11 6.3.12 6.3.13 6.3.14 6.3.15 6.3.16 6.4 6.4.1 6.4.2 6.4.3 6.4.4 Simple Constant Expressions ......................................................................................................................... 51 Tuple Expressions .......................................................................................................................................... 52 List Expressions .............................................................................................................................................. 53 Array Expressions .......................................................................................................................................... 53 Record Expressions ........................................................................................................................................ 53 Copy-and-update Record Expressions............................................................................................................ 55 Function Expressions ..................................................................................................................................... 55 Object Expressions ......................................................................................................................................... 56 Delayed Expressions ...................................................................................................................................... 57 Computation Expressions .............................................................................................................................. 57 Sequence Expressions .................................................................................................................................... 62 Range Expressions ......................................................................................................................................... 62 Lists via Sequence Expressions ....................................................................................................................... 63 Arrays via Sequence Expressions ................................................................................................................... 63 Null Expressions ............................................................................................................................................. 64 'printf' Formats .............................................................................................................................................. 64 Basic Application Expressions ........................................................................................................................ 65 Object Construction Expressions .................................................................................................................... 66 Operator Expressions ..................................................................................................................................... 67 Late Binding Operator Expressions ................................................................................................................ 68 3

APPLICATION EXPRESSIONS .............................................................................................................................................. 65

6.4.5 6.4.6 6.4.7 6.4.8 6.4.9 6.5 6.5.1 6.5.2 6.5.3 6.5.4 6.5.5 6.5.6 6.5.7 6.5.8 6.5.9 6.5.10 6.5.11 6.5.12 6.6 6.6.1 6.6.2 6.6.3 6.7 6.7.1 6.7.2 6.7.3 6.7.4 6.8 6.8.1 6.8.2 6.8.3 6.9 6.9.1 6.9.2 6.9.3 6.9.4 6.9.5 6.9.6 6.9.7 6.9.8 6.9.9 6.9.10 6.9.11 6.9.12 6.9.13 6.9.14 6.9.15 6.9.16 6.9.17

The AddressOf Operators .............................................................................................................................. 68 Lookup Expressions ........................................................................................................................................ 69 Slice Expressions ............................................................................................................................................ 70 Member Constraint Invocation Expressions .................................................................................................. 70 Assignment Expressions................................................................................................................................. 71 Parenthesized and Block Expressions ............................................................................................................ 72 Sequential Execution Expressions .................................................................................................................. 72 Conditional Expressions ................................................................................................................................. 73 Shortcut Operator Expressions ...................................................................................................................... 73 Pattern-Matching Expressions and Functions ............................................................................................... 73 Sequence Iteration Expressions ..................................................................................................................... 74 Simple for-Loop Expressions .......................................................................................................................... 75 While Expressions .......................................................................................................................................... 75 Try-with Expressions ...................................................................................................................................... 75 Reraise Expressions........................................................................................................................................ 76 Try-finally Expressions ................................................................................................................................... 76 Assertion Expressions .................................................................................................................................... 76 Binding Expressions ....................................................................................................................................... 76 Recursive Binding Expressions. ...................................................................................................................... 78 Deterministic Disposal Expressions ................................................................................................................ 79 Type-Annotated Expressions ......................................................................................................................... 79 Static Coercion Expressions ........................................................................................................................... 79 Dynamic Type-Test Expressions ..................................................................................................................... 80 Dynamic Coercion Expressions....................................................................................................................... 80 Strongly Typed Quoted Expressions ............................................................................................................... 81 Weakly Typed Quoted Expressions ................................................................................................................ 81 Expression Splices .......................................................................................................................................... 82 Values and Execution Context ....................................................................................................................... 83 Zero Values .................................................................................................................................................... 84 Taking the Address of an Elaborated Expression ........................................................................................... 84 Evaluating Value References ......................................................................................................................... 85 Evaluating Function Applications .................................................................................................................. 85 Evaluating Method Applications.................................................................................................................... 85 Evaluating Union Cases ................................................................................................................................. 85 Evaluating Field Lookups ............................................................................................................................... 86 Evaluating Active Pattern Results .................................................................................................................. 86 Evaluating Array Expressions ......................................................................................................................... 86 Evaluating Record Expressions ...................................................................................................................... 86 Evaluating Function Expressions.................................................................................................................... 86 Evaluating Object Expressions ....................................................................................................................... 86 Evaluating Binding Expressions ..................................................................................................................... 86 Evaluating For Loops ..................................................................................................................................... 86 Evaluating While Loops ................................................................................................................................. 87 Evaluating Static Coercion Expressions.......................................................................................................... 87 4

CONTROL FLOW EXPRESSIONS .......................................................................................................................................... 72

BINDING EXPRESSIONS .................................................................................................................................................... 76

TYPE-RELATED EXPRESSIONS ............................................................................................................................................ 79

QUOTED EXPRESSIONS .................................................................................................................................................... 80

EVALUATION OF ELABORATED FORMS ................................................................................................................................ 82

6.9.18 6.9.19 6.9.20 6.9.21 6.9.22 6.9.23 6.9.24 7 7.1

Evaluating Dynamic Type-Test Expressions ................................................................................................... 87 Evaluating Dynamic Coercion Expressions ..................................................................................................... 87 Evaluating Sequential Execution Expressions ................................................................................................ 88 Evaluating Try-with Expressions .................................................................................................................... 88 Evaluating Try-finally Expressions ................................................................................................................. 88 Evaluating AddressOf Expressions ................................................................................................................. 88 Values with Underspecified Object Identity and Type Identity ...................................................................... 89

PATTERNS .............................................................................................................................................................90 PATTERN FORMS ........................................................................................................................................................... 91 7.1.1 7.1.2 7.1.3 7.1.4 7.1.5 7.1.6 7.1.7 7.1.8 7.1.9 7.1.10 7.1.11 7.1.12 7.1.13 7.1.14 7.1.15 7.1.16 Simple Constant Patterns .............................................................................................................................. 91 Named Patterns............................................................................................................................................. 91 Union Case Patterns ...................................................................................................................................... 92 Literal Patterns .............................................................................................................................................. 92 Active Patterns .............................................................................................................................................. 93 “As” Patterns ................................................................................................................................................. 95 Wildcard Patterns .......................................................................................................................................... 95 Disjunctive Patterns ....................................................................................................................................... 95 Conjunctive Patterns...................................................................................................................................... 95 “Cons” and List Patterns ................................................................................................................................ 95 Type Annotated Patterns ............................................................................................................................... 96 Dynamic Type-Test Patterns .......................................................................................................................... 96 Record Patterns ............................................................................................................................................. 96 Array Patterns ............................................................................................................................................... 97 Null Patterns .................................................................................................................................................. 97 Guarded Pattern Rules................................................................................................................................... 97

8 8.1 8.2 8.3 8.4

TYPE DEFINITIONS .................................................................................................................................................98 TYPE DEFINITION GROUP CHECKING AND ELABORATION ....................................................................................................... 102 TYPE KIND INFERENCE .................................................................................................................................................. 104 TYPE ABBREVIATIONS ................................................................................................................................................... 104 RECORD TYPE DEFINITIONS ............................................................................................................................................ 105 8.4.1 8.4.2 8.4.3 8.5 8.5.1 8.5.2 8.5.3 8.6 8.6.1 8.6.2 8.6.3 8.6.4 8.6.5 8.7 8.8 8.9 8.10 Members in Record Types............................................................................................................................ 106 Name Resolution and Record Field Labels ................................................................................................... 106 Structural Hashing, Equality, and Comparison for Record Types ................................................................. 106 Members in Union Types ............................................................................................................................. 107 Structural Hashing, Equality, and Comparison for Union Types .................................................................. 107 Compiled Form of Union Types for Use from Other CLI Languages ............................................................. 107 Primary Constructors in Classes ................................................................................................................... 108 “let” and “do” Declarations in Primary Constructors................................................................................... 109 Members in Classes ..................................................................................................................................... 111 Additional Object Constructors in Classes.................................................................................................... 111 Additional Fields in Classes .......................................................................................................................... 112

UNION TYPE DEFINITIONS ............................................................................................................................................. 106

CLASS TYPE DEFINITIONS ............................................................................................................................................... 108

INTERFACE TYPE DEFINITIONS ......................................................................................................................................... 113 STRUCT TYPE DEFINITIONS ............................................................................................................................................. 114 ENUM TYPE DEFINITIONS .............................................................................................................................................. 115 DELEGATE TYPE DEFINITIONS .................................................................................................................................... 116

5

....... 133 Behavior of the Generated Object............................................................ 127 Abstract Members ............................3 8............................................... 140 MEASURE PARAMETER ERASURE......................... and compare ............. 145 “let” Bindings in Modules .. =.............13................................................................................2 9................................ 145 Literal Definitions in Modules ..4 10......................................................................5 10............................................. AND COMPARISON ....................13.....................................13.......................................... 137 MEASURES..... 147 “do” Bindings in Modules ..............................................................................1 8.......................................................4 9....................................10 8.........................................................................15.................................................1 8..................................... 135 Behavior of the Generated GetHashCode Implementations ........................................ 148 ACCESSIBILITY ANNOTATIONS .... 120 Method Members ............... 121 Curried Method Members ....................2 8.....14...................................................................................................6 9............8........5 9..........................3................3...................................................................................................................13.................................... 135 ABSTRACT MEMBERS AND INTERFACE IMPLEMENTATIONS ............................................................................................................................................1 8............................................................................13...........................................................14....... 135 Behavior of hash........... 122 Optional Arguments to Method Members ......................................................................................................................................................................................... 143 MODULE DEFINITIONS .............................................8 8.... 124 Overloading of Methods ........................ 134 Behavior of the Generated CompareTo Implementations ............................2 9...........................................1 10.......................................................................................................13..3 10...............................2....... 116 TYPE EXTENSIONS .........................................................................................15 8......... 139 9........................................2.........12................................2 8......................................1 9.................................................................................................5 8.........................4 8......................... 117 Imported C# Extensions Members .Equals Implementation ....................................................................................................................15.... 126 Members Represented as Static Members ..................................................................................................................2............................................................................................................ 146 Type Function Definitions in Modules ..........1 8.........................................4 10........................................................................................................................................................................................2 10..................................................................................6 9 9...................................... 141 TYPE DEFINITIONS WITH MEASURES IN THE F# CORE LIBRARY.....9 EXCEPTION DEFINITIONS ............................................15..............................................................................................11 8...........................................13 8.................. 132 Comparison Attributes ..........................3 8...........3 10......................................... 121 Named Arguments to Method Members ...........7 Constraint solving ............................... HASHING............12 8......................7 8.........................5 10.........................3 8..................................... 127 Members Implementing Abstract Members .......................................................................................................................................................................... 143 10 10.........13.........................................3 UNITS OF MEASURE .......................13................................................................................................5 8...................................................................................................................................... 119 Property Members ....6 8..................................................................................................................................................................................................................................1 10.......... 118 MEMBERS ................... 125 Naming Restrictions for Members .................................13.................................................. 149 6 ..............................2..............................13..........1 NAMESPACE DECLARATION GROUPS ..................................... 127 8. 148 MODULE ABBREVIATIONS ..................... 147 Active Pattern Definitions in Modules ..................................................................................................................................................... 149 Permitted Locations of Accessibility Modifiers ............................ 128 Interface Implementations ...................................... 123 Type-directed Conversions at Member Invocations ......................................................15...... 125 Members Represented as Events ............................................................................................................2 10......................4 8............................ 139 RELATIONS ON MEASURES ......................................................................................14.......15...........................2 8....................................................... 141 NAMESPACES AND MODULES .....................................................................................5............................................... 138 CONSTANTS ANNOTATED BY MEASURES ... 140 Generalization of Measure Variables ................. 148 IMPORT DECLARATIONS ...........1 9.............. 140 MEASURE DEFINITIONS ........................................................................................................................ 130 EQUALITY.............................. 140 MEASURE PARAMETER DEFINITIONS .........14 8...................................... 131 Equality Attributes ............................................................................................................................................................................................................................15.............2...

........................................................................................................................................................... 171 Name Resolution for Type Variables .....................................................................................................................................................................1........................................................... 167 Name Resolution for Members ....................................................1 14........................................................................................................................................................1........5.4 14........................................................ 176 FUNCTION APPLICATION RESOLUTION ..............1 13............................. 156 12........................................1...................................2...................... 155 12 PROGRAM STRUCTURE AND EXECUTION ...............5................................................................................................................................................................. 153 Signature Conformance for Values ......................................................................................................1 14...................................2............................................................................................................... 166 Name Environments .........................................................................2 SIGNATURE ELEMENTS............................................2.............................................................1.........................1 11................. 167 Name Resolution in Expressions ...............2..........................................................................................1 14............... 188 CHECKING AND ELABORATING BINDINGS ......... 183 Implicit Insertion of Flexibility for Uses of Values and Members ...................................5 12.....................................................1....................................................................................................................................................................................... 185 Solving Subtype Constraints ... Struct and Other Simple Constraints .........................1 14............................................................................................................... 184 Solving Equational Constraints ............... 164 REFLECTED FORMS OF DECLARATION ELEMENTS ......................... 187 Over-constrained User Type Annotations ..............................2 14...............3 14.....................................................1.......................4 14.........................1....................4.............................................................................6 14...1.....................................2 14.......................................................................1....................................................5.................................................... 178 METHOD APPLICATION RESOLUTION ................................................................................... 163 13............................................................................................................................................................................................................1 12.6 NAME RESOLUTION ..........................................1.......................................2 14. 183 CONSTRAINT SOLVING ................... 160 Execution of Static Initializers ..........................................3 14.......... 188 7 ............................................................4 14......................1..........................................................4...................................................... 173 Unqualified Lookup .....2 11................................9 14........ 186 Solving Member Constraints................ 160 Explicit Entry Point ..........................3 12..............................................................................................5.......................................5................................ 174 Item-Qualified Lookup .............................................................................................................. 185 Solving Nullness...........................3 14....2 14................1 12..................................................................5 14........ 170 Name Resolution for Types ...................................................2 IMPLEMENTATION FILES ............3 14.......2 12........5 14..........................................3 11.................................................2 CUSTOM ATTRIBUTES .................................... 166 Name Resolution in Module and Namespace Paths ...............1.... 159 PROGRAM EXECUTION.. 158 SCRIPT FILES .........................................................................................................................1 14...................2 11........................................................ 165 14 INFERENCE PROCEDURES ........................................................... 172 Opening Modules and Namespace Declaration Groups ...............................................................................1 11.................................................................4 12......................................................................................................................................................................................................5...... 152 Member Signatures ................. 152 Type Definition Signatures ....................................................................................... 153 Signature Conformance for Members .................................................5 14...................................................................................................... 166 14..... 162 13 CUSTOM ATTRIBUTES AND REFLECTION ...................................................................1...........................................................................................................................................................................2 14....................................................................... 174 Expression-Qualified Lookup...8 14.... 151 11..................................................................................7 14.....................................5................................ 163 Custom Attributes and Signatures ................................ 158 COMPILER DIRECTIVES .. 172 RESOLVING APPLICATION EXPRESSIONS ........... 172 Field Label Resolution .......................... 178 Conditional Compilation of Member Calls .................................... 157 SIGNATURE FILES ...............................................1 13.................................. 170 Name Resolution in Patterns ............................1 11.........................2............................................................................................. 152 Value Signatures ................... 153 SIGNATURE CONFORMANCE............................................................................11 NAMESPACE AND MODULE SIGNATURES ...........................

...... 190 Processing Member Definitions .............................................................................................................................11 15 Ambiguities in Bindings ...................................................................................... 199 ADDITIONAL CONSTRAINTS ON CLI METHODS ..................................1...................................1..........7 15............................1..... 207 Permitted Undentations .................... 202 15...........................6.....................................................................7 BASIC TYPES (MICROSOFT................................................... 203 Offside Lines ..........................................................................................................................................1............................2........1 15..... 210 LEXICAL ANALYSIS OF TYPE APPLICATIONS ..............2 16.........1............9 14......................................... 204 The Pre-Parse Stack ...............................................................................................1......... 224 Math Operators .............................................1 17..............................6 14...................4 14..........................2.1...2......................2 17.....8 14............14.........................................................2................. 219 17 THE F# LIBRARY FSHARP.........................................................................................................3 16...............1..................DLL ..........................................6 15................................. 211 16 SPECIAL ATTRIBUTES AND TYPES ... 197 DISPATCH SLOT CHECKING ............................................................................................................................................................ 221 Basic Types that Accept Unit of Measure Annotations ............................................................................................... 209 HIGH PRECEDENCE APPLICATION ......................................................................... 218 Custom Attributes Not Recognized by F# ...........................................................................................3 15..................................................................................4 17........................ 190 Recursive Safety Analysis .......................................1 15....................................................... 223 Generic Equality and Comparison Operators......1 17................. 198 BYREF SAFETY ANALYSIS ..............................................................................................................................1.....................................................................10 15.....................CORE........... 202 Inserted Tokens............9 15..................................... 225 Object Transformation Operators .............................. 190 Processing Recursive Groups of Bindings ........................................5 17....................................................................... 223 Bitwise Operators ........ 191 Generalization ..... 225 8 .................5 15........................................................................................................1...................................................................1..................................... 206 Exceptions to the Offside Rules....FSHARP......................................................1.................................2.........2 15.........................2.................................6...................1.............................. Token Insertions.................................................................3 14.................8 15....................................................................................... 204 Full List of Offside Contexts....................................................................FSHARP..............2 17..........................................4 15....................................................................................................................................................8 14..............................................7 14...1 16................................................................................................ 202 Basic Lightweight Syntax Rules by Example .......6................................. 205 Balancing Rules ..............................................................................6..................... 218 EXCEPTIONS THROWN BY F# LANGUAGE PRIMITIVES ...................6 17..................................................................... 225 The typeof and typedefof Operators ..................................... 188 Mutable Bindings..............1.................1............................6...................................6.............................. 222 nativeptr<_> ....................6............................................................................................ 212 16............................................................................................. 223 Basic Arithmetic Operators ....................................................................................................................... 212 Custom Attributes Emitted by F# ......................................................................7 14.......................................................................................... and Closing Contexts .......................................................OPERATORS) ................................................................................................6............................1...............3 LIGHTWEIGHT SYNTAX ..................... 203 Grammar Rules Including Inserted Tokens ...................................................2 14........9 14.................3 17..............................2 17................ 221 17..................................................................................................................................................2 Custom Attributes Recognized by F# .................................................................................................CORE) ............................. 189 Processing Value Definitions...........................................................................................5 14..CORE.......................................................................................................................................................................................1 17............................................ 201 LEXICAL FILTERING ................................... 222 BASIC OPERATORS AND FUNCTIONS (MICROSOFT...................................................................... 221 Basic Type Abbreviations ...... 189 Processing Function Definitions ...........................6...................... 195 DISPATCH SLOT INFERENCE ................2 15...10 14...... 224 Function Pipelining and Composition Operators ......................................1 14................ 198 ARITY INFERENCE ...............................2............ 206 Offside Tokens................................. 193 Condensation of Generalized Types ......................3 17.............

.................................................................................... 232 GLOSSARY ....6 17......................10 17.8 17...............................................................................1 18 FEATURES FOR ML COMPATIBILITY .........................1 18....11 17..................... 226 CHECKED ARITHMETIC OPERATORS ..... 226 Exception Operators ................................................................................ 231 18..............................................................................................................................3 17............................ 229 REFLECTION .........4... 232 File Extensions and Lexical Matters ..................................... 229 ASYNCHRONOUS COMPUTATIONS (ASYNC) ..................................................................................................................... 227 LIST AND OPTION TYPES ..............................................................................................................17....................................................................................................... 230 17...........................................................................................................................................................1 17.............................................................................................. 231 Extra Operators ..................... 226 Overloaded Conversion Functions ................................. 233 INDEX ...................................................................................4 Conditional Compilation for ML Compatibility ........ 229 IMMUTABLE COLLECTION TYPES (MAP............................................. 228 The List Type .......................... 228 LAZY COMPUTATIONS (LAZY) ............................................................... 229 TEXT FORMATTING (PRINTF) ..............................................................................................................11 17...................................................................................................................9 17................................................2 18...9 17...................................................................................................................................................................8 17..............................................2.......................................................................................................................................13 Pair Operators ........ 231 Extra Syntactic Forms for ML Compatibility..................................... 226 Input/Output Handles .....3 18..... 245 9 ....................... 228 The Option Type....4......4 17........................................................................ 229 NATIVE POINTER OPERATIONS ........ SET) ...................................................................................................2..... 229 QUOTATIONS ...................................................................................................................................................... 230 Stack Allocation ..13............................................................................................................2.................................................................................. 229 AGENTS (MAILBOXPROCESSOR) ...............................1.....................................................................................................5 17...................1.................1.................2 17......10 17...................................................................................................................................................................12 17..................1........................2.................................................................................................................................................................................................7 17..................................................................... 229 EVENT TYPES ......................................

. efficiently executing functional/imperative/object-oriented programming language. 1.p1) / 0. The lines of the sample program in the previous section form a sequence of declarations and are aligned on the same column. consider the following program: let numbers = [ 1 .05) let p2 = f (x + 0.05) let p2 = f (x + 0.fs.p1) / 0. 10 .1 Introduction F# is a scalable. For example.map square numbers printfn "N^2 = %A" squares To explore this program.0. An example of incorrect alignment of code follows: let computeDerivative f x = let p1 = f (x . F# was partly inspired by the OCaml language and shares some common core constructs with it.05) (p2 . describing some important aspects of F# along the way. 10 ] let square x = x * x let squares = List.map square numbers printfn "N^2 = %A" squares Lightweight syntax extends to all the major constructs of the F# syntax.fsx. It aims to be the premier typed functional programming language for the .1 A First Program Over the next few sections.1 The use of lightweight syntax is the default for all F# code in files with extension .05) (p2 . type-safe. we will look at some small F# programs.1 The following is correctly aligned: let computeDerivative f x = let p1 = f (x . Manually invoke the F# command line compiler fsc. As an introduction to F#.exe. succinct. type-inferred. Use F# Interactive. the two lines in the following code are two separate declarations: let squares = List. .NET framework and other implementations of the Ecma 335 Common Language Infrastructure (CLI) specification.. you can:    Compile it as a project in a development environment such as Visual Studio.fsi and . Lightweight Syntax The F# language uses simplified. indentation-aware syntactic constructs known as lightweight syntax.0. the dynamic compiler that is part of the F# distribution.fsscript.

and immutable data is inherently thread safe. x. For example. > let concat (x : string) y = x + y. "text"). which squares its input. Making Types Simple The next line of the sample program defines a function called square. In many languages. To define a tuple. Immutability means that once a value is created and given a name. 'o'. and indeed most things in F# are immutable by default. val it : int * string * int = (42. occasionally you do have to provide explicit type annotations in F# code. val concat : string -> string -> string 11 . without introducing a new type. 'e'. 'u'] > ['a'] @ vowels.ToString(). the value associated with that name cannot be changed. That last thing evaluated in an F# function body is the return value.. however. you need to create a named type. 'u'. let numbers = [1 . From the function signature. false. "42". Some operatorsrelated to lists include :: to add an item to the front of a list and @ to concatenate two lists. 'u']. separate the individual components with commas. let square x = x * x Most statically-typed languages require that you specify type information for a function declaration.. val getNumberInfo : int -> int * string * int > getNumberInfo 42. However. Though F# can typically infer types on your behalf. and sequence expressions. Many primitive types support the multiplication (*) operator (such as byte.. 'o'. > let tuple = (1. val tuple : int * bool * string = (1. a type of data used extensively in functional programming. x * x). 'i'. F# infers the type int (a signed 32-bit integer) by default. F# knows that square takes a single parameter named x and that the function returns x * x.. false. to tell the compiler the type of the input. options.Making Data Simple The first line in our sample simply declares a list of numbers one through ten. A tuple allows you to keep things organized by grouping related values together. if you want to pass around a group of related values as a single entity. val it: char list = ['a'. 'i'. Tuples and lists are some of the many types in F# that are immutable. unions. uint64 and double). Immutability has many benefits: it prevents many classes of bugs. for arithmetic operations. hence there is no ―return‖ keyword here.. A tuple is an ordered collection of values that is treated as an atomic unit. 'u'] > vowels @ ['y']. "text") > let getNumberInfo (x : int) = (x. val vowels: char list = ['e'.. val it: char list = ['e'. This is referred to as type inference. 'i'. 'o'. the following code uses a type annotation for one of the parameters. which makes the process of parallelizing code simpler. 1764) A key concept in F# is immutability. 'o'.. 10] An F# list is an immutable linked list. records. If we try these operators in F# Interactive. F# typically infers this type information for you.. to store these values. we see the following results: > let vowels = ['e'. such as a class or record. 'y'] F# supports a number of other highly effective techniques to simplify the process of modeling and manipulating data such as tuples. 'i'.

1) > swap ("you". false. Without the type annotation. x). This is a powerful switch construct that allows you to branch control flow. we have a list of integers named numbers. and 'a and 'b represent type variables. Functional Programming Continuing with the sample. called a function expression."you") Here the function swap is generic. val swap : 'a * 'b -> 'b * 'a > swap (1. false] The code (fun x -> x % 2 = 0) defines an anonymous function.map (fun x -> x % 2 = 0) [1 . val it : bool list = [false. For example. true.. the F# compiler would not have known which version of the + operator was desired. true).. c] -> 3 | _ -> failwith "List is too big!" 12 . b. Thus the result of x + y is the concatenation of the strings. b] -> 2 | [a. Note that these examples pass a function as a parameter to another function–the first parameter to List. For example. val it : bool * string = (true.map square numbers Consider another example: > List. that takes a single parameter x and returns the result x % 2 = 0 (a Boolean value that says whether x is even).map does just that: let squares = List.Since x is stated to be of type string. The F# library function List. and the square function. which means the code can be used on many types of data. true.. Another tool for data transformation and analysis is pattern matching.map is itself another function. which are place holders for types in generic code. This is called mapping our function over each item in the list. 5]. to the following code defines a function that returns a new tuple with its two values swapped: > let swap (x. then the F# compiler infers that the parameter y must also be a string. Type inference greatly simplifies the process of writing reusable code fragments. The process of type inference also applies automatic generalization to declarations. val it : int * int = (2. This automatically makes code generic when possible. let checkList alist = match alist with | [] -> 0 | [a] -> 1 | [a. Pattern matching also allows you to bind new values. and the only version of the + operator that accepts a left-hand argument of type string also takes a string as the right-hand argument. y) = (y. and we want to create a new list where each item is the result of calling our function. 2).. Using functions as function values is a hallmark of functional programming. we can match against list elements joined together.. and would have defaulted to using int.

a key concept in functional programming. Running F# programs can have multiple parallel active evaluations.ToString()). 5 * 0. Imperative Programming The next line of the sample program prints text in the console window.ToString() let reverse (x : string) = new System.Exception -> "x is an exception" Another way function values are used in F# is in concert with the pipeline operator. and a string: > printfn "%d * %f = %s" 5 0. Other commonly used imperative programming techniques include arrays and dictionaries (hash tables). printfn "N^2 = %A" squares The F# library function printf is a simple and type-safe way to print text in the console window.Console. by using a pattern that performs a dynamic type test: let getType (x : obj) = match x with | :? string -> "x is a string" | :? int -> "x is an int" | :? System.75). and %s are placeholders for integers. such as callbacks and agents that wait to react to events and messages.Pattern matching can also be used as a control construct—for example. The %A format can be used to print arbitrary data types (including lists).75 ((5. given these functions: let square x = x * x let toStr (x : int) = x.NET Interoperability and CLI Fidelity The last line in the sample program calls the CLI function System. The printfn function is an example of imperative programming (calling functions for their side effects). which prints an integer. |>. val it : string = "4201" Pipelining demonstrates one way in which F# supports compositionality in programming. and multiple pending reactions. For example. System.0 * 0. .rev (x. Parallel and Asynchronous Programming F# is both a parallel and a reactive language. Furthermore. %f.ReadKey(true) Since F# is built on top of CLI implementations you can call any CLI library from F#.ReadKey to pause the program before it closed. and strings.750000 = 3. Consider this example.Console. all F# components can be readily used from other CLI languages. floats..ToCharArray())) We can use the functions as values in a pipeline: > let result = 32 |> square |> toStr |> reverse. 13 . F# programs typically use a mixture of functional and imperative techniques.String(Array.75 val it : unit = () The format specifiers %d. The pipeline operator simplifies the process of writing compositional code where the result of one function is passed into the next.. a floating-point number.

Stronger Typing for Floating-Point Code F# applies type checking and type inference to floating-point-intensive domains through units of measure inference and checking.IO open System. "http://www.com". Here speedOfImpact is inferred to have type float<m/s>.search.86<m> let speedOfImpact = sqrt(2. without losing any performance in your compiled code. [<Measure>] type kg [<Measure>] type m [<Measure>] type s let gravityOnEarth = 9.google.Console.com". and message-receiving agents.ReadKey(true) The above code sample shows multiple.Parallel [for site in sites -> http site ] |> Async.Create(Uri url) use! resp = req. CPU-bound computations. F# is also a reactive language.yahoo. You can think of this feature as providing a type system for floating-point code.RunSynchronously The combination of asynchronous workflows and other CLI libraries can be used to implement task parallelism.0 * gravityOnEarth * heightOfTowerOfPisa) The Measure attribute tells F# that kg.One way to write parallel and reactive programs using F# is with F# async expressions. I/O parallelism. The following example requests multiple web pages in parallel. parallel.40 -> async { return fib(i) } ] |> Async. the code below is similar to our original script except that it computes the Fibonacci function (using a technique that will take some time). For example. This allows you to type check programs that manipulate floating-point numbers that represent physical and abstract quantities.GetResponseStream() use reader = new StreamReader(stream) let contents = reader.com".AsyncGetResponse() use stream = resp. "http://www. s and m aren't really types in the usual sense of the word..81<m/s^2> let heightOfTowerOfPisa = 55.bing.RunSynchronously printfn "N^2 = %A" fibs System. 14 .com"] let htmlOfSites = Async. open System open System.Parallel [ for i in 0. reacts to the responses for each request. "http://www. and finally returns the collected results.ReadToEnd() return contents } let sites = ["http://www. but are used to build units of measure. and schedules the computation of the numbers in parallel: let rec fib x = if x <= 2 then 1 else fib(x-1) + fib(x-2) let fibs = Async.Net let http url = async { let req = WebRequest.

y) = (y. val it : string = "F# vf sha!" > "F# is fun!" |> encoder. here is a class definition for an encoder/decoder object.ContainsKey(c) then fwd. The most important of these is object-oriented programming through class type definitions.ofSeq let encode (s:string) String [| for c in let decode (s:string) String [| for c in = s -> if fwd. For example..'Z'). and object expressions.Encode .[c] else c |] /// Encode the input string member x. The encoding is specified by a sequence /// of character pairs.Object-Oriented Programming and Code Organization The sample program shown at the start of this chapter is a script. Object-oriented programming is a primary API design technique for controlling the complexity of large software projects. val it : String = "F# is fun!" An interface type can encapsulate a family of object types: open System type IEncoding = abstract Encode : string -> string abstract Decode : string -> string 15 . rot13 c)]) And use the object as follows: > "F# is fun!" |> encoder. ('Z'.Decode . interface type definitions.ContainsKey(c) then bwd.Decode(s) = decode s You can instantiate this type as follows: let rot13 (c:char) = char(int 'a' + ((int c .ofSeq /// An immutable tree map for the decoding let bwd = symbols |> Seq.Encode(s) = encode s /// Decode the given string member x.map swap |> Map.'a')] type CharMapEncoder(symbols: seq<char*char>) = let swap (x. they are not suitable for larger software components. Although scripts are excellent for rapid prototyping. [('a'. for example.[c] else c |] = s -> if bwd.int 'a' + 13) % 26)) let encoder = CharMapEncoder( [for c in 'a'. open System /// Build an encoder/decoder object that maps characters to an /// encoding and back.. x) /// An immutable tree map for the encoding let fwd = symbols |> Map.'z' -> (c.Encode |> encoder.. F# supports the transition from scripting to structured code through several techniques.

here is an object expression that implements the interface type: let nullEncoder = { new IEncoding with member x. Where appropriate.squares 10) System. For example.Decode(s) = s } Modules are a simple way to encapsulate code during rapid prototyping when you do not want to spend the time to design a strict object-oriented type hierarchy. unless otherwise specified. we place a portion of our original script in a module. In the following example. n] let square x = x * x let squares n = numbers n |> List.Encode(s) = s member x. apostrophes and quotation marks enclose symbols that are used in the specification of the grammar itself. the regular expression abstract matches precisely the characters abstract. The following characters are referred to using the indicated notation: \b \n \r \t backspace newline return tab ASCII/UTF-8/UTF-16/UTF-32 ASCII/UTF-8/UTF-16/UTF-32 ASCII/UTF-8/UTF-16/UTF-32 ASCII/UTF-8/UTF-16/UTF-32 code code code code 08 10 13 09 String of characters that are clearly not a regular expression are written verbatim.Console. and namespaces. which serve as a way of organizing the name hierarchies for larger APIs. Other devices aimed at supporting software engineering include signatures. Regular expressions are given in the usual notation.2 Notational Conventions in This Specification This specification describes the F# language through a mixture of informal and semiformal techniques. For example: regexp+ regexp* regexp? [ char . For example. which can be used to give explicit types to components.ReadKey(true) Modules are also used in the F# library design to associate extra functionality with types.Both object expressions and type definitions can implement interface types. List.char ] one-or-more repetition zero-or-more repetition zero-or-one occurrences range of ASCII characters exclusion of a character range or set Unicode character classes are referred to by their abbreviation—for example. \Lu for any uppercase letter. Therefore. For example. the following regular expression matches (+) or (-): '(' (+|-) ')' 16 . such as '<' and '|'. All examples in this specification use lightweight syntax.squares 5) printfn "Squares up to 10 = %A" (ApplicationLogic.map is a function in a module.char ] [ ^ char . module ApplicationLogic = let numbers n = [1 .map square printfn "Squares up to 5 = %A" (ApplicationLogic.. 1.

the notation element-nameopt indicates an optional element.. token token-name = regexp In the grammar rules.. indicates repetition of the preceding non-terminal construct and the separator token.' . For example. 17 . The notation .' expr means a sequence of one or more expr elements separated by commas. '..This regular expression matches precisely the characters #if: "#if" regexp letter-char = [A-Za-z]+ Regular expressions are usually used to specify tokens.. expr '.

1) and types. as well as other specific rules described in this specification.6.fsx.  Script fragments (for F# Interactive).  Tokenization. Files with extension . The augmented token stream is parsed according to the grammar specification in this document. The command-line options may specify a codepage for this process. o o o Files with extension . Importing.1). or .fsscript must conform to grammar element script-file in §12. sections 2.3. as described in the C# specification. The various checking processes maintain tables of information including an environment and a set of current inference constraints. which are then imported.2 Program Structure The inputs to the F# compiler or the F# Interactive dynamic compiler consist of:  Source code files. The token stream is filtered by a state machine that implements the rules described in §15. . Compilation parameters (via command line arguments or interactive directives). From the F# perspective. Checking includes invoking such procedures as Name Resolution (§14. The results of parsing are checked one by one. The stream of Unicode characters is tokenized into a token stream through the lexical analysis described in §3. Processing the source code portions of these inputs consists of the following steps:  Decoding.fsi.2.4. Those rules describe how additional (artificial) tokens are inserted into the token stream and how some existing tokens are replaced with others.. all such variables have been either generalized or resolved and the type inference context is discarded.  Lexical Filtering.1). Inputs processed by the F# compiler have the COMPILED compilation symbol defined. The specified imported assembly references are resolved to F# or CLI assembly specifications.5) and Generalization (§14.    Assembly references (via command line arguments or interactive directives). These must conform to grammar element script-fragment.  Checking.   Parsing.fsx or .fs. Constraint Solving (§14. Files with extension .1. this results in the pre-definition of numerous namespace declaration groups (§12. Compiler directives such as #time.8). .fsi must conform to grammar element signature-file in §12.3 and 2. with extensions .fs must conform to grammar element implementation-file in §12. These namespace declaration groups are then combined to form an initial name resolution environment (§14. Each file and source code fragment is decoded into a stream of Unicode characters. tokens. 18 . Script fragments can be separated by . Inputs processed by F# Interactive have INTERACTIVE defined.  Type inference uses variables that represent unknowns in the type inference problem. After the processing of a file or program fragment is complete.fsscript.

One result of checking is an elaborated program fragment that contains elaborated declarations. control flow. Elaboration. and types. 19 .5).8). expressions. Elaborated forms are used for evaluation. Elaborated program fragments that are successfully checked are added to a collection of available program fragments. Static initializers are executed as described in (§12. such as constants. the elaborated form is simple.  Execution. and data expressions. Each fragment has a static initializer. For most constructs. CLI reflection. and the F# expression trees that are returned by quoted expressions (§6.

comments can be nested. strings that are embedded in comments are tokenized without looking for closing *) marks.2 Comments Block comments are delimited by (* and *) and may be nested. A source line that contains 20 .1 Whitespace Whitespace is made up of spaces and newline characters. and strings embedded within comments are tokenized by the rules for string and verbatim-string. For example. In practice. This makes (* Here's a code snippet: let s = "*)" *) a valid comment. The intermediate tokens are discarded. Some tokens. Whitespace can appear before the # character.3 Lexical Analysis Lexical analysis converts an input stream of Unicode characters into a stream of tokens. 3. the subsequent text is tokenized recursively using the tokenizations defined in this section until a block-comment-end token is matched. The following describes the grammar for such sections: token if-directive = "#if" whitespace ident-text token else-directive = "#else" token endif-directive = "#endif" A preprocessing directive always occupies a separate line of source code and always begins with a # character and a preprocessing directive name. 3. Single-line comments begin with // and extend to the end of a line. Note: In particular. are discarded after processing as described later in this section. For the purposes of this specification. token block-comment-start = "(*" token block-comment-end = "*)" token end-of-line-comment = "//" [^'\n' '\r']* When a block-comment-start token is matched. XML documentation tokens are end-of-line-comments beginning with /// and are kept and associated with subsequent declaration elements. 3. This conversion is done by repeatedly processing the input character stream using a longest-match interpretation of a collection of regular expressions that specify different possible tokens. such as block-comment-start. comment tokens are discarded from the returned lexical stream. regexp whitespace = ' '+ regexp newline = '\n' | '\r' '\n' token whitespace-or-newline = whitespace | newline Whitespace tokens whitespace-or-newline are discarded from the returned token stream.3 Conditional Compilation #if ident/#else/#endif are preprocessing directives that delimit conditional compilation sections.

the #if. 21 . Multi-line comments are not permitted on source lines that contain pre-processing directives. myName1 | `` [^ '\n' '\r' '\t']+ | [^ '\n' '\r' '\t'] `` For example. text is recursively tokenized until a corresponding else-directive or endif-directive. Any sequence of characters that is enclosed in double-backtick marks (`` ``).with odd#name`` All input files are currently assumed to be UTF-8-encoded. If an if-directive token is matched during tokenization. The converse applies to the text between any corresponding elsedirective and the endif-directive. \Nl. by using the command line option –define). or #endif directive can end with whitespace and a single-line comment. Text that is skipped is tokenized using the following token specifications: token skip-text-directive = "#if" whitespace ident | "#else" | "#endif" token skip-text = skip-text-directive | . \Lm. tabs. See the C# specification for a list of the the Unicode characters that are accepted for the Unicode character classes \Lu. \Lt. \Li. #else. and double-backtick pairs themselves. \Pc. regexp digit-char = [0-9] regexp letter-char = '\Lu' | '\Ll' | '\Lt' | '\Lm' | '\Lo' | '\Nl' regexpconnecting-char = '\Pc' regexp combining-char = '\Mn' | '\Mc' regexp formatting-char = '\Cf' regexp ident-start-char = | letter-char | _ regexp ident-char = | letter-char | digit-char | connecting-char | combining-char | formatting-char | ' | _ regexp ident-text = ident-start-char ident-char* token ident = | ident-text For example. is treated as an identifier. Strings and comments are not treated as special in skipped text. \Lo. Otherwise. excluding newlines. 3. \Mc and \Cf. \Mn. then the tokens are included in the token stream.4 Identifiers and Keywords Identifiers follow the specification below. In particular:   #if ident/#else/#endif sections can be nested. ``value. If the given ident-text is defined in the compilation environment (for example. the tokens are discarded.

regexp escape-char = '\' ["\'ntbr] regexp non-escape-chars = '\' [^"\'ntbr] regexp simple-char-char = | (any char except '\n' '\t' '\r' '\b' ' \ ") regexp unicodegraph-short = '\' 'u' hexdigit hexdigit hexdigit hexdigit regexp unicodegraph-long = '\' 'U' hexdigit hexdigit hexdigit hexdigit hexdigit hexdigit hexdigit hexdigit regexp char-char = | simple-char-char | escape-char | trigraph | unicodegraph-short regexp string-char = | simple-string-char | escape-char | non-escape-chars | trigraph | unicodegraph-short | unicodegraph-long 22 . With the exception of the symbolic keywords (§3.5 Strings and Characters String literals may be specified for two types: Unicode strings (type string = System. as described in the previous section Trigraph specifications of Unicode characters.The following identifiers are treated as keywords of the F# language: token ident-keyword = abstract and as assert base begin class default delegate do done downcast downto elif else end exception extern false finally for fun function global if in inherit inline interface internal lazy let match member module mutable namespace new null of open or override private public rec return sig static struct then to true try type upcast use val void when while with yield The following identifiers are reserved for future use: token reserved-ident-keyword = atomic break checked component const constraint constructor continue eager fixed fori functor include measure method mixin object parallel params process protected pure recursive sealed tailcall trait virtual volatile A future revision of the F# language may promote any of these identifiers to be full keywords. we refer to the token generated for a keyword simply by using the text of the keyword itself. the following token forms are reserved: token reserved-ident-formats = | ident-text ( '!' | '#') In the remainder of this specification. Literals may also be specified using C#-like verbatim forms that interpret \ as a literal character rather than an escape sequence.6). you can directly embed the following in a string in the same way as in C#: • • • Unicode characters Identifiers.String) and unsigned byte arrays (type byte[] = bytearray). 3. In a UTF-8-encoded file.

= _ ? ?? (*) <@ @> <@@ @@> The following symbols are reserved for future use: 23 . However. Thus. if a line ends with \. s has the value "abc\010 has ASCII value 10. Strings may include \n as a newline character..6 Symbolic Keywords The following symbolic or partially symbolic character sequences are treated as keywords: token symbolic-keyword = let! use! do! yield! return! | -> <.| newline regexp string-elem = | string-char | '\' newline whitespace* string-elem token char token string = = ' char-char ' " string-char* " regexp verbatim-string-char = | simple-string-char | non-escape-chars | newline | \ | "" token verbatim-string token token token token token = @" verbatim-string-char* " bytechar = ' simple-or-escape-char 'B bytearray = " string-char* "B verbatim-bytearray = @" verbatim-string-char* "B simple-or-escape-char = escape-char | simple-char simple-char = any char except newline.'. For example: let s = "abc def" In this case. : ( ) [ ] [< >] [| |] { } ' # :?> :? :> .tab. .backspace. For example let s = @"abc\def" gives s value "abc\def".. No Unicode characters with surrogate-pair UTF-16 encodings or UTF-16 encodings greater than 127 may be used in these tokens. def" where \010 is the embedded control character for \n.\. the following gives s the value "abcdef": let s = "abc\ def" Without the backslash. :: := ." To translate a string token to a string value. String-like and character-like literals can also be specified for unsigned byte arrays (type byte[]). which 3.. the resulting string includes the newline and whitespace characters in the string. the newline character and any leading whitespace elements on the subsequent line are ignored.return. the F# parser concatenates all the Unicode characters for the string-char elements within the string. Verbatim strings may be specified by using the @ symbol preceding the string.

. 34n example. 34UL example. 34l example. Only the operators ? and ?<.4. 34un example. 34uy example. 34uL 24 . 34us example. example. 34ul example.8).8 Numeric Literals The lexical specification of numeric literals is as follows: regexp regexp regexp regexp digit = [0-9] hexdigit = digit | [A-F] | [a-f] octaldigit = [0-7] bitdigit = [0-1] regexp int = | digit+ For example. regexp first-op-char = !%&*+-. The quote-op-left and quote-op-right operators are used in quoted expressions (§6.token reserved-symbolic-sequence = ~ ` 3. example.7 Symbolic Operators User-defined and library-defined symbolic operators are sequences of characters as shown below.6). 34s example. 34 0x22 0o42 0b10010 example. The associativity and precedence of symbolic operators when used in expression forms is given in §4.may start with ?. &&& and ||| are valid symbolic operators. 3. except where the sequence of characters is a symbolic keyword (§3.. 34u example. 34 regexp xint = | int | 0 (x|X) hexdigit+ | 0 (o|O) octaldigit+ | 0 (b|B) bitdigit+ token token token token token token = = = = = = | token nativeint = token unativeint = token int64 = token uint64 = | sbyte byte int16 uint16 int32 uint32 xint xint xint xint xint xint xint xint xint xint xint xint 'y' 'uy' 's' 'us' 'l' 'ul' 'u' 'n' 'un' 'L' 'UL' 'uL' For For For For For For For For For For For For For For For For example. example. 34y example. 34L example./<=>@^|~ regexp op-char = first-op-char | ? token quote-op-left | <@ <@@ token quote-op-right | @> @@> token | | | | | = = symbolic-op = ? ?<first-op-char op-char* quote-op-left quote-op-right For example.

ii.ident when all three tokens are adjacent. -3. token1 . (b) Otherwise the usual grammar rules apply with an addition for ADJACENT_PREFIX_OP expr = expr MINUS expr | MINUS expr | ADJACENT_PREFIX_OP expr Case (b) also applies to uses of +. the tokens remain.0f For example. 3. For example. The token steam is post-filtered by the following additional rules: (a) If the token stream contains . However the ―-‖ token is marked as an ADJACENT_PREFIX_MINUS token.token ieee32 = | float [Ff] | xint 'lf' token ieee64 = | float | xint 'LF' token bignum For example. This rule is not applied for the sequence: i.1 Post-filtering of Adjacent Prefix Tokens Negative integers are specified using the – token. Otherwise.0F or 3. digit* digit+ (.token where these tokens are adjacent then If token is a constant signed literal the pair of tokens is merged/. for example. 0x0000000000000000LF = int ('Q' | 'R' | 'Z' | 'I' | 'N' | 'G') For example. 0x00000000lf For example.0 For example.token2 where all three tokens are adjacent and token1 is a terminating token from expression forms that have lower precedence than the grammar production expr = MINUS expr For example. it is not applied for the token sequence ident .8. 25 . -3 becomes a single token ―-3‖. 3. 34742626263193832612536171N token decimal = (float|int) [Mm] token float = digit+ . digit* )? (e|E) (+|-)? digit+ 3.

In the absence of line number directive. See §15 for a full specification and for the augmented grammar rules that take these into account. 3. Without this rule. for example. C:\source. such as 34. This construction is used in expressions of the form [for x in 1. When using F# Interactive from tools such as Visual Studio.3.” to immediately follow an integer.Path. The name of the current file is determined by the most recent line directive in the file.. recorded in debugging symbols. are post-filtered to two tokens: one int and one symbolic-keyword.”.11 Identifier Replacements The following identifiers are automatically replaced by expressions: __SOURCE_DIRECTORY__ Replaced by a literal verbatim string that specifies the name of the directory that contains the current file. 3. the name is determined by that given to the command-line compiler in combination with System.. 3. Note: This rule allows “. the first line of a file is numbered 1. the name stdin is used. 26 .... a line directive is implicitly added before each interactive execution of script fragment.8.9 Line Directives The following directives adjust the source code filenames and line numbers that are reported in error messages. For F# Interactive. If no line directive has been given.2 -> x + x ].IO.. ―. the longest-match rule would consider this sequence to be a floating-point number followed by a “.‖.3 Reserved Numeric Literal Forms The following token forms are reserved for future numeric literal formats: token reserved-literal-formats = | (xint | ieee32 | ieee64) ident-char+ 3.GetFullPath. and propagated to quoted expressions: token line-directive = # int # int string # int verbatim-string #line int #line int string #line int verbatim-string A line number directive applies to the line that immediately follows the directive.10 Hidden Tokens Some hidden tokens are inserted by lexical filtering (§15) or are used to replace existing tokens.” Tokens of the form token intdotdot = int.2 Post-filtering of Integers Followed by Adjacent “.8.

__SOURCE_FILE__ Replaced by a literal verbatim string that contains the name of the current file. __LINE__ Replaced by a literal string that gives the line number in the source file. after taking into account adjustments from line directives. for example. 27 . file.fs.

| ident | _ | For operator definitions. The text (+++) is an ident-or-op which acts as an identifier with associated text +++.. For example. y) In this example. for active pattern definitions (§7) the active pattern case names aer placed in parentheses. active-pattern-op-name := | | ident | . For example: let (+++) x y = (x.. the operator name is placed in parentheses. 2.1 Operator Names Several places in the grammar refer to an ident-or-op rather than an ident: ident-or-op := | ident | ( op-name ) | (*) op-name := | symbolic-op | range-op-name | active-pattern-op-name range-op-name := | . 4. otherwise (* is interpreted as the start of a comment: let ( *+* ) x y = (x + y) 28 .map ((+) 1) [ 1... let (|A|B|C|) x = if x < 0 then A elif x = 0 then B else C These names can be used in expressions..4 Basic Grammar Elements This section defines grammar elements that are used repeatedly in later sections. a space is required. the binary operator +++ is defined.. . List. 3 ] The three character token (*) is used to define the * operator: let (*) x y = (x + y) For other operators that begin with *. for example.. | ident | | | ident | . | . Likewise.

op_Range .Symbolic operators and some symbolic keywords are given a compiled name that is visible in the compiled form of F# programs.. op_RangeStep 29 . .. The compiled names are shown below.. [] op_Nil :: op_ColonColon + op_Addition op_Subtraction * op_Multiply / op_Division ** op_Exponentiation @ op_Append ^ op_Concatenate % op_Modulus &&& op_BitwiseAnd ||| op_BitwiseOr ^^^ op_ExclusiveOr <<< op_LeftShift ~~~ op_LogicalNot >>> op_RightShift ~+ op_UnaryPlus ~op_UnaryNegation = op_Equality <> op_Inequality <= op_LessThanOrEqual >= op_GreaterThanOrEqual < op_LessThan > op_GreaterThan ? op_Dynamic ?<op_DynamicAssignment |> op_PipeRight ||> op_PipeRight2 |||> op_PipeRight3 <| op_PipeLeft <|| op_PipeLeft2 <||| op_PipeLeft3 ! op_Dereference >> op_ComposeRight << op_ComposeLeft <@ @> op_Quotation <@@ @@> op_QuotationUntyped ~% op_Splice ~%% op_SpliceUntyped ~& op_AddressOf ~&& op_IntegerAddressOf || op_BooleanOr && op_BooleanAnd += op_AdditionAssignment -= op_SubtractionAssignment *= op_MultiplyAssignment /= op_DivisionAssignment .

32 and 64-bit signed integers --------- 32-bit signed integer 8. & | @ # ^ ! ? / . 32 and 64-bit unsigned integers 32-bit number of type "float32" 64-bit number of type "float" User or library-defined integral literal type Unicode character of type "char" String of type "string" (System. const := | sbyte | int16 | int32 | int64 | byte | uint16 | uint32 | int | uint64 | ieee32 | ieee64 | bignum | char | string | verbatim-string -.. 16.String) 30 .’ and optional whitespace. The individual lexical formats for the different constants are defined in §3.. For example.String) String of type "string" (System. long-ident := ident '. 16.Compiled names for other symbolic operators are op_N1. the symbolic identifier <* has the compiled name op_LessMultiply: > < + * = ~ % .3 Constants The following table shows the constants that may be used in patterns and expressions.' ident long-ident-or-op := | long-ident '.2 Long Identifiers Long identifiers long-ident are sequences of identifiers separated by ‘. ) [ ] Greater Less Plus Minus Multiply Equals Twiddle Percent Dot Amp Bar At Hash Hat Bang Qmark Divide Dot Colon LParen Comma RParen LBrack RBrack 4.Nn where N1 to Nn are the names for the characters as shown in the table below..' ident-or-op | ident-or-op 4..8. Long identifiers long-ident-or-op are long identifiers that may terminate with an operator name. : ( . '.' .

-. -. For example.. %..x2:C) = C(x1. && can be used as both prefix and infix operators. The marker OP indicates the class of symbolic-op tokens that begin with the given prefix. infix-or-prefix-op := +. the tilde character is prepended to generate the operator name.It always accepts arguments in tupled form. excluding those listed elsewhere in the table.4 Operators and Precedence 4. rather than curried form.’) := :: $ or ? The operators +. so the following prefix operators are defined with the ~ character added: // For a complete redefinition of the prefix + operator: let (~+) x = x // For a complete redefinition of the infix + operator to be addition modulo-7 let (+) a b = (a + b) % 7 // For defining the operator on a type: type C(n:int) = let n = n % 7 member x.x2:C) = C(x1. &.1 Categorization of Symbolic Operators The following symbolic-op tokens can be used to form prefix and infix expressions. and cannot be redefined. +.to the identifier x. %. in common with all union cases.| | | | | bytestring -verbatim-bytearray bytechar -false | true -() -- String of type "byte[]" -. When these operators are used as prefix operators. +.4.N+x2.N) static member (-) (x1:C.N = n static member (~+) (x:C) = x static member (~-) (x:C) = C(-n) static member (+) (x1:C. This generated name is also used in definitions for these prefix operators. 31 . though it may be used to form infix expressions.N-x2. &. -..N) The operator :: is special. It represents the union case for the addition of an element to the head of an immutable linked list.. -x is parsed as an application of the operator ~. -. && prefix-op := infix-or-prefix-op ~ ~~ ~~~ !OP (and any repetitions of ~) (except !=) infix-op := infix-or-prefix-op -OP +OP || <OP >OP = |OP &OP ^OP *OP /OP %OP != (or any of these preceded by one or more ‘.String of type "byte[]" Char of type "byte" Boolean constant of type "bool" unit constant of type "unit" 4.

which can be pictured as follows: a + b * c rather than a + b * c Likewise. see §15.for infix uses of these symbols %left %right %left %right -.pattern match rules %left -. along with the indicated left/right associativity resolution. For example.high precedence type application. fun.2 %left -. see §15.4. given the tokens a * b * c the left-associativity of * means we can picture the resolution of the ambiguity as: a * b * c In the preceding table.4.2 Precedence of Symbolic Operators and Pattern/Expression Constructs The precedence of ambiguous expression and pattern constructs is as follows.for prefix uses of these symbols %left %left -. from lowest (least tightly binding) to highest (most tightly binding). For example. 32 . let function. the rules from §6) involve tokens in the table. the expr infix-op expr rule for b * c takes precedence over the expr infix-op expr rule for a + b. The marker OP indicates the class of symbolic-op tokens beginning with the given prefix. try if -> := . consider the following token stream: a + b * c In this expression.* has the same precedence as *. and precedence order for ambiguity resolution as when | . expressions. match. or || & && :> :?> !=OP <OP >OP = |OP &OP $ ^OP :: :? -OP +OP *OP /OP %OP **OP "f x" "lazy x" "assert x" "| rule" prefix-op .3 The preceding table is interpreted as follows. the ambiguity is resolved by applying higher precedence to a construct that involves the token that comes later in the table. characters are ignored when determining precedence for infix operators. leading . . If ambiguous grammar rules (for example. excluding those listed elsewhere in the table. f(x) f<types> %right %right %left %right %nonassoc %nonassoc %nonassoc %right %right %nonassoc %left %left %right %left %right %right %nonassoc %left -. Infix operators.high precedence application.

In the preceding table.2 and §15.3. the entries for ―high precedence application‖ and ―high precedence type application‖ arise from the augmentation of the lexical token stream.* (frequently used for pointwise-operation on matrices) have the expected precedence. 33 .Note: This rule ensures that operators such as . see §15.

A type that contains no type variables is called ground. ( type ). either by the translation of syntactic types that appear in the source text.FSharp.Type and are runtime representations of some or all of the information that is carried in type definitions and static types.. The syntactic forms of types as they appear in programs are as follows: type := ( type ) type -> type type * . . or via constraints related to particular language constructs. which arise during type checking and inference. type atomic-type := type --restricted to #type. such as IEnumerable< > named type. long-ident<types>) typar := _ 'ident ^ident -.. An object‘s runtime type is related to the static type of the identifiers and expressions that correspond to the object. . Runtime types of objects do not contain type variables. such as int list array type lazy type type with constraints variable type with subtype constraint anonymous type with subtype constraint type. Runtime types reported by System.5 Types and Type Constraints The notion of type is central to the static checking of F# programs.Reflection may contain type variables. which are objects of type System.  Static types.. typar. which are represented by System.. .. which is available on all F# values. option<int> is the fully processed static type inferred for an expression Some(1+1).member "trait" constraint 34 . Runtime types may be tested by built-in language operators such as :? and :?>. the expression form downcast expr. and pattern matching type tests. For example. * type typar long-ident long-ident<types> long-ident< > type long-ident type[ .type variable -. Static types may contain type variables as described later in this section..  Runtime types. Syntactic types are converted to static types during the process of type checking and inference.static head-type type variable constraint := typar :> type -.anonymous variable type -. ] type lazy type typar-defns typar :> type #type types := ------------- function type tuple type variable type named type._>.String or Microsoft.GetType() method.Map<_. such as int named type.coercion constraint typar : null -. and also appears at runtime through dynamic type tests and reflection. The word is used with four distinct but related meanings:  Type definitions such as the actual CLI or F# definitions of System. Runtime types associated with objects are accessed by using the obj. long-ident.nullness constraint static-typars : (member-sig ) -..Type values.Collections. such as list<int> named type.  Syntactic types such as the text option<_> that might occur in a program text.

declarations. and results in output constraints Χ’.. and a floating type variable environment (§14. That is. each static type is processed under input constraints Χ. 35 . Specifically: array<int> not array < int > 5. .. a set of current inference constraints is maintained.enum decomposition constraint unmanaged -. expressions. During conversion and throughout the checking of types.delegate decomposition constraint typar-defn := attributesopt typar typar-defns := < typar-defn.1 Checking Syntactic Types Syntactic types are checked and converted to static types as they are encountered. For example int32 * int32 is used to represent the syntactic type that appears in source code and the static type that is used during checking and type inference. possibly involving one or more explicit or implicit generic parameters. typar-defn typar-constraintsopt > typar-constraints := when constraint and . Type inference variables are either solved or generalized by type inference (§14..CLI non-Nullable struct not struct -.5). Type inference variables and constraints are progressively simplified and eliminated based on these equations through constraint solving (§14.5). For the remainder of this specification we use the same syntax to represent syntactic types and static types.typar typar typar typar typar typar : : : : : : (new : unit -> 'T) -. and constraint static-typars := ^ident (^ident or . type> -. or ^ident) member-sig := <see Section 10> A named type that is followed by a < for a type instantiation must be syntactically adjacent with no intervening whitespace. Every expression in an F# program is given a unique inferred static type. as determined bylexical filtering (§15).5).1)... Static types are a specification device used to describe   The process of type checking and inference The connection between syntactic types and the execution of F# programs. The conversion from syntactic types to static types happens in the context of a name resolution environment (§14.unmanaged constraint delegate<type..5). and entire files.1) and a type inference environment (§14.CLI reference type enum<type> -. The phrase ―fresh type‖ means a static type formed from a fresh type inference variable (§14.CLI default constructor constraint struct -..

5). A fresh type inference variable is created and added to the type inference environment (see §14. 5. the formal constraints C are added to the current inference constraints with respect to these new variables. This type variable is tagged with an attribute indicating it may not be generalized except at inline definitions (see §14. A type of the form ty lazy is shorthand for the named type Microsoft. though only in the context of a syntactic type embedded in an expression or pattern.Lazy<ty>. * tyn is a tuple type. Furthermore.…. Note: this specification generally uses upper case identifiers such as 'T or 'Key for user-declared generic type parameters. A fresh type inference variable is created and added to the type inference environment (see §14. the result is a variable type that refers to an existing declared type parameter.1. The elaborated form of a tuple type is shorthand for a use of the family of F# library types System. any type variables that are contained in any type with which it is equated via a type inference equation may similarly not be generalized.FastFunc<ty1. and ty2 is the range.Tuple<_.6. the following are all variable types: 'a 'T 'Key During checking. where ty1 is the domain of the function values associated with the type. If the type variable name is given a type in that environment. A type of the form long-ident is a named type with no type arguments.Control. The number of type arguments n is used as part of the name resolution process to distinguish between named types that take different numbers of type arguments..5). See §6.ty'n> are generated for each formal type parameter.   If name resolution succeeds. Named types are converted to static types as follows:  Name Resolution for Types (§14.FSharp.….1.….1) must resolve long-ident to a type definition with formal generic parameters <typar1.8).3..5.3 Tuple Types A type of the form ty1 * . 36 .1.. A type of the form ^ident is a statically resolved type variable. typarn> and formal constraints C. If name resolution fails.2 for the details of this encoding.FSharp. Otherwise. For example.1 Named Types A type of the form long-ident<ty1. a fresh type inference variable is created (see §14. 5.5). It is processed as if it were written long-ident<type>._>.1) is applied to the identifier.. and lower-case identifiers such as 'a or 'b for compiler-inferred generic parameters. A type of the form ty1 -> ty2 is a function type.. the current floating type variable environment is consulted.  Fresh type inference variables <ty'1. Name Resolution (§14.. A type of the form type long-ident is a named type with one type argument. and constraints tyi = ty'i added to the current inference constraints. A type of the form _ is an anonymous variable type. then that mapping is used. In compiled code it is represented via the named type Microsoft.Core.tyn> is a named type with one or more suffixed type arguments.ty2>.2 Variable Types A type of the form 'ident is a variable type.

..] is an array of integers of rank 3. During checking. ] is a multidimensional array type. 5.int>>.5 Constrained Types A type of the form type when constraints is a type with constraints. The conditions governing when two types satisfy a subtype constraint are specified in §5. Note: This limitation is specifically needed to simplify type inference. For example. 5. as if they are an instantiation of a fictitious type definition System..1. types and members with constraints. from patterns of the form pattern :> type. int[. For example.Tuple<int. 37 .1.2. from uses of generic values. A type of the form typar :> type is a type variable with a subtype constraint and is equivalent to typar when typar :> type. and from the implicit use of subsumption when calling members (§14. tuple types are distinct from their encoded form. type is checked as a type. then constraints are checked and added to the current inference constraints.0 supports multidimensional array types only up to rank 4. and the constraint is added to the current inference constraints.4. This is for consistency with other postfix type names in F# such as int list list. The various forms of constraints are described in the subsections that follow.Arrayn<ty> where n corresponds to the rank of the array type. During checking. if during type inference.When considered as static types. the type instantiations are constrained to be equal. where 'a is a fresh type inference variable.][] in C# although the dimensions are swapped. However. typar is first checked as a variable type. Except where specified otherwise in this document. reduce the size of types shown to users.7. the encoded form of tuple types is visible in the F# type system through runtime types. . Note: Subtype constraints also arise implicitly from expressions of the form expr :> type. A type variable may not be constrained by both distinct instantiations of the same named type. these array types are treated as named types. . For example. type is first checked and converted to a static type. 5. and help ensure the reporting of useful error messages. then an error arises when the type instantiations are constrained to be equal.1 Subtype Constraints A constraint of the form typar :> type is an explicit subtype constraint. If two such constraints arise during constraint solving. a type variable is constrained by both IA<int> and IA<string>. A type of the form #type is an anonymous type with a subtype constraint and is equivalent to 'a when 'a :> type.4. typeof<int * int> is equivalent to typeof<System.4 Array Types A type of the form ty[] is a single-dimensional array type.] in F# is the same as the type int[.2).2 Type Constraints 5. Note: The type int[][. F# 2. A type of the form ty[ .

If these are named types. Note: Nullness constraints are primarily for use during type checking and are used relatively rarely in F# code. In addition:  The typar must be a statically resolved type variable of the form ^ident.5.8. that is.. Note: Member constraints are primarily used for defining overloaded functions in the F# library and are used relatively rarely in F# code.3 Member Constraints A constraint of the form (typar or . and support set.2) of the form ^ident. and ensure the reporting of useful error messages. the argument and return types in the two member constraints are themselves constrained to be equal.5. 38 .6.1. 5. Note: This limitation is specifically needed to simplify type inference. and means that generic code may not use this constraint unless that code is inlined (§14. the function let f x = x + x results in a function f that can be used only to add one type of value. A type variable may not be involved in the support set of more than one member constraint with the same name. Uses of overloaded operators do not result in generalized code unless definitions are marked as inline.8). then either the named type for ^a or the named type for ^b must support a static member called + with the given signature.2.6. staticness.4 .   The member-sig cannot be generic.2 Nullness Constraints A constraint of the form typar: null is an explicit nullness constraint. Nullness constraints also arise from expressions of the form null.. For example. This ensures that the constraint is resolved at compile time against a corresponding named type and means that generic code cannot use this constraint unless that code is inlined (§14. During checking. or typar) : (member-sig) is an explicit member constraint.2. ^b and ^c.4. In addition:  Each of typar must be a statically resolved type variable (§5. This ensures that the constraint is resolved at compile time. the operator + is defined in the F# library with the following signature: val inline (+) : ^a -> ^b -> ^c when (^a or ^b) : (static member (+) : ^a * ^b -> ^c) This indicates that each use of the operator + results in a constraint on the types that correspond to parameters ^a. If it is. typar is first checked as a variable type and the constraint is added to the current inference constraints. The conditions that govern when a type satisfies a nullness constraint are specified in §5. it cannot include explicit type parameter definitions. reduce the size of types shown to users. For example.8). argument arity. The conditions governing when a type satisfies a member constraint are specified in §14. such as int or float–the exact type will be determined by later constraints.

During constraint solving (§14.7 Enumeration Constraints A constraint of the form typar : enum<underlying-type> is an explicit enumeration constraint. Note: This constraint form is primarily to give completeness with respect to the full set of constraints that are permitted by CLI implementations. For various technical reasons the two types cannot be equated. the constraint type : (new : unit -> 'T) is met if type has a parameterless object constructor. notably because types such as System. During constraint solving (§14. That is.Nullable<System.8 Delegate Constraints A constraint of the form typar : delegate<tupled-args-type. In F# the type option<_> is similar to some uses of System. 5.Nullable<_>. excluding the CLI type System. the constraint type : enum<underlying-type> is met if type is a CLIcompatible enumeration type with constant literal values of type underlying-type. 5. the constraint type : not struct is met if type is a reference type.5 Value Type Constraints A constraint of the form typar : struct is an explicit value type constraint. Note: This constraint form primarily exists to allow the definition of library functions such as enum. 5.5.. the constraint type : delegate<tupled-arg-type. The enum constraint does not imply anything about subtyping. During constraint solving (§14..Enum.6 Reference Type Constraints A constraint of the form typar : not struct is an explicit reference type constraint. 5. During constraint solving (§14.5).5).Nullable is inherited from C# and other CLI languages. During constraint solving (§14. the constraint type : struct is met if type is a value type. an enum constraint does not imply that the type is a subtype of System. return-type> is an explicit delegate constraint. Note: This constraint form is primarily to give completeness with respect to the full set of constraints that are permitted by CLI implementations.Nullable<_>> and System..5).5).Nullable<_>. the delegate must match the standard CLI design pattern where the sender object is the first argument to the event. The restriction on System. * argN.2.2. Note: This constraint form is primarily to give completeness with respect to the full set of constraints that are permitted by CLI implementations. It is rarely used directly in F# programming. 39 .5).2. It is rarely used in F# programming. It is rarely used in F# programming.2.2. * argN and tupled-arg-type = arg1 * . For example.4 Default Constructor Constraints A constraint of the form typar : (new : unit -> 'T) is an explicit default constructor constraint. It is rarely used in F# programming. return-types> is met if type is some delegate type D with declaration type D = delegate of object * arg1 * .Nullable<string> are not valid CLI types.. which give this type a special syntactic status.

5. then each of these must satisfy tyi : equality. if the type has equality dependencies ty1. float32. then the type definition does not have. 5. For example.5). int64. uint16. int32. . then each of these must satisfy tyi : comparison Note: an equality constraint is a relatively weak constraint. nativeint. It is rarely used directly in F# programming.9 Unmanaged Constraints A constraint of the form typar : unmanaged is an unmanaged constraint. During constraint solving (§14. uint32. This is because the purpose of the constraint is to simplify the presentation of CLI event handlers to the F# programmer. or structural types that are inferred to have the NoEquality attribute. the constraint type : unmanaged is met if type is unmanaged as specified below:  Types sbyte..IntPtr or is System. During constraint solving (§14.  The constraint type : comparison is a comparison constraint. and the type definition implements System. Such a constraint is met if all the following conditions hold:  if the type is a named type. it possible to use reference equality on all reference types. and is not inferred to have.5).  if the type has comparison dependencies ty1. such as C#.. then the type definition does not have.10 Equality and Comparison Constraints A constraint of the form typar : equality is an equality constraint. satisfy this constraint.UIntPtr. This corresponds to the fact that in other CLI languages. where the first argument is a “sender” object. the NoComparison attribute. because it usually implies that a type must implement System. A constraint of the form typar : comparison is a comparison constraint.. and is not inferred to have. .Delegate. the constraint type : equality is met if all the following conditions hold:  if the type is a named type. unativeint.IComparable or is an array type or is System. 40 .2.Note: This constraint form primarily exists to allow the definition of certain F# library functions related to event programming. a ‘delegate’ constraint doesn’t imply that the type is a subtype of System. A non-generic struct type whose fields are all unmanaged types is unmanaged. int16. The delegate constraint applies only to delegate types that follow the “standard” form for CLI event handlers.2. float. uint64. tyn.   Type nativeptr<type> is unmanaged.IComparable. tyn... The delegate constraint does not imply anything about subtyping. byte. char. the NoEquality attribute. because all CLI types apart from F# types that are annotated with the NoEquality attribute.. A comparison constraint is a stronger constraint. decimal are unmanaged.

an operator to form function types.  type variables 'ident.'Value>. 5. record field definitions and corresponding specifications in signatures.IComparable > (x: 'T.Dispose() Explicit type parameter definitions can declare custom attributes on type parameter definitions (§13. member definitions.Dictionary<'Key. and specific n-tuple types.1). Type definitions may have custom attributes (§13.    The generic parameters of type definitions may have associated formal type constraints. during type checking and elaboration.3).IDisposable> (x: 'T.1 Characteristics of Type Definitions Type definitions include CLI type definitions such as System. Backward : 'T2 -> 'T2 } Explicit type parameter definitions can include explicit constraint declarations. syntactic types and constraints are processed into a reduced form made up of:  named types op<types>. 41 .Dispose() Note: In most circumstances. with one or more type parameters. These are eliminated for the purposes of checking and inference (see §5.Dispose() else y. System. some of which are relevant to checking and inference.2).4.CompareTo(y) < 0 then x.5. y: 'T) = if x.3 Type Parameter Definitions Type parameter definitions can occur at value definitions in modules. where each op consists of a specific type definition.IDisposable and 'T :> System.4 Logical Properties of Types As described above.'T2> = { Forward: 'T1 -> 'T2.4.1). The following terms are used to categorize type definitions:  Type definitions may be generic. For example: let id<'T> (x:'T) = x val id<'T> : 'T -> 'T type Funcs<'T1.String and types defined in F# code (§8). type definitions.Dispose() y. For example: let dispose2<'T when 'T :> System.Collections.Generic. 5. y: 'T) = x. Type definitions may be type abbreviations (§8. specific shapes of array type. for example. declarations that imply subtype constraints on arguments can be written more concisely: let throw (x: Exception) = raise x Multiple explicit constraint declarations use and: let multipleConstraints<'T when 'T :> System.

 Type definitions have a kind which is one of class. union. This means that the types int32 and System. tuple. For example.   Type definitions may have zero or one base type declarations.Collections. enum. after expanding abbreviations.5). union. after expanding type definitions. All relations on static types are considered modulo these equational inference constraints and abbreviations. Struct types are value types. Record. Class. The kind of type refers to the kind of its outermost named type definition. given by the declaration type int = System.Contains("Hello") As described in §6.  Type definitions may have one or more interface declarations.Int32. static types may refer to type abbreviations (see §8.List<int> is a class type. and thus the type of y is string.3) such as int. Furthermore. Likewise we refer to interface. The expansion of type abbreviations (§8. Type definitions may be sealed. The second constraint arises from the use of the generic operator (=). delegate.3). These represent an additional. record. struct. say ty1 and ty2. record. This typically means that type abbreviations should be preserved in the logical structure of types throughout the checking process. tuple. an abbreviation for System.2) if it is not specified explicitly as part of the type definition.Int32 is a struct type. Thus. interface. delegate. y. encapsulated type supported by any values formed using the type definition.Int32.4. union. delegate.2 Expanding Abbreviations and Inference Equations Two static types are considered equivalent and indistinguishable if they are equivalent after taking into account both of the following:   The inference equations inferred from the current inference constraints (§14.Int32 -> int and int -> System. For example. interface delegate. 42 . 5. A type is a reference type if its outermost named type definition is a reference type. as are System. function. Note: Implementations of F# should attempt to preserve type abbreviations when reporting types and errors to users. or abstract. a type is a class type if it is a named type C<types> where C is of kind class. tuple. and union types are all reference type definitions. For example. abstract. we say int is a struct type because System. and variable types. These represent additional encapsulated types supported by values formed using the type. record. function.Generic. Likewise. enum and array types are all sealed. The process of checking imposes constraints ty1 = string and ty1 = ty2. The kind is determined at the point of declaration through a simple procedure called Type Kind Inference (§8. as are class types marked with the SealedAttribute attribute. System. consider the process of checking the function let checkString (x:string) y = (x = y). The process of constraint solving means that the ty2 = string is inferred.Int32 are considered equivalent.Int32 in the F# library. during checking fresh type inference variables are created for values x and y. struct. some aspects of the base type are used to form the implementation of the type definition. measure. struct.

ValueType System. If an expression is made up of multiple subexpressions. Occasionally it is useful to give a more fully annotated representation of the inferred and generalized type information. generalization is applied (see §14. For example. in which case the type variable is said to be rigid and have a binding site. where formal generic parameters are substituted for the actual type instantiation type-inst. for some constructs (notably let and member bindings). static types may be partial. then the resulting constraint set is normally the union of the constraints arising. For example: let id<'a> x'a = x'a 5. This means that some intermediate inference variables and constraints are factored out of the intermediate constraint sets and new implicit binding site(s) are assigned for these variables.MulticastDelegate System. substitute the formal generic parameters of C for type-inst.       Interface types Struct types Enum types Delegate types All array types Variable types System. given let id x = x the type inference variable associated with the value x is generalized and has an implicit binding site at the definition of function id. Type variables may also refer to explicit type parameter definitions.6.4. given type C<'T> = 'T * 'T the binding site of 'T is the type definition of C.Array System.Object The specification of these types can be found in the CLI specifications and corresponding implementation documentation. Type variables without a binding site are inference variables. 43 .5.Exception System.5 Interfaces Types of a Type The interface types of a named type C<type-inst> are given by the transitive closure of the interface declarations of C and the interface types of the base type of C.3 Type Variables and Binding Static types may be type variables.4 Base Type of a Type The base type of a static type is as follows:      Record types Union types Exception types Abstract types Class types System. in that they contain type inference variables that have not been solved or generalized. else System. For generic types C<type-inst>.Object System.4. For example. However.Object System.4.8).Enum System.Object The declared base type of the type definition if the type has one. During type inference. 5.Object.Object System.

ICollection<ty> and System. System. written ty2 :> ty1.String and other CLI reference types satisfy this constraint. if ty1 is in the transitive closure of the base types and interface types of ty2.IEnumerable<ty>. Types in this category are: o o All CLI reference types defined in other CLI languages. .6 Type Equivalence Two static types ty1 and ty2 are definitely equivalent (with respect to a set of current inference constraints) if:  ty1 has form op<ty11. or  ty1 and ty2 are both variable types. Two static types ty1 and ty2 are feasibly equivalent if ty1 and ty2 may become definitely equivalent through the addition of further constraints to the current inference constraints. ty2 has form op<ty21. all named types and type definitions can be categorized into the following four kinds: a) Types with the null literal. As a result. because they generally result in error-prone code.IList<ty>.Collections.. 5.Collections.Generic. This means that the addition of new constraints may make types definitely equivalent where previously they were not..4. which includes System.Generic.4. and ty is in the inclusive transitive closure of the base and interface types of ty2. Variable types 'T coerce to all types ty where a constraint of the form 'T :> ty2 exists in the current inference constraints. For example. and they both refer to the same binding site or are the same type inference variable.Generic. The appearance of null values during execution cannot be completely precluded for technical reasons related to the CLI and CLI libraries.8 Nullness One of the aims of the design of F# is to greatly reduce the use of null literals in common programming tasks. Types defined in F# and annotated with the AllowNullLiteral attribute.The interface types for single dimensional array types ty[] include the transitive closure starting from the interface System. 44 . A static type ty2 feasibly coerces to static type ty1 if ty2 coerces to ty1 may hold through the addition of further constraints to the current inference constraints. different F# types vary in their treatment of the null literal and null values. These are types that have null as an ―extra‖ value.5). given Χ = { 'a = int }. . The result of adding constraints is defined in Constraint Solving (§14.7 Subtyping and Coercion A static type ty2 coerces to static type ty1 (with respect to a set of current inference constraints X).. and these types permit the direct use of the null literal. ty1n>. However:   The use of some null literals is needed in order to interoperate with CLI libraries.4. we have list<int> = list<'a>.Collections.. Thus list<int> and list<'a> are feasibly equivalent for the empty constraint set. ty2n> and each ty1i is definitely equivalent to ty2i for all 1 <= i <= n. For these purposes.. For example. 5. 5..

However. Types in this category are: o o The unit type. However it is.Core. one or all of the ―normal‖ values of the type is represented by the null value. function. This is a common technique in some programming languages. The behavior of operations with respect to null values is defined in §6.9 Default Initialization Related to nullness is default initialization of values of particular types to zero values.zeroCreate. the use of the null literal is not directly permitted.4. 5. In particular. limited set of F# library primitives. These are types that do not admit the null literal but use the null value as a representation.CompilationRepresentation(CompilationRepresentationFla gs. For these types.  Checked default initialization may be used when types are known to have a valid and ―safe‖ default zero value. Types in this category are: o o All F# list.UseNullAsTrueValue) attribute flag and a single nullary union case. null is considered an abnormal value. For these types. The null value is used to represent this case. d) Types without null. These are types that do not admit the null literal. class and interface types. including primitive integers. default initialization is still allowed in some circumstances. record.  Unchecked default initialization may be encountered through the use of CLI libraries and through a very specific.defaultof<type>.defaultof<_> and Array. is a variable type with a typar : null constraint. However. in particular Unchecked. Types in this category are o all value types. The null value is used to represent all values of this type. the use of the null literal is not directly permitted. floating-point numbers and any value of a CLI or F# struct type. These are types that do not admit the null literal and do not have the null value. the types of fields labeled with DefaultValue(true) are checked to ensure they admit default initialization. All F# union types apart from those with null as a normal value (as discussed in the next paragraph). null is used as a representation for None in the F# option<_> type.FSharp. but the design of F# deliberately de-emphasizes this technique. Any union type with the Microsoft. For these types. strictly speaking. 45 .9. A static type ty satisfies a nullness constraint ty : null if it:   has an outermost named type with the null literal.b) Types with null as an abnormal value. c) Types with null as a representation value. For example. possible to generate a null value for these types using certain functions such as Unchecked. but do have null as an abnormal value. tuple.

and ty is underlying[] (or vice-versa).Monday[] does not statically coerce to int32[]. let x = box 1 let y = x :? System. but the expression x :? System. int64[]/uint64[]. nativeint[]/unativeint[].Nullable<int32> printf "%b" y // true In the previous code.DayOfWeek. the type int32 does not coerce to System. let x = box [| 1 |] let y = x :? uint32 [] printf "%b" y // true In the previous code. all of which hold for F# types. let x = box [| "" |] let y = x :? obj [] printf "%b" y // true In the previous code.Nullable<int32>. or the (un)signed equivalent of underlying[] by the rule above.  vty is enum[] where enum has underlying type underlying. For example: let x = box [| System.10 Dynamic Conversion Between Types One ground type vty dynamically converts to another type ty if:   ty coerces to vty. the type System.Nullable<vty>.A type admits default initialization if it is:    A type satisfying the nullness constraint. vty is int32[]and ty is uint32[](or vice-versa). the type string[] does not statically coerce to obj[]. the type int32[] does not statically coerce to uint32[]. Likewise for sbyte[]/byte[]. int16[]/uint16[]. ty is System.DayOfWeek. 5.Nullable<int32> evaluates to true. but the expression x :? int32[] evaluates to true.4. A primitive value type. but the expression x :? uint32 [] evaluates to true. elemty1 is a reference type and elemty1 converts to elemty2. but the expression x :? obj []evaluates to true. A struct type whose field types all admit default initialization. 46 .Monday |] let y = x :? int32[] printf "%b" y // true In the previous code.ty is elemty2[].   vty is elemty1[]. Note: This specification covers the additional rules of CLI dynamic conversions.

type annotation expr :> type -.static upcast coercion expr :? type -.slice expression (1D) expr.static upcast expression downcast expr -.quoted expression %expr -.try/with expression try expr finally expr -.a constant value ( expr ) -.recursive binding expression use bindings in expr –.block expression begin expr end -.resource binding expression fun argument-pats -> expr -. slice-range] -.the "null" value for a reference type expr : type -. .simple for loop for pat in expr-or-range-expr do expr done -.array expression expr { comp-or-range-expr } -.enumerable for loop assert expr -.type application expression expr infix-op expr -.lookup expression expr '. ..try/finally expression if expr then expr elif-branchesopt else-branchopt -.tuple expression new type expr -.assert expression <@ expr @> -. .high precedence application expr<types> -.match expression try expr with rules -.dot lookup expression expr expr -. .assignment expression expr .simple object expression { new base-call object-members interface-impls } -.expression splice (static-typars : (member-sig) expr) -– static member invocation 47 .conditional expression while expr do expr done -. expr -.matching function expression expr .[slice-range] -.quoted expression <@@ expr @@> -.dynamic downcast expression let bindings in expr –.[slice-range.expr -..sequential execution expression match expr with rules -.object expression { field-binds } -.prefix application expression expr.function expression function rules -.computed array expression lazy expr -.block expression long-ident-or-op -. expr -.dynamic type test expr :?> type -.slice expression (2D) expr <.list expression [| expr .while loop for ident = expr to expr do expr done -. .[expr] -. expr ] -..dynamic downcast coercion upcast expr -..6 Expressions The expression forms and related elements are as follows: expr := const -. expr |] -.computed list expression [| comp-or-range-expr |] -.' long-ident-or-op -... .application expression expr(expr) -.binding expression let rec bindings in expr -.infix application expression prefix-op expr -.computation expression [ comp-or-range-expr] -.record cloning expression [ expr .record expression { expr with field-binds } -.indexed lookup expression expr.delayed expression null -.

members using binding syntax -..Expressions are defined in terms of patterns and other entities discussed in later sections.interface implementation object-members := with val-or-member-defns end val-or-member-defns := bindings member-defns member-defns := -..anonymous base construction -..interface construction expression base-call := object-construction object-construction as ident -..named base construction interface-impls := interface-impl . .members using member syntax member-defn . elif-branch elif-branch := elif expr then expr else-branch := else expr binding := inlineopt accessopt ident-or-op typar-defnsopt argument-pats return-typeopt = expr -.function binding mutableopt accessopt pat typar-defnsopt return-typeopt = expr -. ...' expr expr-or-range-expr := expr range-expr elif-branches := elif-branch . atomic-pat field-bind := long-ident = expr -.. interface-impl interface-impl := interface type object-membersopt -....' . member-defn 48 ..value binding return-type := : type bindings := binding and ..field binding field-binds := field-bind .. and binding argument-pats:= atomic-pat .. The following constructs are also used: exprs := expr '. field-bind object-construction := type expr -. '.construction expression type -.

All expressions are assigned a static type through type checking and inference. the state of the inference procedure is left unchanged and the test fails... expr . 49 . with reference to procedures such as Name Resolution (§14.‖ indicates that the initial type satisfies the given property given the current inference constraints.. We also use the following terminology:  The phrase ―the type ty1 is asserted to be equal to the type ty2‖ or simply ―ty1 = ty2 is asserted‖ indicates that the constraint ―ty1 = ty2‖ is added to the current inference constraints. each expression is checked with respect to an initial type. expr expr .yield result -..1 Some Checking and Inference Terminology The rules applied when checking individual expression forms are described in the following subsections.expr expr.5)..  The phrase ―type ty is known to . expr slice-range := expr..range sequence with skip ----- slice slice slice slice from from from from index start index start to to to to end index index end 6.Computation and range expressions are defined in terms of the following productions: comp-or-range-expr := comp-expr short-comp-expr range-expr comp-expr := let! pat = expr in comp-expr do! expr in comp-expr use! pat = expr in comp-expr yield! expr yield expr return! expr return expr expr --------- binding computation sequential computation auto cleanup computation yield computation yield result return computation return result control flow or imperative action short-comp-expr := for pat in expr-or-range-expr -> expr range-expr := expr .expr '*' -. The initial type dictates some of the information available to resolve method overloading and other language constructs.  The phrase ―ty1 is asserted to be a subtype of ty2‖ or simply ―ty1 :> ty2 is asserted‖ indicates that the constraint ty1 :> ty2 is added to the current inference constraints.1) and Constraint Solving (§14. In this case either an error is reported or..5). if we are only attempting to assert the condition. Additionally:  Adding constraints to the type inference constraint set may fail if an inconsistent constraint set is detected (§14. During type checking.range sequence -.  The phrase ―the expression expr has type ty‖ means the initial type of the expression is asserted to be equal to ty.. .

elaborated forms are syntactically a subset of syntactic expressions. array creation. for example. With the exception of the extra resolution information noted above. let x = 1 in x + x. the elaborated form of System. and ident = expr in expr  Applications of methods and functions (with static overloading resolved).2 Elaboration and Elaborated Expressions Checking an expression generates an elaborated expression in a simpler.WriteLine("Hello") carries the information about exactly which overloaded method definition the call has resolved to. including applications of dynamic dispatch through a particular method dispatch slot         Dynamic type coercions: expr :?> type Dynamic type tests: expr :? type For-loops: for ident in ident to ident do expr done While-loops: while expr do expr done Sequencing: expr. reduced language that effectively contains a fully resolved and annotated form of the expression. union cases. record creation) Default initialization expressions (giving default values for types) Primitive bindings of variables: let ident = expr in expr Primitive bindings of functions and union cases: let rec ident = expr and . expr Try-with: try expr with expr Try-finally: try expr finally expr The constructs required for the elaboration of pattern matching (§7). o o o o Null-tests Switches on integers and other types Switches on union cases Switches on the runtime types of objects 50 .. Elaborated forms are underlined in this specification.Console. for example.. and in some cases (such as constants) the elaborated form is the same as the source form.6. The elaborated forms used in this specification are:         Constants Resolved value references: path Lambda expressions: (fun ident -> expr) Primitive object expressions: { new ty(args) with bindings interface-impls } Data expressions (tuples. The elaborated expression carries more explicit information than the source form.

Unit) (System.3.01f 1. Generating a byref-pointer by taking the address of a record field: &(expr. 1.The following constructs are used in the elaborated forms of expressions that make direct local and array assignments and generate ―byref‖ pointer values.[expr]) Elaborated expressions are used as the basis of evaluation (see §6.3 Data Expressions 6. By convention. when describing the process of elaborating compound expressions.     Assigning to a byref-pointer: expr <-stobj expr Generating a byref-pointer by taking the address of a mutable value: &path.9) and also form the basis for the expression trees returned by quoted expression (see §6.Boolean) (System.UIntPtr) (System.01 1.01e10f 99999999n 10328273un 99999999I 'a' "3" "c:\\home" @"c:\home" "ASCII"B () false true // // // // // // // // // // // // // // // // // // // // // // // // // sbyte byte int16 uint16 int/int32 uint32 int64 uint64 float/double float/double float/double float32/single float32/single float32/single nativeint unativeint bigint char string string string byte[] unit bool bool (System.01e10 1. Boolean and unit constants.FSharp.Core.Boolean) Simple constant expressions have the corresponding simple type and elaborate to the corresponding simple constant value. 6.field) Generating a byref-pointer by taking the address of an array element: &(expr. System.IntPtr) (System.Numerics.Char) (String) (System. For example: 3y 32uy 17s 18us 86 99u 99999999L 10328273UL 1.8). The operations are loosely named after their corresponding primitive constructs in the CLI.BigInteger or user-specified) (System.1 Simple Constant Expressions Simple constant expressions are numeric.String) (Verbatim Unicode.String) (Microsoft.0f 1. we omit the process of recursively elaborating sub-expressions. string. 51 .

For example: let three = (1.. and do not have observable side effects...FromOne()  NumericLiteral<suffix>.7.2.FromInt32(xxxx)  NumericLiteral<suffix>.. Z._. Tuple expressions elaborate to uses of System.tyB> where tyB is the converted form of the type (ty8 *. module NumericLiteralZ = let FromZero() = "" let FromOne() = "Z" let FromInt32 n = String.3. defining a module NumericLiteralZ as below permits the use of the literal form 32Z to generate a sequence of 32 ‗Z‘ characters._. For 9 <= n the reified form is new Tuple<ty1. . 6....ty7._.. and if such an instantiation occurs in F# code or CLI library metadata referenced by F# code an error may be reported by the F# compiler..4._> always have Tuple<_> in the final position.8..* tyN).3.ty7.Tuple<ty8>>.6.. exprn is a tuple expression.tyn>(expr1.. N.0) The expression has the type (ty1 * .exprn). Runtime types that are instantiations of the eight-tuple type Tuple<_.FromInt64(xxxx)  NumericLiteral<suffix>.9..Tuple<ty8>>(expr1. * tyn) for fresh types ty1 … tyn.Integer literals with the suffixes Q. and each individual expression ei is checked using initial type tyi.expr7.tyN>..1.ty7.….…...replicate n "Z" F# compilers may optimize on the assumption that calls to numeric literal functions always terminate."3") let blastoff = (10. 52 .. tuple types are shorthand for types involving the additional F# library type System.Tuple... No literal syntax is available for numbers outside the range of 32-bit integers._.Tuple<_> as follows:   For n = 8 the reified form is new Tuple<ty1.FromString("xxxx") For example._. are idempotent. Tuple types and expressions are encoded into uses of a family of F# library types named System. Syntactic types that have some other form of type in this position are not permitted.. R.. G are used for user-defined and library-defined types through the following syntactic translation: xxxx<suffix> For xxxx = 0 For xxxx = 1 For xxxx in the Int32 range For xxxx in the Int64 range For other numbers  NumericLiteral<suffix>._..Tuple as follows:   For n <= 7 they elaborate to new Tuple<ty1. new Tuple<ty8>(expr8).. For n = 8 they elaborate to new Tuple<ty1..FromZero()  NumericLiteral<suffix>..2 Tuple Expressions An expression of the form expr1. For tuple types:   For n <= 7 the reified form is new Tuple<ty1.2. I.. For large n .5..

2.6.. Name : string } let data1 = { Count = 3. then the corresponding runtime type is ty1 * .5 Record Expressions An expression of the form { field-bind1 . int16.. exprn |] is an array expression. expr7..Tuple<int.7.(op_Cons(expr2.int. uint16.. * ty8 * For the runtime type Tuple<ty1.... } let data2 = { Name = "Hello"... 6..4 Array Expressions An expression of the form [|expr1.* tyn) and expr8n is the elaborated form of the expression expr8.int.int. (1. byte. Runtime types of other forms do not have a corresponding tuple type. The inversion is given by: * For the runtime type Tuple<ty1.. List expressions elaborate to uses of Microsoft. * tyN. int64 and uint64 are compiled to an efficient binary representation based on a call to System.. exprn.. Name = "Hello"...List<_> as op_Cons(expr1..0 implementation ensures that large arrays of constants of type bool. Array expressions are a primitive elaborated form. If this determines that ty is a named type. uint32.List<ty> for a fresh type ty.tyN> when n <= 7.int>>.. ty7..3.3. char. with the constraint ty' :> ty.Tuple<int. each expression expri is checked using a fresh type ty' as its initial type. * tyN.int>>.. and (1..Collections.. 6. For example.. sbyte. For example: type Data = { Count : int.) where op_Cons and op_Nil are the union cases with symbolic names :: and [] respectively. tuple types are distinct from their encoded form.tyBn> . field-bindn } is a record construction expression..3. The initial type of the expression is asserted to be ty[] for a fresh type ty.3. Count= 3 } 53 .. The initial type of the expression is asserted to be Microsoft..Runtime..FSharp. * tyN * For the runtime type Tuple<ty1. if tyBn corresponds to the F# tuple type ty8 * . op_Cons (exprn. each expression expri is checked using ty as its initial type.. among other things...3 List Expressions An expression of the form [expr1.int. Tuple<tyN>> when n = 8. This means.2) has a runtime a type compatible with System. Otherwise. the corresponding F# tuple type is ty1 * .FSharp.. that the F# reflection library can correctly report tuple types based on runtime System.4.int.8.int>...... new ty8n(e8n) where ty8n is the type (ty8*.. Note: The F# 2.Tuple<int.RuntimeHelpers.ty7.Collections. exprn] is a list expression. the encoded form of tuple values and types is visible in the F# type system through runtime types. If this determines that ty is a named type. the corresponding F# tuple type is ty1 * . … ... typeof<int * int> is equivalent to typeof<System. However... Likewise.Type values.5. int32..9) has runtime type Tuple<int..ty8n>(expr1. each expression expri is checked using a fresh type ty' as its initial type.. with the constraint ty' :> ty.int. Otherwise each expression expri is checked using ty as its initial type. op_Nil).CompilerServices. 6. Note: The above encoding is invertible and the substitution of types for type variables preserves this inversion.. When considered as static types.. For 9 <= n they elaborate to new Tuple<ty1.InitializeArray.

Each referenced field must be accessible (see §10. b = 2 } The expression on the last line elaborates to let v = 1 + 1 in { b = 2. Height : float } let data3 = { M.Name = "John". For example: type R = {b : int.0 } let data6 = { data5 with M2. then the initial type is a fresh type inference variable fty'i with a constraint fty'i :> ftyi. 54 . For example: type C = val x : int val y : int new() = { x = 1. Name : string.  If field-labeli is not a single identifier or the initial type is a variable type.. which must resolve to a field Fi in a unique record type R as follows:  If field-labeli is a single identifier fld and the initial type is known to be a record type R<_.5).0 } Each field-bindi has the form field-labeli = expri..0 implementation also permits a deprecated record initialization form { new type with Field1 = expr1 and … and Fieldn = exprn }.Height = 186. Each element of this set has a corresponding record type.Data.0 } Fields may also be referenced by using the name of the type that contains them: module M2 = type Data = { Age : int.tyN.6.. a : int } { a = 1 + 1. Height : float } let data5 = { M2. M2....  Otherwise the initial type is ftyi. M2. resulting in a set of record types RSeti.. M. there must be precisely one field binding for each field in record type R. Records expressions are also used for object initializations in additional object constructor definitions (§8.Name = "Bill". a = v }. and each field then resolves to the corresponding field in R. The intersection of all RSeti must give a single record type R.Name = "John".._> with field Fi with name fld then the field label resolves to Fi.0 } let data4 = { data3 with M. That is..Name = "Bill"..Height=176.4)..Data. although only when uppercase identifiers are used. This expression form should not be used in F# code and a future version of the F# language will issue a deprecation warning when this form is used.. M.. as must the type R. data4 uses a long identifier to indicate the relevant field: module M = type Data = { Age : int.Height = 186.tyN> is a named type.Age = 17.Data. Primitive record constructions are an elaborated form where the fields appear in the same order as in the record type definition.In the following example.tyN> for fresh types ty1. M2. which results in a set of fields FSeti.Height = 176. The set of fields must be complete.. After all field labels are resolved.1) on field-labeli.Data.. Name : string.. Each expri is then checked in turn with an initial type determined by the following procedure:   Assume the type of the corresponding field Fi in R<ty1.Data. Each field-labeli is a long-ident...tyN> is ftyi If the type of Fi prior to taking into account the instantiation <ty1. then the field label is resolved by performing Field Label Resolution (see §14.Age = 17.. Record expressions themselves elaborate to a form that may introduce let bindings to ensure that expressions are evaluated in the order that the field bindings appear in the original expression.. M. the overall record expression is asserted to be of type R<ty1. y = 2 } Note: The F# 2.

. field-labeln = exprn } is a copy-and-update record expression.. FM are the fields of R not given bindings by field-binds and v is a fresh variable..3.. vn -> let pat1 = v1 . ... then the initial type is a fresh type inference variable fty'i with a constraint fty'i :> ftyi.y) (z. Height = 186.0 } The expression expr is first checked with the same initial type as the overall expression...3. Height = 176.7 Function Expressions An expression of the form fun pat1 .. Each field label must resolve to a field Fi in a single record type R. incomplete match (x... the following does not raise an exception: let f = fun [x] y -> y let g = f [] // ok However...6. Name = "John". . Function expressions that involve non-variable pattern arguments elaborate as if they had been written as follows: fun v1 ... For example: (fun (fun (fun (fun x -> x + 1) x y -> x + y) [x] -> x) // note..FM } where F1 . the field bindings are resolved using the same technique as for record expressions.. Height : float } let data1 = { Age = 17. FM = v.w) -> x + y + z + w) Function expressions that involve only variable pattern arguments are a primitive elaborated form.. patn -> expr is a function expression. After all field labels are resolved. all of whose fields are accessible.tyN> is ftyi.0 } let data2 = { data1 with Name = "Bill"... 6. For example..  Otherwise the initial type is ftyi. For example. … . an exception is raised: let z = g 3 // MatchFailureException is raised 55 . Name : string. below data2 is defined using such an expression: type Data = { Age : int. … .tyN> is a named type..tyN> for fresh types ty1. if a third line is added. F1 = v.F1... field-labeln = exprn. let patn = vn expr No pattern matching is performed until all arguments have been received. Each field-labeli is a long-ident.. the overall record expression is asserted to be of type R<ty1.. Copy-and-update expressions elaborate as if they were a record expression written as let v = expr in { field-label1 = expr1 . If the type of Fi prior to taking into account the instantiation <ty1.tyN. Each expri is then checked in turn with initial type given by the following procedure:   Assume the type of the corresponding field Fi in R<ty1.6 Copy-and-update Record Expressions An expression of the form { expr with field-label1 = expr1 . Subsequently.

Finalize() = printfn "Finalize".Object() with member x.b) = compare (a % 7) (b % 7) } let obj2 = { new System. interface System. The keyword member can be used even when overriding a member or implementing an interface. For example obj4 in the preceding examples has static type System.Object but the object additionally implements the interface System. For each member. The overall type of the expression is ty0 and is asserted to be equal to the initial type of the expression. each tyi must be an interface type.4).  First. an attempt is made to associate the member with a unique dispatch slot using dispatch slot inference (§14. Note: In the case of the interface declarations.  Apart from ty0. then the overall type is instead ty1. The additional interfaces are not part of the static type of the overall expression.ToString() } let obj4 = { new System. if ty0 is type equivalent to System.  The type ty0 must be a class or interface type.IComparer<int> with member x. For example: let obj1 = { new System. override or default.Collections.IDisposable.ToString() = " + base.Object and where ty1 exists. Lexical filtering inserts simulated $end tokens when lightweight syntax is used. base.3.6.ToString () = "Hello. then the argument types and return type of the member are constrained to be precisely those of the dispatch slot.Dispose() = printfn "Dispose". the call to these constructors is resolved and elaborated using Method Application Resolution (see §14. However. Object expressions are statically checked as follows.7). Note: Object expression members can each use the keyword member. The base construction argument args-expr must be given if and only if ty0 is a class type.Object() with member x. The type must have one or more accessible constructors. ty0 to tyn are checked and must all be named types. Each set of object-members is of the form with val-or-member-defns endopt.Generic.ToString () = "Hello" } let obj3 = { new System.Object() with member x. } An object expression can specify additional interfaces beyond those required to fulfill the abstract slots of the type being implemented.IDisposable with member x.Compare(a. 56 . If a unique matching dispatch slot is found.8 Object Expressions An expression of the form { new ty0 args-expropt object-members interface ty1 object-members1 … interface tyn object-membersn } is an object expression. but can be revealed through type tests. the object-members are optional and are considered empty if absent.

} use . } try .. } while .. Each member of an object expression can initially access the protected members of ty0.3.10 Computation Expressions The following expression forms are all computation expressions: expr expr expr expr expr expr expr expr expr expr { { { { { { { { { { for .. The object must satisfy dispatch slot checking (§14.. For example: lazy (printfn "hello world") is syntactic sugar for new System.... the ―this‖ value for the member is in scope and has type ty0.Lazy library type ensures expression expr is evaluated on demand in response to a ..IsAnonymous = true } 6.Object() with member i. } 57 .. 6... type public INewIdentity = abstract IsAnonymous : bool let anon = { new System.ToString() = "anonymous" interface INewIdentity with member i. The following example shows how to both implement an interface and override a method from System.. } return . } yield ... and are subject to the same limitations as byref values described in §14. The arguments.. Object expressions elaborate to a primitive form and execute by creating an object whose runtime type is compatible with all of the tyi with a dispatch map that is the result of dispatch slot checking.. and in each member a base variable with this name is in scope. The overall type of the expression is INewIdentity.3.9 Delayed Expressions An expression of the form lazy expr is a delayed expression... Base variables can only be used in the member implementations of an object expression. } let! .8) which ensures that a one-to-one mapping exists between dispatch slots and their implementations..Lazy (fun () -> expr) The behavior of the System. then it must be named base. } yield! . } return! .Value operation on the lazy value.9. If the variable base-ident is given.Object. patterns and expressions implementing the bodies of all implementing members are next checked one by one as follows: o o o For each member. } let ..

Bind(expr.TryFinally( {| cexpr |}Delayed.. {| cexpr |}C b. (fun () -> expr)) = b. {| cexpr1 |}C = other-expr. b.More specifically.Delay(fun () -> {| cexpr |}C). cexpr1 |} {| other-expr |} Where   The auxiliary translation {| cexpr |}Delayed is b. excluding the final rule. cexpr1 |} {| other-expr0 .For({| expr |}E.For({| seq { expr1 .Zero() 58 . {| cexpr |}Delayed) {| try cexpr with pati -> cexpri |}C = b. (fun pat -> {| cexpr |}C)) {| while expr do cexpr |}C = b.Using(expr.Bind(expr. The translation {| _ |}C is defined recursively as follows: {| let binds in cexpr |}C {| let! pat = expr in cexpr |}C {| do expr in cexpr |}C {| do! expr in cexpr |}C {| yield expr |}C {| yield! expr |}C {| return expr |}C {| return! expr |}C {| use pat = expr in cexpr |}C {| use! v = expr in cexpr |}C = = = = let binds in {| cexpr |}C) b. A trans-cexpr0 is any syntactic expression form given an explicit translation by the above rules. (fun v -> match v with | (pati:exn) -> {| cexpri |}C | _ -> reraise exn) {| try cexpr finally expr |} {| trans-cexpr0.Return(expr) = b.Combine({| trans-cexpr0 |}C. (fun v -> b.Run (b. The type of b must be a named type after the checking of builder-expr. (fun pat -> {| cexpr |}C)) {| for ident = expr1 to expr2 do expr3 |}C = b.Using(v.ReturnFrom(expr) = b.TryWith({| cexpr |}Delayed. The expression builder-expr { cexpr } translates to let b = builder-expr in b. (fun () -> {| cexpr |}C)) = b. (fun pat -> {| cexpr |}C)) = b.Zero() {| if expr then cexpr0 else cexpr1 |}C = if expr then {| cexpr0 |}C else {| cexpr1 |}C {| match expr with pati -> cexpri |}C = match expr with pati -> {| cexpri |}C {| for pat in expr do cexpr |}C = b.Bind(expr.While((fun () -> expr). (fun pat -> {| cexpr |}C)) expr. the grammar of expressions with the additional constructs defined in comp-expr. Computation expressions are used for sequences and other non-standard interpretations of the F# expression syntax. if no method Delay exists on the type of b when this expression is checked. {| cexpr1 |}Delayed) = other-expr. Likewise. This expression is then checked. then that call is omitted. syntactically. then that call is omitted.Yield(expr) = b.Delay(fun () -> {| cexpr |}C)) for a fresh variable b. = b. computation expressions are of the form builder-expr { cexpr } where cexpr is. expr2 }|}E.(fun v -> {| cexpr |}C))) {| if expr then cexpr0 |}C = if expr then {| cexpr0 |}C else b. If no method Run exists on the inferred type of b when this expression is checked.YieldFrom(expr) = b.

try/finally can have subtle semantics and you may simply decide to only allow try/with. or neither. 2.IEnumerable<ty>. up to a time limit. /// for example. for some type ty. where the Combine and Zero operations do not follow the same pattern. Zero returns the empty sequence. /// Note combinators like this are usually written in the reverse way. The normal rule when implementing a monad in F# is that you really only need to implement Bind. You may wish to restrict the use of certain syntactic forms within sequence expressions. This translation implicitly places type constraints on the expected form of the builder methods.IDisposable member Bind: Async<'T> * ('T -> Async<'U>) -> Async<'U> member TryFinally: Async<'T> * (unit -> unit) -> Async<'T> member TryWith: Async<'T> * (exn -> Async<'T>) -> Async<'T> Note: The computation expression syntax allows the smooth embedding of computational structures known as monoids and monads.Generic. TryFinally and TryWith methods are needed for three reasons: 1. Using. /// e |> bind k 59 .6. The auxiliary translation {| _ |}E converts expr to a value compatible with the type System. these correspond to implementing a builder of a type with the following member signatures: type AsyncBuilder with member For: seq<'T> * ('T -> Async<unit>) -> Async<unit> member Zero : unit -> Async<unit> member Combine : Async<unit> * Async<'T> -> Async<'T> member While : (unit -> bool) * Async<unit> -> Async<unit> member Return : 'T -> Async<'T> member Delay : (unit -> Async<'T>) -> Async<'T> member Using: 'T * ('T -> Async<'U>) -> Async<'U> when 'U :> System. using enumerable extraction §6. For example. The impedance matching is known as “binding. Some operators such as Delay often have more efficient implementations than their boilerplate implementation in terms of bind and return.FSharp. for the async builder found in the Microsoft.Control library. For.5. While. F# computation expressions can also be used to implement monoids. lazy computations) and regular F# coding constructs. for example. Combine appends two sequences.” and is the code that implements the impedance matching is inserted automatically by the computation expression machinery at points such as let!. Everything else you need is boilerplate code.ModuleSuffix)>] module Eventually = /// The bind for the computations. Combine. Return and (optionally) a “try/with” primitive. for example. A monad is a way of automatically doing impedance matching between one kind of computation (for example. For example. There is no “bind” in this case. The following example shows a common approach to implementing a new computation expression builder for a monad. /// Computations that can cooperatively yield by returning a continuation type Eventually<'T> = | Done of 'T | NotYetDone of (unit -> Eventually<'T>) [<CompilationRepresentation(CompilationRepresentationFlags. Stitch 'k' on to the end of the computation. 3.Collections. The example uses computation expressions to define computations that can be "partially run" by executing them step-by-step. Implementations of the Delay. and For concatenates lots of sequences.

let tryFinally e compensation = catch (e) |> bind (fun res -> compensation(). let step c = match c with | Done _ -> c | NotYetDone f -> f () // The rest of the operations are boiler plate /// The tryFinally operator. a tailcall | Exception e -> result (Exception e)) /// The delay operator. "catch" and "bind". let delay f = NotYetDone (fun () -> f()) /// The stepping action for the computations. match res with | Ok v -> result v | Exception e -> raise e) /// The tryWith operator. let tryWith e handler = catch e |> bind (function Ok v -> result v | Exception e -> handler e) /// The whileLoop operator. /// This is boiler-plate in terms of "result" and "bind". /// This is boiler-plate in terms of "result".Exception /// The catch for the computations. "catch" and "bind". Stitch try/with throughout /// the computation and return the overall result as an OkOrException. let combine e1 e2 = e1 |> bind (fun () -> e2) 60 . let result x = Done x type OkOrException<'T> = | Ok of 'T | Exception of System. let rec whileLoop gd body = if gd() then body |> bind (fun v -> whileLoop gd body) else result () /// The sequential composition operator /// This is boiler-plate in terms of "result" and "bind". /// This is boiler-plate in terms of "result". let rec catch e = match e with | Done x -> result (Ok x) | NotYetDone work -> NotYetDone (fun () -> let res = try Ok(work()) with | e -> Exception e match res with | Ok cont -> catch cont // note.let rec bind k e = match e with | Done x -> NotYetDone (fun () -> k x) | NotYetDone work -> NotYetDone (fun () -> bind k (work())) /// The return for the computations.

Combine(e1.Dispose()) // Give the mapping for F# computation expressions.Bind(e.delay f member x.Using(resource..GetEnumerator() tryFinally (whileLoop (fun () -> ie.e2) = Eventually.Current in f v))) (fun () -> ie.Dispose()) /// The forLoop operator.tryFinally e compensation member x.Return(v) = Eventually.Delay(f) = Eventually../// The using operator.bind k e member x.combine e1 e2 member x.TryWith(e.‖ For example: let step x = Eventually. 2 do printfn " x = %d" x return 3 + 4 } These computations can now be ―stepped.TryFinally(e.MoveNext()) (delay (fun () -> let v = ie.compensation) = Eventually.e) = Eventually.f) = Eventually. computations can now be built using eventually { .forLoop e f member x..result v member x.handler) = Eventually.Zero() = Eventually. "result" and "bind".using resource e let eventually = new EventuallyBuilder() Once defined.IDisposable) f = tryFinally (f resource) (fun () -> resource. let forLoop (e:seq<_>) f = let ie = e.result () member x. type EventuallyBuilder() = member x.k) = Eventually.step x comp |> step // returns "NotYetDone <closure>" comp |> step |> step // prints "x = 1" // returns "NotYetDone <closure>" comp |> step |> step |> step |> step |> step |> step // prints "x = 1" // prints "x = 2" // returns ‚NotYetDone <closure>‛ comp |> step |> step |> step |> step |> step |> step |> step |> step // prints "x = 1" // prints "x = 2" // returns "Done 7" 61 .For(e:seq<_>.ReturnFrom(v) = v member x. let using (resource: #System. }: let comp = eventually { for x in 1 . /// This is boiler-plate in terms of "catch".tryWith e handler member x.

this builder type is not actually defined in the F# library.Using (resource.YieldFrom (s:seq<_>) = s member x..Return (():unit) = Seq. 3 ] do for y in [5. expr2 |} {| for pat in expr1 -> expr2 |} {| for pat in expr1 do expr2 |} {| while expr1 do expr2 |}       Seq.IEnumerator<ty> whose MoveNext.Generic.EnumerateWhile (fun () -> expr1) {| expr2 |})  SequenceExpressionHelpers.SeqBuilder. Seq.map (fun pat -> {| expr2 |}) expr1 Seq.empty  if expr then {| expr0 |}C else {| expr1 |}C {| try expr1 finally expr2 |} {| use v = expr1 in expr2 |} |} {| let v = expr1 in expr2 |} {| match expr with pati -> expri |} {| expr1 |} {| if expr then expr0 |}C {| if expr then expr0 else expr1 |} Here the use of Seq and SequenceExpressionHelpers refers to the corresponding functions in Microsoft.append {| expr1 |} {| expr2 |} Seq.While (guard.match expr with pati -> {| cexpri |}  expr1 .Generic.Collections.singleton v member x.EnumerateUsing v {| expr2  let v = expr1 in {| expr2 |} . e2 . 6] do yield x + y } seq { for x in [ 1.xs2) = Seq.FSharp.compensation) = SequenceExpressionHelpers.3. 3 ] -> x + x } Logically speaking. e3 } 62 . Instead. This has a GetEnumerator method that returns a System. 2.11 Sequence Expressions An expression in one of the following forms is a sequence expression: seq { comp-expr } seq { short-comp-expr } For example: seq { for x in [ 1. This type can be considered to be defined as follows: type SeqBuilder() = member x. sequence expressions can be thought of as computation expressions with a builder of type Microsoft.EnumerateUsing resource xs However.TryFinally (xs.empty  if expr then {| expr0 |}C else Seq. 2.Collections. This means that a sequence expression generates an object of type System. seq { e1 .6.12 Range Expressions Expressions of the following forms are range expressions.EnumerateThenFinally xs compensation member x. Current and Dispose methods implement an on-demand evaluation of the sequence expressions..3.Seq. 6.Yield (v) = Seq.FSharp..For (xs.EnumerateWhile guard body member x.Collections.IEnumerable<ty> for some type ty.xs) = SequenceExpressionHelpers.Combine (xs1.append xs1 xs2 member x.collect (fun pat -> {| expr2 |}) expr1 SequenceExpressionHelpers.collect f xs member x. e2 } seq { e1 .singleton expr expr Seq.empty member x.Collections.g) = Seq. sequence expressions are elaborated directly as follows: {| yield expr |} {| yield! expr |} {| expr1 . 2. 3 ] do yield x + x } seq { for x in [ 1.EnumerateThenFinally (| expr1 |}) (fun () -> expr2)  let v = expr1 in SequenceExpressionHelpers.body) = SequenceExpressionHelpers.

) e1 e2 e3 The default definition of these operators is in Microsoft.Collections... can be omitted for simple range expressions. using an increment of 1 (as given by Microsoft. using an increment of expr2. 63 . 5. 8. 10 } // 1.3.FSharp. e3 } → (. e2 .. The (. 2 . and the corresponding forms with step ranges. expr2 are translated to uses of the (. 9.. expr2 |] .FSharp..)operator. 7.FSharp.13 Lists via Sequence Expressions An expression in one of the following forms [ comp-expr ] [ short-comp-expr ] [ range-expr ] is a list sequence expression. 6.toArray(seq { cexpr }).. 2. expr2 do expr3 done.Monday then yield 2] 6. In all cases [ cexpr ] elaborates to Microsoft.. yield 2 ] let x3 = [ yield 1 if System.DayOfWeek = System. . 4.) e1 e2 seq { e1 . the corresponding forms in computation expressions. expr2 ].. [| expr1 .3....5.. but this is not recommended and might be deprecated in a future release.GenericOne). expr2 do expr3 done is sometimes elaborated as a simple for loop-expression (§6. 7. Note: Range expressions also occur as part of the translated form of expressions such as [ expr1 .) operator generates an IEnumerable<_> for the range of values between the given start (expr1) and finish (expr3) values.Collections. e2 } → (. 3. The (.. It is always preferable to explicitly mark the type of a computation expression. expr3 are translated to uses of the (..Seq.Operators..14 Arrays via Sequence Expressions An expression in one of the following forms is an array sequence expression: [| comp-expr |] [| short-comp-expr |] [| range-expr |] In all cases [| cexpr |] elaborates to Microsoft. which denotes the type of computation expression.) operator: seq { e1 ..toList(seq { cexpr }).Range expressions generate sequences over a specified range.LanguagePrimitives.DateTime.. For example: seq { 1 .FSharp. for var in expr1 .) operator generates an IEnumerable<_> for the range of values between the given start (expr1) and finish (expr2) values.DayOfWeek.. 10 seq { 1 . A sequence iteration expression of the form for var in expr1 .7). 6. . 3. 9 Range expressions involving expr1 . 10 } // 1. For example: let x2 = [ yield 1.Now. and those involving expr1 ..Seq. expr1 ..Core. The seq keyword... 5. .

They are typically used with one of the functions printf.Now.'Result. int16. uint32.3. a constant string is interpreted as a printf-style format string if it is expected to have the type Microsoft. This induces a nullness constraint (§5. sprintf or bprintf in the Microsoft. The constraint ensures that the type directly supports the value null.DateTime.FSharp. yield 2 |] let x3 = [| yield 1 if System.2. %f. %i bool string char basic integer type byte.15 Null Expressions An expression in the form null is a null expression.16 'printf' Formats Format strings are strings with % markers indicating format placeholders.'Tuple>. 'Tuple is the type of the tuple of values generated by treating the string as a generator (for example.FSharp. uint64.DayOfWeek.PrintfFormat<'Printer.DayOfWeek = System.Decimal System. Format strings receive special treatment in order to type check uses of these functions more precisely. %G %M %O %A %a %t System. fprintf.Object a fresh variable type 'T a formatter of type 'State -> 'T -> 'Residue for a fresh variable type 'T a formatter of type 'State -> 'Residue 64 . int32.4. Format placeholders in the format string give rise to variations in these types as follows: %b %s %c %d. §5. of which 'Printer and 'Tuple are the most interesting:   'Printer is the function type generated by applying a printf-like function to the format string.3. %F. when the format string is used with a function similar to scanf in other languages).Core. 6.'Residue. nativeint or unativeint %u %x %X %o basic integer type basic integer type basic integer type basic integer type float or float32 %e. A format placeholder has the following shape: %[flags][width][.Printf module. More concretely. sbyte.Core. Format strings are analyzed at compile time and annotated with static and runtime type information as a result of that analysis.2. %g. Null expressions are a primitive elaborated form. uint16. int64.Monday then yield 2 |] 6. %E. The string is statically analyzed to resolve the generic parameters of the PrintfFormat type.8) on the initial type of the expression.'State.precision][type].For example: let x2 = [| yield 1.

Math."Three") System.4. Applying printf to it yields a function of type string -> int -> string -> unit. +.Environment.2.[slice-range] expr.Generic.2).4. and item lookups.Collections. dot-notation lookups. -.' long-ident-or-op expr expr expr(expr) expr<types> expr< > type expr -------long-ident lookup expression dot lookup expression application expression high precedence application expression type application expression type application expression (empty type list) simple object expression Some examples of application expressions are: System.GetEnvironmentVariable("PATH").Object().2. 'c. The width is an integer that represents the minimum number of characters in the result.(string * int * string)> for fresh variable types 'b. To check an application expression. 'd. slice-range] -----infix application expression prefix application expression indexed lookup expression slice expression (1D) slice expression (2D) Assignment expressions are processed in a similar way to application expressions and are covered in §6. and a compile-time error will be reported if it is used.1 Basic Application Expressions Application expressions involve variable names.Console.9: | expr <.[expr] expr.Object() System.Collections.KeyValuePair(3. function applications.ToString() System.List<int>(10) System.[1] If the long-ident-or-op starts with the special pseudo-identifier keyword global.Valid flags are: 0.[slice-range. For example. 'b. 'd.GetType() System.PI. the expression form is repeatedly decomposed into a lead expression expr and a list of projections projs through the use of Unqualified Lookup (§14. the format string "%s %d %s" is given the type PrintfFormat<(string -> int -> string -> 'd). type applications.expr -.Math.Dictionary<int. 'c. The # flag is invalid.int>(10).PI The following are also application expressions because of their expansion as syntactic sugar: | | | | | expr infix-op expr prefix-op expr expr. ignoring all open directives (see §14.Length System.System.ToString() (3 + 4).Collections.1). For example: global. 6. and the space character. | | | | | | | long-ident-or-op expr '.Generic.4 Application Expressions 6.Generic. method applications. then the identifier is resolved with respect to the global namespace—that is. 65 .WriteLine("Hello World") Application expressions may start with object construction expressions that do not include the new keyword: System.PI System. This in turn uses procedures such as ExpressionQualified Lookup and Method Application Resolution.Math.assignment expression The checking of application expressions is described in detail as an algorithm in §14.

If ty is a named class or struct type. System.Forms. en) is an object construction expression and constructs a new instance of a type.List<int>() System.Forms.4). and the struct type does not have a constructor method that takes zero arguments.Forms.Environment.  Otherwise. checking an application expression results in an elaborated expression that contains a series of lookups and method calls.Windows. n is 0.Form(Text="Text") elaborates to let v = new System.Environment. If ty is a struct type. new System.Form() in v.2 Object Construction Expressions An expression of the form new ty(e1 . usually by calling a constructor method on the type. the type must have one or more accessible constructors.Windows. v for some fresh variable v. For example.GetEnvironmentVariable elaborates to (fun v -> System. then the expression elaborates to the default ―zero-bit pattern‖ value for the given struct type.. union or tuple type.Generic.Windows.2. For example. record.set_Text("Text").GetEnvironmentVariable(v)) for some fresh variable v. 6.  The use of post-hoc property setters results in the insertion of additional assignment and sequential execution expressions in the elaborated expression. then:   ty must not be abstract.4.As described in §14. The elaborated expression may include:       Uses of named values Uses of union cases and primitive record constructions Applications of functions Applications of static and instance methods (including those to access properties) and object constructors Uses of fields.Collections. The overloading between these potential constructors is resolved and elaborated using Method Application Resolution (see §14. 66 .. both static and instance Uses of active pattern result elements Additional constructs may be inserted when resolving method calls into simpler primitives:  The use of a method or value as a first-class function may result in additional resolved ―let‖ bindings and function expressions.Object() System.Form (Text="Hello World") 'T() The initial type of the expression is first asserted to be equal to ty.  The use of optional arguments results in the insertion of Some(_) and None data constructions in the elaborated expression. For example: new new new new System. The type ty must not be an array.

4) The %expr and %%expr expression splice operatorsin quotations (§6.4. The expression may resolve to a specific definition of a userdefined or library-defined operator.b) 3 +++ 4 In some cases. These rules are applied after applying the rules for late binding operators (§6. Exceptions returned by this function are wrapped on return using System.CLI default constructor constraint .2).tyn) -> rtyA.FSharp.CreateInstance<ty>().1) imply that the operator resolves to an expression that implicitly uses a static member invocation expression (§6.Core..If ty is a delegate type then this is a delegate implementation expression. then the name resolution rules (§14. -. then the overall expression must be in the form new ty(expr) where expr has type ty1 -> . 67 .5) The expr && expr and expr || expr shortcut control flow operators (§6. /.CreateInstance<ty>(). the operator name will resolve to a standard definition of an operator defined in the F# library. The type variable is constrained as follows: ty : (new : unit -> ty)  -. -> tyn -> rtyB. >>>. that is.3 Operator Expressions Operator expressions are specified in terms of their shallow syntactic translation to other constructs. in the absence of an explicit definition of (+). Some operators defined in the F# library receive special treatment in this specification.. For example. %. |||. then   There must be no arguments (that is.4). If type rtyA is a CLI void type then rtyB is unit.Activator... 3 + 4 resolves to a use of the infix operator Microsoft. If the operator does not resolve to a user-defined or library-defined operator.. &&&.LanguagePrimitives. The parenthesized operator name is then treated as an identifier and the standard rules for unqualified name resolution (§14. see §17. the overall expression must be of the form new ty(fun pat1 If ty is a type variable. which in turn calls System. In particular:     The &expr and &&expr address-of operators (§6. The expression elaborates to a call to Microsoft. patn -> exprbody). **. For example: let (+++) a b = (a. <<<. which in turn uses CLI reflection to find and call the nullary object constructor method for the given type.3) The library-defined operators (such as +..4.IntrinsicFunctions.Operators.. 6. The following translations are applied in order: infix-or-prefix-op e1 prefix-op e1 e1 infix-op e2 → (~infix-or-prefix-op) e1 → (prefix-op) e1 → (infix-op) e1 e2 Note: When an operator that may be used as an infix or prefix operator is used in prefix position.  If any of the types tyi is a byref-type then an explicit function expression must be specified. *..1) in expressions are applied.FSharp.TargetInvocationException. n = 0).4.4.5.Core. otherwise it is rtyA.  If the delegate type has an Invoke method with an actual signature Invoke(ty1.8. ^^^.(+). a tilde character ~ is added to the name of the operator.8) that involves the types of the operands.

4 Late Binding Operator Expressions Expressions of the form expr1 ? expr2 and expr1 ? expr2 <. field. it is not applied to (?) x y 6. For example. For &expr and &&expr .message:string) = Receiver(message) static member (-->) (message."Message One" "Message Two" --> r 6.9. byref-valued argument.3.5 The AddressOf Operators Under default definitions. Note: The F# core library FSharp.expr3 → → → → (?) expr "ident" (?) expr1 expr2 (?<-) expr1 "ident" expr2 (?<-) expr1 expr2 expr3 Here "ident" is a string literal that contains the text of ident. this means that the effective behavior of operators that are not defined in the F# library is to require a static member.dll does not give a default definition for the (?) and (?<-) operators.For example. based on a type-directed resolution: type Receiver(latestMessage:string) = static member (<--) (receiver:Receiver. DefinitelyMutates).4. However. It is not applied to uses of the parenthesized operator names. In the following code. with the same name as the operator.receiver:Receiver) = Receiver(message) let r = Receiver "no message" r <-.expr2 expr1 ? (expr2) <. called byref-address-of expression and nativeptr-address-of expression respectively. and the expression expr is checked with initial type ty. the use of the otherwise undefined operator --> resolves to the static member on the Receiver type. written AddressOf(expr. on type of one of the operands of the operator.Core. the initial type of the overall expression must be of the form byref<ty> and nativeptr<ty> respectively. it is common to define the operators to perform a dynamic lookup on the reflection properties of an object or on the dynamic results of a regular expression match. These expressions take the address of a mutable local variable. for example. user code may define these operators.expr3 are late binding operator expressions which simplify the process of writing code that uses late binding. 68 . expressions of the forms &expr &&expr are address-of expressions. or static mutable global variable. The overall expression is elaborated recursively by taking the address of the elaborated form of expr. defined in §6. This syntactic translation is applied regardless of the definition of the (?) and (?<-) operators. array element.4. Such expressions are defined by their syntactic translation: expr ? ident expr1 ? (expr2) expr1 ? ident <.

Addresses generated by the && operator must not be passed to functions that are in tail call position.get_Item(e2.IntrinsicOperators. e5] <. array types of rank 1. 69 . use a value of type nativeptr<ty>.e4 e3.[e2] e1. which are defined in the F# core library when applied to one argument.Item : int * int * int -> 'T type 'T[. Their use is recommend only to pass addresses where byref or nativeptr parameters are expected.6 Lookup Expressions Lookup expressions are specified in terms of their shallow syntactic translation to other constructs: e1. e5. 2. e1. e4) e4. if type checking determines that the type of e1 is a named type that supports the DefaultMember attribute.IntrinsicOperators. e3) e3.] with member arr. and a warning or error will typically be given if this is possible.FSharp. Note: The rules in this section apply to uses of the following prefix operators.e5 e3.. e3. e1.Item : int * int * int * int -> 'T In addition. e5) e4. these types may NOT be used within named types such as tuples or function types. then the member name identified by the DefaultMember attribute is used instead of Item. e1. e3] e3.LanguagePrimitives. e1. e1.] with member arr. 3 and 4 are assumed to support a type extension that defines an Item property with the following signatures: type 'T[] with member arr.FSharp.NativeInterop module may also result in the generation of invalid or unverifiable CIL code. In particular.set_Item(e2.4. e3.Core.[e2.get_Item(e2.set_Item(e2.(~&) Microsoft.(~&&) Other uses of these operators are not permitted.Item : int * int -> 'T type 'T[.[e2.[e2] e1. They may be used as the argument type specifications of DllImport annotated functions and class member signatures.get_Item(e2. e3) e3.[e2.LanguagePrimitives..e6 → → → → → → → → e1.. e4] <. e4. e1.Item : int -> 'T type 'T[.FSharp. or to pass a byref parameter on to a subsequent function. e1.e3 e3] <. e1. 6.[e2. e5) e4) e4. so their use is highly constrained.Core. The F# compiler does not check for this. e5] <.[e2. for the purposes of resolving expressions of this form. e4] e3.get_Item(e2) e1. e4. e6) In addition. or when interoperating with native code. Direct uses of the named types byref and nativeptr and values in the Microsoft.set_Item(e2. e1.[e2. e1.set_Item(e2.] with member arr. When calling an existing CLI signature that uses a CLI pointer type ty*. e1. Microsoft. e3.Note: Use of these operators may result in unverifiable or invalid CIL code .

GetSlice : ?start1:int * ?end1:int -> 'T[.] type 'T[. e3 .arg3.4. a statically resolved member constraint static-typars : (member-sig) is applied (§5.None.None) is present and None otherwise.Speak() = "I'm a dog" 70 .GetSlice(None.*] opt opt ] → → → → e1. At least one ei opt opt where argi is Some(ei opt opt must be present. Note: Static member constraint invocation expressions are necessarily used in inlined code.None. e3 ] opt opt e1.None) e1.GetSlice(None.arg5) e1.arg3) → e1... For example: let inline speak (a: ^a) = let x = (^a : (member Speak: unit -> string) (a)) printfn "It said: %s" x let y = (^a : (member MakeNoise: unit -> string) (a)) printfn "Then it went: %s" y type Duck() = member x.arg3) e1.[e2 . A similar translation is used for 2D slices: e1.[*] opt opt ] ) if ei opt → e1. The elaborated form of the expression is a member invocation to the member on the type that causes the type to satisfy the member constraint. e3 .Speak() = "I'm a duck" member x.arg4.GetSlice(arg2.None) Because this is a shallow syntactic translation...3).GetSlice(arg2.arg3.. CIL array types of rank 1 to 4 are assumed to support a type extension that defines a method GetSlice with the following signature: type 'T[] with member arr. e3 e1.GetSlice(arg2.. the GetSlice name may be resolved by any of the relevant Name Resolution (§14..] type 'T[. *] e1.1) techniques.] with member arr.4.] 6.GetSlice : ?start1:int * ?end1:int * ?start2:int * ?end2:int -> 'T[. e4 . This is determined through the process of constraint solving and code inlining.GetSlice(None.None.] with member arr..8 Member Constraint Invocation Expressions An expression of the form (static-typars : (member-sig) expr) is a member constraint invocation expression.[e2 . For 1D slices: e1. ty is asserted to be equal to the return type of the constraint.7 Slice Expressions Slice expressions are specified in terms of their shallow syntactic translation to other constructs.arg2.MakeNoise() = "quack" type Dog() = member x.[*.2.6. In addition.None...[*.] with member arr.[e2 .GetSlice : ?start1:int * ?end1:int * ?start2:int * ?end2:int * ?start3:int * ?end3:int * ?start4:int * ?end4:int -> 'T[. e5 opt opt e1. including defining the method as a type extension for an existing type. e2 .GetSlice : ?start1:int * ?end1:int * ?start2:int * ?end2:int * ?start3:int * ?end3:int -> 'T[. and expr is checked with an initial type corresponding to the argument types of that constraint.. When such an expression is checked with initial type ty.] type 'T[.

o In this case expr2 is incorporated as the last argument in the method application resolution for the setter method and the overall elaborated expression is a method call to this setter property including the last argument. o In this case expr2 is then checked using expected result type ty. producing an elaborated expression expr2. 71 .field with actual result type ty.[expr1b] where expr1a has type ty[]. o In this case expr2 is then checked using expected result type ty.[expr1b] .  A reference to a mutable field expr1a.expr2 is an assignment expression. producing an elaborated expression expr2.3). A modified version of Unqualified Lookup (§14. producing an elaborated expression expr2. The overall elaborated expression is an assignment to a value reference path <-stobj expr2. This proceeds as normal except that the last qualification for expr1 must resolve to one of the following constructs:  An invocation of a (possibly indexer) property with a setter method.3). The overall elaborated expression is an assignment to a field AddressOf(expr1a. o In this case expr2 is then checked using expected result type ty.9.9.4. thus producing an elaborate expression expr1.member x. The overall elaborated expression is an assignment to a field AddressOf(expr1a.  A array lookup expr1a. producing an elaborated expression expr2.2.9 Assignment Expressions An expression of the form expr1 <.MakeNoise() = "grrrr" let x let y speak speak Outputs: It said: I'm a duck Then it went: quack It said: I'm a dog Then it went: grrrr = new Duck() = new Dog() x y 6. DefinitelyMutates) <-stobj expr2 (see §6. The overall elaborated expression is an assignment to a value reference &path <-stobj expr2.1) is applied to expression expr1 using a fresh expected result type ty.  A reference to a value path of type byref<ty>. o In this case expr2 is then checked using expected result type ty.  A mutable value path of type ty.field. DefinitelyMutates) <-stobj expr2 (see §6.

x <. The expression expr2 is then checked with the same initial type as the overall expression. Sequential execution expressions are a primitive elaborated form expr1.x <. expr2. expr2 is a sequential execution expression.5 Control Flow Expressions 6. After checking expr1.3 s4. and an additional syntax rule for lightweight syntax applies (§15. a $sep token is automatically inserted. If the assertion fails.3 s3. where “immediate” contents means the contents of a mutable value type. given [<Struct>] type SA = new(v) = { x = v } val mutable x : int [<Struct>] type SB = new(v) = { sa = v } val mutable sa : SA let let let let s1 = SA(0) mutable s2 = SA(0) s3 = SB(0) mutable s4 = SB(0) Then these are not permitted: s1. For example: printfn "Hello".1 Parenthesized and Block Expressions An expression of the form (expr) is a parenthesized expression and begin expr end is a block expression.2 Sequential Execution Expressions An expression of the form expr1.sa <.Note: the above interpretations of assignments means that local values must be mutable in order to mutate their immediate contents using primitive field assignments and array lookups.5.1.5. a warning rather than an error is reported. In this case.1).SA(2) 6. The expression expr is checked with the same initial type as the overall expression. The expression expr1 is checked with an arbitrary initial type ty.x <.sa. 3 Note: The . 72 . 6.x <. For example. The elaborated form of the expression is simply the elaborated form of expr. this means that the token can be omitted for sequential execution expressions that implement functions or immediately follow tokens such as begin and (. ty is asserted to be equal to unit.3 and these are: s2. In practice.sa. printfn "World". token is optional when both the expression expr2 occurs on a subsequent line that starts in the same column as expr1 and the current pre-parse context that results from the syntax analysis of the program text is a SeqBlock (§15).3 s4.

(&&) Microsoft.IntrinsicOperators. j -> printfn "j = %d" j | i.FSharp. For example. the expression form if expr1 then expr2 else expr3 is equivalent to: match (expr1:bool) with true -> expr2 | false -> expr3 If the else branch is omitted. For example: match (3. 2 -> printfn "i = %d" i | _ -> printfn "no match" 73 .Core.LanguagePrimitives. 6. then it is interpreted as a strict function that evaluates both its arguments before use.FSharp.5.3 Conditional Expressions An expression of the following form is a conditional expression: if expr1a then expr1b elif expr3a then expr2b … elif exprna then exprnb else exprlast The elif and else branches may be omitted.IntrinsicOperators. the expression is a sequential conditional expression and is equivalent to: match (expr1:bool) with true -> expr2 | false -> () with the exception that the initial type of the overall expression is first asserted to be unit. 6. For example: if (1 + 1 = 2) then "ok" else "not ok" if (1 + 1 = 2) then printfn "ok" Conditional expressions are equivalent to pattern matching on Boolean values.5.LanguagePrimitives. 2) with | 1.4 Shortcut Operator Expressions Under default definitions. expressions of the following form are respectively an shortcut and expression and a shortcut or expression: expr && expr expr || expr These are defined by their syntactic translation: expr1 && expr2 expr1 || expr2 → if expr1 then expr2 else false → if expr1 then true else expr2 Note: The rules in this section apply to uses of the operators Microsoft. If the operator is not immediately applied to two arguments.(||) defined in the F# core library when applied to two arguments. Pattern matching is used to evaluate the given expression and select a rule (§7).6.5.5 Pattern-Matching Expressions and Functions An expression of the form match expr with rules is a pattern-matching expression.Core.

except that a dynamic check is inserted to detect whether the enumerator satisfies IDisposable.1. then that type is used instead. in which case it is enumerated through a process known as enumerable extraction.IDisposable as d -> d. For example: for x.1). the loop is evaluated in much the same way.GetEnumerator() try while (v.. 4)] do printfn "x = %d. For example: function | 1. where x is a fresh variable: fun x -> match x with | 1. j -> printfn "j = %d" j | _ -> printfn "no match" 6. In particular. if the Current property has return type obj and the collection type ty has an Item property with a more specific (nonobject) return type ty2. (3.5.An expression of the form function rules is a pattern-matching function and is syntactic sugar for a singleargument function expression followed by immediate matches on the argument. Note: The done token is optional if expr2 appears on a later line and is indented from the column position of the for token. and an additional syntax rule for lightweight syntax applies (§15. the expression elaborates to the following. where v is of type IEnumerator<ty> and pat is a pattern of type ty: let v = expr1. and a dynamic cast is inserted to convert v.Current with | pat -> expr2 | _ -> () finally match box(v) with | :? System.Dispose() | _ -> () If the assertion fails. If the assertion succeeds. y = %d" x y The expression expr1 is checked with a fresh initial type tyexpr which is then asserted to be compatible with the type IEnumerable<ty>. a $done token is automatically inserted. then the type tyexpr may also be of any static type that satisfies the ―collection pattern‖ of CLI libraries. 2). j -> printfn "j = %d" j | _ -> printfn "no match" is syntactic sugar for the following. However. is elaborated as a simple for-loop expression (§6. expr2 do expr3 done where the type of expr1 or expr2 is equivalent to int. The type of pat is determined by the return type of the Current property on the enumerator value. In this case.MoveNext()) do match v. In this case. A sequence iteration of the form for var in expr1 .5.7) 74 . tyexpr may be any type that has an accessible GetEnumerator method that accepts zero arguments and returns a value that has accessible MoveNext and Current properties.Current to ty2. for a fresh type ty.6 Sequence Iteration Expressions An expression of the form for pat in expr1 do expr2 done is a sequence iteration expression. y in [(1.

and an additional syntax rule for lightweight syntax applies (§15.Today. For example: for x = 1 to 30 do printfn "x = %d.5. a $done token is automatically inserted. expr2 do expr3 done is always elaborated as a simple for-loop expression whenever the type of expr1 or expr2 is equivalent to int. 6.DayOfWeek. For-loops over ranges specified by variables are a primitive elaborated form.5.9 Try-with Expressions An expression of the form try expr with rules is a try-with expression. An expression of the form for var in expr1 . and an additional syntax rule for lightweight syntax applies (§15. For example: try "1" with _ -> "2" try failwith "fail" with | Failure msg -> "caught" | :? System.InvalidOperationException -> "unexpected" 75 .6. For example while System.5. A warning is reported if the body expr3 of the for loop does not have static type unit. x^2 = %d" x (x*x) The bounds expr1 and expr2 are checked with initial type int. The overall type of the expression is unit.7 Simple for-Loop Expressions An expression of the following form is a simple for loop expression: for var = expr1 to expr2 do expr3 done Note: The done token is optional when e2 occurs indented from the column position of the for token and on a subsequent line.Monday do printfn "I don't like Mondays" The overall type of the expression is unit.DayOfWeek = System. A warning will be reported if the body expr2 of the while loop cannot be asserted to have type unit. The expression expr1 is checked with initial type bool.8 While Expressions An expression of this form is a while loop expression: while expr1 do expr2 done Note: The done token is optional when expr2 occurs indented from the column position of the while and on a subsequent line.1. The elaborated form of a simple for loop expression is: let start = expr1 in let finish = expr2 in for var = start to finish do expr3 done for fresh variables start and finish. with an increment of 1. 6.1). In this case.. a $done token is automatically inserted.1).DateTime.1. In this case. When executed the iterated range includes both the starting and ending values in the range.

For example: try "1" finally printfn "Finally!" try failwith "fail" finally printfn "Finally block" Expression expr1 is checked with the initial type of the overall expression.1 Binding Expressions An expression of the form let binding in expr is a binding expression and establishes bindings within the local lexical scope of body-expr and has the same overall type as expr. 6.5. The pattern matching clauses are then checked with the same initial type and with input type System.Assert is a conditional method call. and a warning is given if this type cannot then be asserted to be equal to unit.Core.10 Reraise Expressions The F# library function reraise must be applied to an argument and can be used only on the immediate righthand side of rules in a try-with expression. 6.Operators.11 Try-finally Expressions try expr1 finally expr2 is a try-finally expression. 6. 6.Debug. Try-finally expressions are a primitive elaborated form.Assert(expr) Note: System. This means that assertions will not be triggered unless the DEBUG conditional compilation symbol is defined.6. Try-with expressions are a primitive elaborated form.6 Binding Expressions 6.12 Assertion Expressions An expression of the form assert expr is an assertion expression. Expression expr2 is checked with arbitrary initial type.Exception. reraise() Note: The rules in this section apply to any use of the function Microsoft.5.reraise defined in the F# core library.Diagnostics.Debug. 76 . try failwith "fail" with e -> printfn "Failing".FSharp.Expression expr is checked with the same initial type as the overall expression.Diagnostics. The expression assert expr is syntactic sugar for System.5.

id "Three") and let swap (x.1) For example: let x = 1 x + x and let x. and an additional syntax rule for lightweight syntax applies (§15. y) = (y. In this case. it defines one or more values by matching a pattern against an expression: mutableopt accessopt pat typar-defnsopt return-typeopt = rhs-expr then            If pat is a single value pattern ident. (3. typars1 and expr1 are as defined in §14. where ident1. Otherwise. y = ("One". 2). a $in token is automatically inserted. 4 ] Binding expressions are checked by first checking binding (§14.6). the resulting elaborated form of the entire expression is let tmp <typars1… typarsn> = expr in let ident1 <typars1> = expr1 in … let identn <typarsn> = exprn in body-expr. 1) x. If the binding is a value definition. 3.Note: The in token is optional when expr occurs on a subsequent line aligned with the token let.6. 77 . 2. 4) ] and let K x y = x in List.1. where tmp is a fresh identifier and each identi/typarsi/expri arises from the compilation of the pattern pat (§7) against the input tmp. that is. the resulting elaborated form of the entire expression is let ident1 <typars1> = expr1 in body-expr.x) List. The body expr is checked against the initial type of the overall expression.Length + y and let id x = x in (id 3.map swap [ (1.map (K 3) [ 1. This defines a set of identifiers identj with inferred types tyj and these are added to the name resolution environment with type tyj.

has at least one argument pattern)..10). When one or more of the bindings specifies a value. In this case. which differ from those applied to ―let‖ bindings in class definitions (§8. Any custom attributes specified on the declaration.2). inlineopt accessopt ident-or-op typar-defnsopt pat1 . Recursive bindings where all the values on the right-hand side are functions or lazy evaluations are a primitive elaborated form. the recursive expressions are analyzed for safety (§14.v + 1 printfn "v = %d" v These variables are under the same restrictions as values of type byref<_> (§14. the bindings define a set of recursive functions.2. typars1 and expr1 are as defined in §14. the following expression is rejected: let f<'T> (x:'T) = x in f 3   ―Let‖ bindings in expressions are not public and are not subject to arity analysis (§14. That is. For example: let rec twoForward count = printfn "at %d.9).3). ―Let‖ bindings may be marked as mutable.If the binding is a function definition.10):  ―Let‖ bindings in expressions may not define explicit generic parameters (§5. 6.1) twoForward 1 Normally. For example: let mutable v = 0 while v < 10 do v <. ―Let‖ bindings in expressions are subject to the following rules. modules (§10. and are similarly implicitly dereferenced. each binding specifies a function (that is.. taking one step back " count twoForward (count . expression bindings may not have the ThreadStatic or ContextStatic attributes.6.6. that is. patn return-typeopt = rhs-expr Then the resulting elaborated form of the entire expression is   let ident1 <typars1> = expr1 in body-expr where ident1. As a result.2 Recursive Binding Expressions.6. within all of the expressions on the right-hand side of the bindings in bindings. parameters and/or return arguments are ignored and a warning is given if these are present. The variables bound are available for use within their own definitions. This may result in warnings (including some reported as compile-time errors) and runtime checks. An expression of the form let rec bindings $in expr is a recursive binding expression.6. 78 . Multiple bindings may be defined by using let rec … and ….3.1) and computation expressions (§6.7). taking two steps forward" count if count = 1000 then "got there!" else oneBack (count + 2) and oneBack count = printfn "at %d.

6. the Dispose method is called on the variable‘s value when the variable goes out of scope.GetEnumerator() (upcast 1 : obj) The initial type of the overall expression is ty. For example: use inStream = System. Static coercions are a primitive elaborated form. Expression expr is checked using a fresh initial type tye. so the target type is the initial type of the overall expression. For example: (1 : int) let f x = (x : string) + x When checked.3 Deterministic Disposal Expressions An expression of the form use ident = expr1 in expr2 is a deterministic disposal expression. the initial type of the overall expression is asserted to be equal to ty.7.1). Thus the overall expression elaborates to let ident = expr1 try expr2 finally (match (ident :> obj) with | null -> () | _ -> (ident :> System.Dispose()) 6. Only one variable may be defined by the binding.IO.IDisposable). a flexible type constraint.7 Type-Related Expressions 6.3] :> seq<int>).6.7. that is.1 Type-Annotated Expressions An expression of the form expr : ty is a type-annotated expression where ty indicates the static type of expr. with constraint tye :> ty.ReadLine() (line1. 79 .IDisposable. For example: (1 :> obj) ("Hello" :> obj) ([1. If the dynamic value of the expression after coercion to type obj is non-null.OpenText "input.line2) The expression is first checked as an expression of form let ident = expr1 in expr2 (§6.2 Static Coercion Expressions An expression of the form expr :> ty is a static coercion expression.File. which results in an elaborated expression of the form: let ident1 : ty1 = expr1 in expr2. The expression upcast expr is equivalent to expr :> _. and the binding is not generalized. The expression elaborates to the elaborated form of expr.txt" let line1 = inStream.ReadLine() let line2 = inStream. Note: This ensures information from the annotation will be used during the analysis of expr itself. The type ty1.2. 6. is then asserted to be a subtype of System. Expression expr is then checked with initial type ty.6.

7. The type tye must not be sealed. then ty :> tye is asserted. the expression forms capture the enclosed expression in the form of a typed abstract syntax tree.FSharp. 6. The downcast e1 is equivalent to expr :?> _. Expression expr is checked using a fresh initial type tye. If type ty is sealed. For example: ((1 :> obj) :? int) ((1 :> obj) :? string) The initial type of the overall expression is bool.4 Dynamic Coercion Expressions An expression of the form expr :?> ty is a dynamic coercion expression.Quotations namespace in the F# core library. A warning is given if tye coerces to ty. or if type tye is not an interface type.6. Expression expr is checked using a fresh initial type tye.3 Dynamic Type-Test Expressions An expression of the form expr :? ty is a dynamic type-test expression. 6. In both cases.8 Quoted Expressions An expression in one of these forms is a quoted expression: <@ expr @> <@@ expr @@> The former is a strongly typed quoted expression. then ty :> tye is asserted. After these checks:     The type tye must not be a variable type. and the latter is a weakly typed quoted expression. Dynamic type tests are a primitive elaborated form. seethe documentation for the Microsoft. For example: let obj1 = (1 :> obj) (obj1 :?> int) (obj1 :?> string) (downcast obj1 : int) The initial type of the overall expression is ty.7. so the target type is the initial type of the overall expression. or if ty is a variable type. The exact nodes that appear in the expression tree are dictated by the elaborated form of expr that arises from checking. After checking:     The type tye must not be a variable type. or if ty is a variable type. The type tye must not be sealed. or if type tye is not an interface type. If type ty is sealed. Dynamic coercions are a primitive elaborated form. 80 . A warning is given if tye coerces to ty. Note: For the specification of the nodes that may be encountered.

Call. the following limitations apply to the constructs that may be used in a quoted expression:   Quotations may not use object expressions.Quotations.8. and type-bound members. or member may be annotated with the ReflectedDefinition attribute.TryGetReflectedDefinition.Quotations.Expr.Expr<ty> for a fresh type ty. For example: let id x = x let f (x : int) = <@ id 1 @> In this case the value appears in the expression tree as a node of kind Microsoft.FSharp. The expression expr is checked with fresh initial type ty. in which case the expression tree that forms its definition may be retrieved dynamically using the Microsoft.FSharp.Quotations.  References to expression-bound values.FSharp. For example: <@ 1 + 1 @> <@ (fun x -> x + 1) @> The initial type of the overall expression is asserted to be of the form Microsoft.Expr. these should be type-annotated to refer to a specific type or be lifted to be module-bound functions or class-bound members. the initial type of the overall expression is asserted to be of the form Microsoft.Expr.8. 6. value. which is defined in the F# library.Quotations. In F# 2.  References to generic type parameters or uses of constructs whose type involves a generic parameter.In particular. quotations may contain:  References to module-bound functions and values. Instead.FSharp. x) : 'T * 'T @> In this case. the actual value of the type parameter is implicitly substituted through the type annotations and types in the generated expression tree. Quotations may not define expression-bound functions that are themselves inferred to be generic. In particular.1 Strongly Typed Quoted Expressions A strongly typed quoted expression has the form <@ expr @>.Expr. 6.  A function.2 Weakly Typed Quoted Expressions A weakly typed quoted expression <@@ expr @@> is similar to a normal quoted expression but drops the type annotation.Value. such as the following: let f (x : int) = <@ x + 1 @> In this case the value appears in the expression tree as a node of kind Microsoft.0.FSharp. For example: <@@ 1 + 1 @@> <@@ (fun x -> x + 1) @@> 81 .Quotations. such as the following: let f (x:'T) = <@ (x. The expression expr is checked with initial type ty.

If the overall splice expression is checked with initial type ty.8. given open Microsoft. A strongly typed expression splice may only occur in a quotation.Quotations let f1 (v:Expr<int>) = <@ %v + 1 @> let tree = f1 <@ 3 @> the identifier tree evaluates to the same expression tree as <@ 3 + 1 @>. Uses of this operator must be applied to an argument and may only occur in quoted expressions. 6.8. an expression of the following form is a weakly typed expression splice: %%expr For example. 82 .FSharp. Uses of this operator must be applied to an argument and may only occur in quoted expressions. then the expression expr is checked with initial type Microsoft. 6.Quotations.(%%).Core.1 %expr Strongly Typed Expression Splices Under default definitions.FSharp.Quotations.Expr. No additional constraint is placed on ty. Note: Additional type annotations will often be required for successful use of this operator. given open Microsoft.(%) defined in the F# core library.3.6.Quotations let f1 (v:Expr) = <@ %%v + 1 @> let tree = f1 <@@ 3 @@> the identifier tree evaluates to the same expression tree as <@ 3 + 1 @>. which is defined in the F# core library.ExtraTopLevelOperators.3. The expression tree replaces the splice in the corresponding expression tree node.8. 6.9 Evaluation of Elaborated Forms At runtime.FSharp. A weakly typed expression splice may only occur in a quotation.Core. an expression of the following form is a strongly typed expression splice: For example. These are respectively strongly typed and weakly typed splicing operators.Expr<ty>.FSharp.ExtraTopLevelOperators.FSharp. The rules in this section apply to any use of the prefix operator Microsoft. execution evaluates expressions to values.3 Expression Splices Both strongly typed and weakly typed quotations may contain expression splices %expr and %%expr. The evaluation semantics of each expression form are specified in the subsections that follow. Note: The rules in this section apply to any use of the prefix operator Microsoft.FSharp. The expression tree replaces the splice in the corresponding expression tree node.2 Weakly Typed Expression Splices Under default definitions. then the expression expr is checked with initial type Microsoft. If the overall splice expression is checked with initial type ty.

6.9.1 Values and Execution Context
The execution of elaborated F# expressions results in values. Values include:      Primitive constant values References to object values The special value null Values for value types, containing a value for each field in the value type Pointers to mutable locations (including static mutable locations, mutable fields and array elements)

Evaluation assumes:  A global pool (heap) of object values. Each object value contains: o o o o A runtime type Fields A possible union case label A closure that assigns values to all variables that are referenced in the method bodies that are associated with the object  A global table that maps runtime-type/name pairs to values, where the name is that of a static field in a type definition or a value in a module.

6.9.1.1

Parallel Execution

Evaluation in a concurrent environment may involve both multiple active computations (multiple concurrent and parallel threads of execution) and multiple pending computations (pending callbacks, such as those activated in response to an I/O event).

6.9.1.2

Memory Model

If multiple active computations concurrently access mutable locations, then the atomicity, read, and write guarantees of the underlying CLI implementation apply. These guarantees are related to the logical sizes and characteristics of values, which depend on their type:  F# reference types are guaranteed to map to CLI reference types. In the CLI memory model, reference types have atomic reads and writes. F# value types map to a corresponding CLI value type that has corresponding fields. Reads and writes of sizes less than or equal to one machine word are atomic.

Pattern matching preserves memory model characteristics by first ensuring that the expression being matched is read and assigned into an immutable location. The VolatileField attribute marks a mutable location as volatile in the compiled form of the code. The semantics of adding this attribute are documented in the ECMA CLI specification. Ordering of reads and writes from mutable locations may be adjusted according to the limitations specified by the CLI memory model. The following example shows scenarios where these issues can occur, with annotations concerning the order of reads: type ClassContainingMutableData() = let value = (1, 2) let mutable mutableValue = (1, 2) [<VolatileField>] let mutable volatileMutableValue = (1, 2)

83

member x.ReadValues() = // Two reads on –an immutable value; no memory model issues arise. let (a1, b1) = value // One read on mutableValue, which may be duplicated according to CLI ECMA spec. let (a2, b2) = mutableValue // One read on volatileMutableValue, which may not be duplicated. let (a3, b3) = volatileMutableValue a1, b1, a2, b2, a3, b3 member x.WriteValues() = // One read on mutableValue, which may be duplicated according to CLI ECMA spec. let (a2, b2) = mutableValue // One write on mutableValue. mutableValue <- (a2 + 1, b2 + 1) // One read on volatileMutableValue, which may not be duplicated. let (a3, b3) = volatileMutableValue // One write on volatileMutableValue. volatileMutableValue <- (a3 + 1, b3 + 1) let obj = ClassContainingMutableData() Async.Parallel [ async { return obj.WriteValues() }; async { return obj.WriteValues() }; async { return obj.ReadValues() }; async { return obj.ReadValues() } ]

6.9.2 Zero Values
All ground types have a zero value. This is the ―default‖ value for the type in the CLI execution apparatus:   For reference types: the null value For value types: the value with all fields set to the zero value for the type of the field. The zero value is also computed by the F# library function Unchecked.defaultof<ty>.

6.9.3 Taking the Address of an Elaborated Expression
The process of computing the elaborated forms of certain expressions must compute a ―reference‖ to an elaborated expression expr, written AddressOf(expr, mutation). The AddressOf operation is used internally within this specification to indicate the elaborated forms of address-of expressions, assignment expressions, and method and property calls on objects of variable and value type. The AddressOf operation is computed as follows:  If expr has form path where path is a reference to a value with type byref<ty> then the elaborated form is &path.  If expr has form expra.field where field is a mutable, non-readonly CLI field then the elaborated form is &(AddressOf(expra).field)  If expr has form expra.[exprb] where the operation is an array lookup then the elaborated form is &(AddressOf(expra).[exprb])  Otherwise, the elaborated form is &v where v is a fresh mutable local value that is initialized using let v = expr as the first binding in the overall elaborated form for the entire assignment expression. This is 84

known as a defensive copy of an immutable value. If expr is a struct, then expr will be copied each time the AddressOf operation is applied, resulting in a different address each time. To keep the struct in place, the field that contains it should be marked as mutable. The AddressOf operation is computed with respect to mutation, which indicates whether the relevant elaborated form mutates memory using the resulting pointer. This assumption changes the errors and warnings reported.  If mutation is DefinitelyMutates, then an error is given if a defensive copy arises. An explicit defensive copy can be used if the operation is intended.  If mutation is PossiblyMutates, then a warning is given if a defensive copy arises.

An F# compiler can optionally upgrade PossiblyMutates to DefinitelyMutates for calls to property setters and methods named MoveNext and GetNextArg, which are the most common cases of struct-mutators in CLI library design. This is done by the F# 2.0 compiler. Note:In F# 2.0, the warning “copy due to possible mutation of value type” is a level 4 warning and is not reported when using the default settings of the F# compiler. This is because the majority of value types in CLI libraries are immutable. This is warning number 52 in the F# 2.0 implementation. CLI libraries do not include metadata to indicate whether a particular value type is immutable. Unless a value is held in arrays or locations marked mutable, or a value type is known to be immutable to the F# compiler, F# inserts copies to ensure that inadvertent mutation does not occur.

6.9.4 Evaluating Value References
For elaborated value references v, the value corresponding to v in the environment is returned.

6.9.5 Evaluating Function Applications
For elaborated applications of functions, evaluation is defined with respect to sequences of applications of the form f e1 ... eN. The constituent expressions are evaluated and the body of the function value resulting from the f is executed. The first formal parameter is assigned the value of the first actual argument and ; additional arguments are applied iteratively to further resulting function values. All arguments e1 ... en are first evaluated, and then applied.

6.9.6 Evaluating Method Applications
For elaborated applications of methods, the elaborated form of the expression will be either expr.M(args) or M(args).  The (optional) expr and args are evaluated in left-to-right order and the body of the member is evaluated in an environment with formal parameters that are mapped to corresponding argument values.   If expr evaluates to null then NullReferenceException is raised. If the method is a virtual dispatch slot (that is, a method that is declared abstract) then the body of the member is chosen according to the dispatch maps of the value of expr.

6.9.7 Evaluating Union Cases
For elaborated uses of a union case Case(args) for a type ty, the arguments are evaluated in left-to-right order and an object value is returned that is compatible with the case Case. The CLI runtime type of the object is either ty or some type compatible with ty. If the type ty uses null as a representation (§5.4.8) and Case is the single, nullary union case, then the generated value is null. 85

6.9.8 Evaluating Field Lookups
For elaborated lookups of CLI and F# fields, the resolved form of the expression will be either expr.F for an instance field or F for a static field. The (optional) expr is evaluated and the field is read. If expr evaluates to null, then NullReferenceException is raised.

6.9.9 Evaluating Active Pattern Results
For active pattern result references (see §10.2.4) for result i in an active pattern with N possible results of types types, the elaborated expression form is an object construction of an object of type Microsoft.FSharp.Core.Choice<types> that uses a union case ChoiceNOfi.

6.9.10 Evaluating Array Expressions
When executed, an elaborated array expression is evaluated by first evaluating each expression in turn in left-toright order, and returns a new array containing the given values.

6.9.11 Evaluating Record Expressions
When evaluated, a primitive record construction is evaluated by first evaluating each constituent expression in left-to-right order and then building an object of type R<ty1,...,tyN>.

6.9.12 Evaluating Function Expressions
Function expressions (fun v1 … vn -> expr) are a primitive elaborated form. If only one variable is present, then whenever the function value is invoked later, the variable v1 will be bound to the input argument, the expression expr will be evaluated, and its value will be the result of the corresponding function invocation. If multiple patterns are present, then the function expression evaluates to a curried function value. Applying the curried function value to one argument results in a residual function value that accepts n-1 arguments. Whenever at total of n arguments has been received, the arguments are matched against the input patterns, any results from the match are bound, and the expression expr is evaluated and returned as the result of the application. The result of calling the obj.GetType() method on the resulting object is under-specified (see §6.9.24).

6.9.13 Evaluating Object Expressions
When executed, object expressions { new ty(args) with bindings interface-impls } are evaluated by creating an object whose runtime type is compatible with all of the tyi and whose dispatch map maps dispatch slots to their implementing members as listed in the object expression, or as inherited from the dispatch slots of the type ty. The base construction expression ty(args)is executed as the first step in the construction of the object. The result of calling the obj.GetType() method on the resulting object is under-specified (see §6.9.24).

6.9.14 Evaluating Binding Expressions
For each binding pat = rhs-expr, the right-hand side expression is evaluated and then matched against the given patterns to produce a collection of bindings that establish values for the identifiers bound by the pattern.

6.9.15 Evaluating For Loops
For-loops for var = expr1 to expr2 do expr3 done over ranges specified by variables are a primitive elaborated form.

86

Expressions expr1 and expr2 are evaluated once, then expression expr3 is evaluated repeatedly with the variable var bound to successive values in the range of expr1 up to expr2. If expr1 is greater than expr2, then expr3 is never evaluated.

6.9.16 Evaluating While Loops
While-loops while expr1 do expr2 done are a primitive elaborated form. Expression expr1 is evaluated. If its value is true expression expr2 is evaluated, and the expression while expr1 do expr2 done is evaluated again. If expression expr1 evaluates to false, the loop terminates.

6.9.17 Evaluating Static Coercion Expressions
At runtime, a boxing coercion is inserted if tye is a value type and ty is a reference type.

6.9.18 Evaluating Dynamic Type-Test Expressions
Elaborated expressions of the form expr :? ty evaluate as follows:   expr is evaluated to a value v. If v is null, then o o  If tye uses null as a representation (§5.4.8), the result is true. Otherwise the expression evaluates to false.

If v is not null and has dynamic type vty, and vty dynamically converts to ty (§5.4.10) then the expression evaluates to true. o o An exception is made if ty is an enumeration type, in which case ty must be precisely vty. Otherwise the expression evaluates to false.

6.9.19 Evaluating Dynamic Coercion Expressions
Elaborated expressions of the form expr :?> ty evaluate as follows:   expr is evaluated to a value v. If v is null o o  If tye uses null as a representation (§5.4.8) then the result is the null value. Otherwise a NullReferenceException is raised.

If v is not null o If v has dynamic type vty, and vty dynamically converts to ty (§5.4.10) then the expression evaluates to the dynamic conversion of v to ty. This means an unboxing coercion is inserted if tye is a reference type and ty is a value type. o Otherwise an InvalidCastException is raised.

Note that expressions of the form expr :?> ty evaluate in the same way as uses of the F# library function unbox<ty>(expr).

87

The result of the overall expression is v. If no rule matches. 88 . reraise() continues the exception processing mechanism with the original exception information. then the exception is reraised.20 Evaluating Sequential Execution Expressions Sequential expressions e1.9. The expression evaluates to the address of the referenced local mutable value.[exprb]) &v where v is a mutable local.23 Evaluating AddressOf Expressions An elaborated address-of expression is of one of the following forms:     &path where path is a static field. For example.. most notably the option<_> type. or mutable static field.9. then expression e2 is evaluated to a value v. The result of the overall expression is v.Note: Some F# types use null as a representation for efficiency reasons (§5. For these types. System. mutable field. val it : int option = None 6.InvalidCastException… > (box(None:string option) :?> int option). The expression expr is evaluated and if an exception occurs then the pattern rules are executed against the resulting exception value.22 Evaluating Try-finally Expressions Expressions of the form try e1 finally e2 are a primitive elaborated form. boxing and unboxing can lose type distinctions.field) &(expra. 6.4. its result discarded.. The expression e1 is evaluated. &(expr.9. The special expression reraise() may be used in the right-hand sides of rules.9. though it may not be used inside any inner closure. contrast: > (box([]:string list) :?> int list). reraise() When executed. e1 is evaluated to a value v and e2 is then executed regardless of whether an exception was raised by evaluation of e1.21 Evaluating Try-with Expressions Try-with expressions try expr with rules are a primitive elaborated form. 6. try failwith "fail" with e -> printfn "Failing".8). 6. e2 are a primitive elaborated form.

Runtime. F(&bb.Object. as evidenced by the fact that the type string[] dynamically converts to obj[] (§5. and the AddHandler and RemoveHandler operations to register and unregister event handlers are based on the object identity of delegate values. Similarly.GetHashCode are underspecified.ArrayTypeMismatchException exception.zeroCreate<obj> 10 let b = Array. its existence means that array assignments and taking the address of array elements may fail at runtime with a System. System. the following code will fail at runtime: let F(x: byref<obj>) = () let a = Array. The results of these operations are underspecified when used with values of the following F# types:      Function types Tuple types Immutable record types Union types Boxed immutable value types For two values of these types.Runtime.CompilerServices. System. obj2) returns true if the two object references refer to the same object.RuntimeHelpers.zeroCreate<string> 10 F(&a.[1]) 6.GetHashCode() returns a hash code that is partly based on physical object identity. for union types the results of the following operations are underspecified in the same way:  Object. for function values and objects that are returned by object expressions.10). although the operations terminate and do not raise exceptions.GetHashCode() Object.ReferenceEquals and System. Likewise.ReferenceEquals(obj1.The underlying CIL execution machinery used by F# supports covariant arrays.24 Values with Underspecified Object Identity and Type Identity The CLI and F# support operations that detect object identity—that is. the results of System.4. An implementation of F# does not have to define the results of these operations for values of these types.[0]) let bb = ((b :> obj) :?> obj[]) // The next line raises a System.ArrayTypeMismatchException if the runtime type of the target array does not match the runtime type of the element being assigned.CompilerServices.RuntimeHelpers. whether two object references refer to the same ―physical‖ object.GetType() Likewise. For example. Although this feature is rarely used in F#.Object. the results of the following operations are underspecified in the same way:   Object.GetType() 89 . For example.9.

. . . . long-ident. fun and let expression and declaration constructs. try. function. pat-param ] | ( pat-param. null....pattern. (pat).7 Patterns Patterns are used to perform simultaneous case analysis and decomposition on values in conjunction with the match.. _ field-pat := long-ident = pat pat-param := | const | long-ident | [ pat-param ... . Rules are attempted in order from top-to-bottom and left-to-right. . record-pat. pat ] array-pat := [| |] [| pat ..... .. field-pat } atomic-pat := pat -... . '|' rule -.. . array-pat.with.. pat-param ) | long-ident pat-param | pat-param : type | <@ expr @> | <@@ expr @@> | null pats := pat .. . . The syntactic forms of patterns are shown in the subsequent table. pat |] record-pat := { field-pat .pat (pat) list-pat array-pat record-pat :? atomic-type :? atomic-type as ident null attributes pat list-pat := [ ] [ pat . rule := pat pattern-guardopt -> expr pattern-guard := when expr pat := const long-ident pat-paramopt patopt _ pat as ident pat '|' pat pat '&' pat pat :: pat pat : type pat. ..restricted to const. field-pat rules := '|'opt rule '|' .. optional guard and action ------------------ constant pattern named pattern wildcard pattern "as" pattern disjunctive pattern conjunctive pattern "cons" pattern pattern with type constraint tuple pattern parenthesized pattern list pattern array pattern record pattern dynamic type test pattern dynamic type test pattern null-test pattern pattern with attributes 90 . ..... :? atomic-type.. list-pat. pat field-pats := field-pat .

N. 7. I. During checking. The match succeeds if this call returns true.1 may be used as a constant pattern with the exception of integer literals that have the suffixes Q.3. This reduces pattern matching to decision trees.FSharp. 91 .Core. the variable is assigned the same value and type as the value being matched. Note: The use of Microsoft.1. and CLI ordinal string equality is used for matching strings. 7. G.(=) taking the relevant match input and constant as arguments.FSharp.(=) means that CLI floating-point equality is used for matching floating-point values.Operators. otherwise. For example: let rotate3 x = match x with | 0 -> 2 | 1 -> 0 | 2 -> 1 | _ -> failwith "rotate3" Any constant listed in §6. the match fails. which contain such constructs as the following:       Conditionals on integers and other constants Switches on union cases Conditionals on runtime types Null tests Binding expressions An array of right-hand-targets referred to by index Attributes and accessibility annotations on patterns are not permitted except on patterns that are in argument position for a ―let‖ binding in a module or a member-binding in a type.1 Pattern Forms 7.Operators.1 Simple Constant Patterns The pattern const is a constant pattern which matches values equal to the given constant. Simple constant patterns have the corresponding simple type and elaborate to a call to the F# generic equality function Microsoft. R.2 Named Patterns Patterns in the following forms are named patterns: Long-ident Long-ident pat Long-ident pat-params pat If long-ident is a single identifier that does not begin with an uppercase character then it is always interpreted as a variable-binding pattern and represents a variable that is bound by the pattern. Z.1.Patterns are elaborated to expressions through a process called pattern match compilation.Core.

2 resolves to a literal value. 7. For example: type Data = | Kind1 of int * int | Kind2 of string * string let data = Kind1(3. then the pattern is a union case pattern. This produces one of:     A union case An exception label An active pattern case name A literal value If no resolution is available.5).2 resolves to a union case.1.1. On a successful match the data values carried by the union are matched against the given argument pattern.1.Length + s2. then the pattern is a literal pattern. then long-ident and long-ident pat are patterns that recognize values compatible with Case. b) -> a + b | Kind2(s1. 2) match data with | Kind1(a.3 Union Case Patterns If long-ident from §7. and it is recommended that this always be done if the length of the identifier is greater than two.IsUpperInvariant is true and System.4 Literal Patterns If long-ident from §7. For example: [<Literal>] let Case1 = 100 [<Literal>] let Case2 = 100 match 1 with | Case1 -> "Case1" | Case2 -> "Case1" | _ -> "Some other case" 92 . s2) -> s1. An F# implementation may optionally give a warning if the identifier is uppercase. then it resolves using Name Resolution in Patterns (§14. 7.If long-ident has length greater than one or begins with an uppercase identifier (that is. and the second form is used if it takes arguments.Char.Char. then long-ident must be a single identifier ident and the pattern is a variablebinding pattern.IsLowerInvariant is false on the first character). The subsequent resolution of the named patterns is described in the following sections. The first form is used if the corresponding case takes no arguments.1.Length Assuming long-ident resolves to a union case Case.1. System.

 (|CaseName|_|) inp — Partial.  (|CaseName|_|) arg1 . In F# 2. The function accepts n+1 arguments (the last being the value matched). The function accepts one argument (the value being matched). The function accepts one argument (the value being matched).0.. and can return any type.. and can return any type. The function accepts one argument (the value being matched). The following illustrates the definition and use of a partial active pattern function: let (|Positive|_|) inp = if inp > 0 then Some(inp) else None let (|Negative|_|) inp = if inp < 0 then Some(-inp) else None match 3 with | Positive n -> printfn "positive. |CaseNamen|_|) are not permitted.7.5 Active Patterns If long-ident from §7._> based on the number of case names..1... The rules of name resolution in patterns (§14.5) ensure that CaseNamei is associated with an active pattern function f in one of the following forms:  (|CaseName|) inp — Single case.1. and must return a value of type option<_>.. multi-case. argn inp — Single case with parameters. In particular. The function accepts n+1 arguments (the last being the value matched). Other active pattern functions are not permitted.|CaseNamen|) inp — Multi-case. and must return a value of type Choice<_.. n = %d" n | Negative n -> printfn "negative. argn inp — Partial with parameters. the limitation n ≤ 7 applies.1. and must return a value of type option<_>  (|CaseName1| . n = %d" n | _ -> printfn "zero" The following illustrates the definition and use of a multi-case active pattern function: let (|A|B|C|) inp = if inp < 0 then A elif inp = 0 then B else C match 3 with | A -> "negative" | B -> "zero" | C -> "positive" The following illustrates the definition and use of a parameterized active pattern function: let (|MultipleOf|_|) n inp = if inp%n = 0 then Some (inp / n) else None match 16 with | MultipleOf 4 n -> printfn "x = 4*%d" n | _ -> printfn "not a multiple of 4" 93 ..  (|CaseName|) arg1 .... partial functions (|CaseName1| ..2 resolves to an active pattern case name CaseNamei for the syntactic pattern forms long-ident pat-paramsopt patopt then the pattern is an active pattern.

top-to-bottom reading of the entire pattern indicates that execution is required. syntactically the pat-params are patterns and are limited to those forms shown in the grammar. ChoicekOfN v.Core.. 94 ..|idN|) —or— (|id1|_|) where: id is idk for one of the identifiers in this list. Microsoft.Assuming that the active pattern case name is associated with a function value f. where tyin is the type of input being matched.FSharp. or Some v. f is a value of function type tyin -> tyout.. then the pattern applies f to the input being matched. If present. The patterns are then converted to the syntactically identical corresponding expression forms and passed as arguments to the active pattern function f. tyout must be:    ty1 when n = 1 and an underscore is not present.Core. When an active pattern function takes arguments. When executed. The precise number of times the active pattern function is executed is implementation-dependent. the pat-params are interpreted as expressions that are passed as arguments to the active pattern function. The name of f must be in one of the following forms: (|id1|. Microsoft.FSharp. along with any given parameters. the pattern matches if the active pattern function returns v..Option<ty1> when _ is present. the pattern argument pat is then matched against v.. respectively. consider the following active patterns: let (|A|_|) x = if x = 2 then failwith "x is two" elif x = 1 then Some() else None let (|B|_|) x = if x=3 then failwith "x is three" else None let (|C|) x = failwith "got to C" let f x = match x with | 0 -> 0 | A -> 1 | B -> 2 | C -> 3 | _ -> 4 These patterns evaluate as follows:: f f f f f 0 1 2 3 4 // // // // // 0 1 failwith "x is two" failwith "x is three" failwith "got to C" An active pattern function can be executed multiple times against the same input when resolving a single overall pattern match. An active pattern function is executed only if a left-to-right. For example.Choice<ty1. To avoid ambiguities..tyN> and _ is not present.

.1. pat] is syntactic sugar for a series of :: and empty list patterns. 31)) -> Some(year) | _ -> None 7.10 “Cons” and List Patterns The pattern pat :: pat is a union case pattern matching the ―cons‖ case of F# list values. [pat ._] -> 2 | _ :: t -> count t + 1 95 .. attempts to match the second pattern.1. Both patterns must bind the same set of variables with the same types. 1) | Date (year. For example: type Date = Date of int * int * int let isYearLimit date = match date with | (Date(year. 2) 7. For example: let t1 = (1.6 “As” Patterns The pattern pat as ident binds the given name to the input value and matches the value against the given pattern. 12. For example: let (|MultipleOf|_|) n inp = if inp%n = 0 then Some (inp / n) else None match 56 with | MultipleOf 4 m & MultipleOf 7 n -> printfn "x = 4*%d = 7*%d" m n | _ -> printfn "not a multiple of both 4 and 7" 7. Also. For example: let rec count x = match x with | [] -> 0 | [_] -> 1 | [_. binding any variables that appear in either. and if that fails.1.1. 1.9 Conjunctive Patterns The pattern pat & pat is a conjunctive pattern and matches the input against both patterns.1.8 Disjunctive Patterns The pattern pat | pat is a disjunctive pattern and attempts to match the input value against the first pattern.7 Wildcard Patterns The pattern _ is a wildcard pattern and matches any input. [] matches the empty list. Likewise. . . 2) let (x.7. For example: let categorize x = match x with | 1 -> 0 | 0 -> 1 | _ -> 0 7. y) as t2 = t1 printfn "%d-%d-%A" x y t2 // 1-2-(1.

IComparable -> 1 | :? string -> 1 // a warning is reported that this rule is "never matched" | _ -> 2 At runtime a dynamic type-test pattern succeeds if and only if the corresponding dynamic type-test expression e :? ty would have returned true. 7. For example: open System let message (x : Exception) = match x with | :? System.1. 7. For example: type Data = { Header:string.. Dynamic type-test patterns are checked for redundancy. long-identn = patn} is a record pattern. it is bound to the value that was coerced to the given type. For example: let rec sum xs = match xs with | [] -> 0 | (h : int) :: t -> h + sum t In this example. Size: int. this in turn implies that xs and t have static type int list. Through type inference.Length | _ -> 0 A warning occurs if the input type cannot be statically determined to be a subtype of type. Coercion is taken into account: match box "3" with | :? string -> 1 | :? string -> 1 // a warning is reported that this rule is "never matched" | _ -> 2 match box "3" with | :? System.13 Record Patterns The pattern { long-ident1 = pat1. Names: string list } 96 .1.1.12 Dynamic Type-Test Patterns The patterns :? type and :? type as ident are both dynamic type-test patterns.. The value of the pattern is bound to the results of a dynamic coercion expression e :?> ty. and sum has static type int list -> int. A dynamic type-test pattern matches any value whose runtime type is the given type or a subtype of the given type.11 Type Annotated Patterns The pattern pat : type is a type annotated pattern that specifies the type of the value that is matched to the pattern.OperationCanceledException -> "cancelled" | :? System.7. the pattern is checked using the same conditions as both a dynamic type-test expression e :? ty and a dynamic coercion expression e :?> ty. If the pattern input e has type tyin. .ArgumentException -> "invalid argument" | _ -> "unknown error" If an identifier follows as. . An error occurs if the type test will always succeed. the initial type of h is asserted to be equal to int before the pattern h is checked. For example: open System let findLength (x : obj) = match x with | :? string as s -> s.

8.1. x) when (printfn "not printed". data2 |] -> (data1. true) -> 0 | (_.1.GetEnvironmentVariable("PATH") with | null -> failwith "no path set!" | res -> res Most F# types do not use null as a representation and hence this value is generally used only for checking values coming from CLI method calls and properties.Length * 12 | { Header = "UDP". data2) | _ -> failwith "unknown packet" 7. match (1. data2. However. For example: let path = match System. 2) with | (3. For example: let categorize x = match x with | _ when x < 0 -> -1 | _ when x < 0 -> 1 | _ -> 0 The guards on rules are executed only after the match value has matched the pattern that is associated with a rule. For example.1. Names = names } -> size + names. . 7. For example: let checkPackets data = match data with | [| "HeaderA". .Environment. 7. y) -> y 97 . Not all record fields for the type need to be specified in the pattern.16 Guarded Pattern Rules Rules of the form pat when expr are guarded pattern rules.. some F# types do use null as a representation.14 Array Patterns The pattern [|pat . pat|] is an array pattern that matches arrays of the given length. data1 |] -> (data1. the following evaluates to 2 with no output. Size = size } -> size | _ -> failwith "unknown header" The long-identi are resolved in the same way as field labels for record expressions and must together identify a single.15 Null Patterns The pattern null is a null pattern that matches values represented by the CLI value null. data1. see §5..let totalSize data = match data with | { Header = "TCP". data2) | [| "HeaderB".4. Size = size. unique F# record type.

.binding attributesopt staticopt do expr -. .nullary union case -. '|' union-type-case union-type-case := attributesopt union-type-case-data union-type-case-data := ident ident of type * .n-ary union case record-type-defn := type-name = '{' record-fields '}' type-extension-elementsopt record-fields := record-field . * type ident : uncurried-sig -. . record-field ..8 Type Definitions Type definitions define new named types.side-effect binding 98 .opt record-field := attributesopt mutableopt accessopt ident : type anon-type-defn := type-name primary-constr-argsopt object-valopt '=' begin class-type-body end class-type-defn := type-name primary-constr-argsopt object-valopt '=' class class-type-body end as-binding := as ident class-type-body := class-inherits-declopt class-let-bindingsopt type-defn-elementsopt class-inherits-decl := inherit type expropt class-let-binding := attributesopt staticopt let recopt bindings –....n-ary union case -. type-defn := abbrev-type-defn record-type-defn union-type-defn anon-type-defn class-type-defn struct-type-defn interface-type-defn enum-type-defn delegate-type-defn type-extension type-name := attributesopt accessopt ident typar-defnsopt abbrev-type-defn := type-name = type union-type-defn := type-name '=' union-type-cases type-extension-elementsopt union-type-cases := '|'opt union-type-case '|' .. The grammar of type definitions is shown below.

enum constant definition -.delegated construction -.exception abbreviation delegate-type-defn := type-name '=' delegate-sig delegate-sig := delegate of uncurried-sig -.sequence construction (before) if expr then additional-constr-expr else additional-constr-expr let val-decls in additional-constr-expr -. type-defn-element primary-constr-args := attributesopt accessopt (pat.. '|' enum-type-case enum-type-case := ident '=' const -.. pat) additional-constr-defn := attributesopt accessopt new pat as-binding = additional-constr-expr additional-constr-expr := stmt '.struct-type-defn := type-name primary-constr-argsopt as-bindingopt '=' struct struct-type-body end struct-type-body := type-defn-elements interface-type-defn := type-name '=' interface interface-type-body end interface-type-body := type-defn-elements exception-defn := attributesopt exception union-type-case-data attributesopt exception ident = long-ident enum-type-defn := type-name '=' enum-type-cases enum-type-cases = '|'opt enum-type-case '|' .explicit construction member-defn := attributesopt staticopt member accessopt member-binding attributesopt abstract memberopt accessopt member-sig attributesopt override accessopt member-binding attributesopt default accessopt member-binding attributesopt staticopt val mutableopt accessopt ident : type additional-constr-defn -..additional constructor ------ concrete member abstract member override member override member value member 99 .' additional-constr-expr -.sequence construction (after) additional-constr-expr then expr -..binding construction additional-constr-init-expr additional-constr-init-expr := '{' class-inherits-decl field-binds '}' new type expr -..exception definition -.CLI delegate definition type-extension := type-name type-extension-elements type-extension-elements := with type-defn-elements end type-defn-element := member-defn interface-impl interface-spec type-defn-elements := type-defn-element . . ..

8) Enum type definitions (§8.get curried-sig := args-spec -> . 100 .5) Class type definitions (§8. -> args-spec -> type uncurried-sig := args-spec -> type args-spec := arg-spec * ..set set. type definitions define fresh.7) Struct type definitions (§8.10) Exception type definitions (§8.12) Measure type definitions (§9. * arg-spec arg-spec := attributesopt arg-name-specopt type arg-name-spec := ?opt ident : interface-spec := interface type For example: type int = System.opt ident with bindings -.method or property definition ident.4) Union type definitions (§8.4) With the exception of type abbreviations and type extension definitions. distinct from other types.9) Delegate type definitions (§8.. named types.member-binding := ident.property definition member-sig := ident typar-defnsopt ident typar-defnsopt ident typar-defnsopt ident typar-defnsopt ident typar-defnsopt : : : : : curried-sig curried-sig curried-sig curried-sig curried-sig -----member signature property signature property signature property signature property signature with with with with get set get.opt binding -.11) Type extension definitions (§8.3) Record type definitions (§8.6) Interface type definitions (§8.Int32 type Color = Red | Green | Blue type Map<'T> = { entries: 'T[] } Type definitions can be declared in:   Module definitions Namespace declaration groups F# supports the following kinds of type definitions:            Type abbreviations (§8...

Permute = RowVector(entries) Exception type definitions and module definitions cannot be part of a type definition group. and .Sum = this..Permute = ColumnVector(entries) and ColumnVector(entries: seq<int>) = let entries = Seq. y : int } with member this.Several type definitions or extensions can be introduced simultaneously using a type definition group: type ..Length = entries. 101 . the following shows how to use these tokens in record and union type definitions: type R1 = { x : int. For example: type RowVector(entries: seq<int>) = let entries = Seq.Length member x.x + this.Length member x.toArray entries member x.y end The with/end tokens can be omitted if the type-defn-elements vertically align with the { in the record-fields. Most forms of type definitions may contain members (§8. or immediately before the name of the type definition: [<Obsolete>] type X1() = class end type [<Obsolete>] X2() = class end and [<Obsolete>] Y2() = class end Note: Type extension elements can include with/end tokens. Static elements are accessed via the type definition. Custom attributes may be placed immediately before a type definition group.Length = entries. For example.) tokens can be omitted if the next record-field vertically aligns with the previous record-field. Within static bindings only the static elements are in scope. Most forms of type definitions may contain both static elements and instance elements. The semicolon (.toArray entries member x..13).. in which case they apply to the first type definition.

determine the accessibility of the type definition. The generic arguments are initially inference parameters. this may not be done if the | tokens align with the type token. type abbreviations are established. a type definition group is checked as follows:  For each type definition. allowing the inference of additional constraints on the parameters. given an initial environment env. In addition.nm) -> nm /// Note: this layout is not permitted type Message = | Result of string | Request of int * string member x. if a Measure attribute is present. It also enables recursive references to the accessible properties of an object that has the same type as the type definition or a related type.For union types. applying incremental generalization. cyclic abbreviations are detected.2). and sorts of generic arguments of the type definition.Name = match x with Result(nm) -> nm | Request(_. accessibility and kind of the type definition are determined. the explicit constraints for the generic parameters are elaborated.   Type definitions are checked in a context where the type definition itself is in scope. the generic arguments. The members and ―let‖ bindings are checked in order. and base types is checked. o For each generic argument. mark it as a measure type definition if a Measure attribute is present. using Type Kind Inference if necessary (§8. o For each type definition T.  For each member. determine and check the basic kind of the type definition. and abstract members (§8. However.  For each type definition.Name = match x with Result(nm) -> nm | Request(_. along with whether the type definition supports equality and/or comparison. the subsequent steps use an environment envT that is produced by adding both the type definitions themselves and the generic arguments for T to env. then the generic argument is marked as a measure parameter. and the consistency of types in fields.  102 .1 Type Definition Group Checking and Elaboration In overview. union cases. For each type definition. For each type definition.   For each type definition. items that represent the members are collectively added to the environment as a recursive group. the base types and implemented interfaces of each new type definition are determined. For example: /// Note: this layout is permitted type Message = | Result of string | Request of int * string member x. the with/end tokens can be omitted if the type-defn-elements vertically align with the first | in the union-type-cases. names. In more detail. as are all members and other accessible functionality of the type. This context enables recursive references to the accessible static content of a type. For each type definition.14) of each new type definition are determined. the union cases. determine the number. a type definition group is checked as follows:  For each type definition. and the additional checks specified in the corresponding sections of this chapter are made. fields.nm) -> nm 8.

class. For each type definition with a primary constructor. Here ―X storing Y‖ means that X is Y or is a struct type with an instance field that stores Y. base-type-definition) (T. fields. make additional checks as defined elsewhere in this chapter. and no inference of additional constraints is permitted. elaborate and add the explicit constraints for the generic parameters of the type definition. apply dispatch-slot inference. For each member: o If the member is in a generic type. recheck the following for constraint consistency: o o o The type being abbreviated. Collectively add the elaborated member items that represent the members for all new type definitions to the environment as a recursive group (§8. zero-argument constructor. if any. T2) where T1 is a struct and T2 is a type that would store a value of type T1 <…> for some instantiaion. The generic parameters are then generalized. For each type definition. The types and constraints occurring in the base types and implemented interfaces. For example.13). o If the member has explicit type parameters. or interface. and abstract members. checking and elaborating any base types and implemented interfaces. This check includes the following steps: o o Create a graph with one node for each type definition. excluding interface implementation members. Close the graph under edges. For each type definition. 103  o . create a member item to represent the primary constructor. elaborate these type parameters and any explicit constraints. For each type definition. For each type definition that is generic. For each type definition. including checking and elaborating the types included in these definitions.   For each type definition. check that the inheritance graph and the struct-inclusion graph are not cyclic. check that the AbstractClass attribute does not appear on a union type. if any. if any. The special case of a struct S<typars> storing a static field of type S<typars> is allowed.       For each type definition that is a type abbreviation. check whether the type definition has a single. if any. determine its union cases. The explicit constraints for any generic parameters. check that the type abbreviation is not cyclic. elaborate and establish the type being abbreviated. and hence forms a type that satisfies the default constructor constraint. For each type definition that is a struct. interface-type-definition) (T1. infer whether the type definition supports equality and/or comparison. For each type definition.  o o   Check for cycles. If the member is an override. For each type definition that is a type abbreviation. default or interface implementation member. create a copy of the type parameters for the generic type and add the copy to the environment for that member.    (T.

 Otherwise. For example: // This is implicitly an interface type IName = abstract Name : string // This is implicitly a class. union. use this attribute as the kind of the type. assign a type to the instance variable. assign an initial type to the elaborated member item based on the patterns that specify arguments for the members. F# infers the kind of an anonymous type by applying the following rules in order:  If the type has a Class attribute. record. with an implicit begin/end.Name = "<no-name>" If a type is not an anonymous type then any use of the Class attribute. Type abbreviations are expanded and erased during compilation and do not appear in the elaborated form of F# declarations. because it has a constructor type ConstantName(n:string) = member x. or Struct attribute.2 Type Kind Inference A type with an anonymous kind is a type that is specified in one of the following ways:   By using the begin/end on the right-hand side of the = token. interface/end. because it has a constructor type AbstractName(n:string) = abstract Name : string default x. and struct/end tokens. non-abstract members and any inherit declarations with arguments.3 Type Abbreviations Type abbreviations define new names for existing types. For example: type PairOfInt = int * int Type abbreviations are processed during checking as part of a set of type declarations.o If the member has syntactic parameters. If the member is an instance member. The process of repeatedly eliminating type abbreviations in favor of their equivalent types must not result in an infinite type derivation. 104 . Interface attribute. Interface attribute. o  Check the ―let‖ bindings and members of each new type definition in order as a recursive group. nor can they be referred to or accessed at runtime.  Otherwise the type is an interface type. 8. ―let‖ bindings.Name = n // This is implicitly a class. These attributes cannot be used with other kinds of type definitions such as type abbreviation. Concrete elements are primary constructors. if the type has any concrete elements then it is a class. or Struct attribute must match the class/end. additional object constructors. or enum types. if such tokens are present. In lightweight syntax. 8.

the order of type variables that are used on the right-hand side of a type definition is determined by a left-to-right walk of the type. Note: Inferred types of public entities may. the following is not a valid type abbreviation.x + this. For example. the following are not valid type definitions: type X = option<X> type Identity<'T> = 'T and Y = Identity<Y> Type abbreviations must have sufficient constraints to satisfy those constraints required by their right-hand side. in visual presentations of types.Sum = this. For this purpose. flexible type constraints may not be used on the right of a type abbreviation. For example.'U> = 'T * 'T // invalid: dropped type variableNote: This restriction simplifies the process of guaranteeing a stable and consistent compilation to generic CLI code. because they expand to a type variable that has not been named in the type arguments of the type abbreviation. Likewise. however these inferred types are considered equivalent to their expanded form. so the following is permitted: type F<'T when 'T :> IA and 'T :> IB> = C<'T> The right side of a type abbreviation must use all the declared type variables that appear on the left side. given the declarations: type IA = abstract AbstractMember : int -> int type IB = abstract AbstractMember : int -> int type C<'T when 'T :> IB>() = static member StaticMember(x : 'a) = x. For example. 8. y : int } member this. the following type is disallowed: type BadType = #Exception -> int // disallowed Type abbreviations may be declared internal or private.4 Record Type Definitions A record type definition introduces a type in which all the inputs that are used to construct a value are available as properties on values of the type.For example.AbstractMember(1) the following is permitted: type D<'T when 'T :> IB> = C<'T> whereas the following is not permitted: type E<'T> = C<'T> // invalid: missing constraint Type abbreviations can define additional constraints.y 105 . type Drop<'T. For example: type R1 = { x : int. Flexible type constraints may not be used in type definitions except in member signatures. appear to refer to private abbreviations.

1 Members in Record Types Record types may declare members (§8... For example: type R = { dx : int.13).IStructuralEquatable interface System. overrides and interface implementations.dy) = this.4.5 Union Type Definitions A union type definition is a type definition with one or more union cases. The union cases Case1 .dx // x is inferred to have type R 8.Collections. which is defined to mean any character where the CLI library function System.IComparable override GetHashCode : unit -> int override Equals : obj -> bool The implementations of the indicated interfaces and overrides are described later in this chapter.IStructuralComparable interface System. This means that they can be used to form both expressions and patterns using unqualified names. 8. and System. Equality. Like all types with overrides and interface implementations. dy: int } let f x = x. fieldN are added to the FieldLabels table of the current name resolution environment.Name = match x with Result(nm) -> nm | Request(_.this.y + dy Record types are implicitly sealed and may not be given the Sealed attribute. they are subject to Dispatch Slot Checking (§14.IsUpper returns true.IsLower returns false. This does not apply if the record type has the RequireQualifiedAccess attribute. Record types may not be given the AbstractClass attribute.x + dx this. interface System.8). Record field labels in the FieldLabels table play a special role in Name Resolution for Members (§14. 8.3 Structural Hashing. the following two definitions differ: 106 . 8.2 Name Resolution and Record Field Labels For a record type.. For example: type Message = | Result of string | Request of int * string member x.this. mutable y : int } member this. and Comparison for Record Types Record types automatically implement the following interfaces and dispatch slots if they are not implemented by the record type author.Char. the record field labels field1 .nm) -> nm Union case names must begin with an upper case letter. CaseN have module scope and are added to the ExprItems and PatItems tables in the name resolution environment.Move(dx.1): an expression‘s type may be inferred from a record label.Char. For example: type R2 = { mutable x : int.y <.. Parentheses are significant in union definitions.x <.Collections. Thus.Record fields may be marked mutable.4.4. This does not apply if the record type has the RequireQualifiedAccess attribute. Record types are implicitly marked serializable unless the AutoSerializable(false) attribute is used.

An exception is made for the F# list and option types. 107 .NewC for each non-nullary union case C.Some properties and/or methods. 8. for each field of the union case. overrides and interface implementations. as specified later in this section. and Option. type OneChoice = A To disambiguate this case and declare an explicit union type. This will get a singleton object representing that case. A compiled union type with only one case does not have a nested type. Option. This will construct an object for that case.Collections. and the values of these cases will be in increasing order from zero.1 Members in Union Types Union types may declare members (§8. the union type itself plays the role of the case type.. Like all types with overrides and interface implementations.Empty..C for each non-nullary union case C.Tags containing one integer literal for each case. Item2.IStructuralEquatable interface System.   One CLI instance property u.IComparable override GetHashCode : unit -> int override Equals : obj -> bool The implementations of the indicated interfaces and overrides are described later in this section.5. and Comparison for Union Types Union types automatically implement the following interfaces and dispatch slots if they are not implemented by the union type author. or a single instance property Item if there is only one field.2 Structural Hashing.  One CLI static method U.IsC for each case C that returns true or false for the case.C for each nullary union case C. List.Collections. which have existing user-facing List.type CType = C of int * int type CType = C of (int * int) The parentheses indicate that the union case takes one argument that is a first-class tuple value.13).. Otherwise it defines a union type. This type will have instance properties Item1.  One CLI nested type U. One CLI instance property u. The following declaration defines a type abbreviation if the named type A exists in the name resolution environment. Instead. 8.Cons. use the following: type OneChoice = | A Union types are implicitly marked serializable unless the AutoSerializable(false) attribute is used. 8.  If U has more than one case. Equality.IStructuralComparable interface System. then it will have one CLI nested type U.5.None. interface System.8).Tag for each case C that fetches or computes an integer tag corresponding to the case.5.3 Compiled Form of Union Types for Use from Other CLI Languages A compiled union type U will have:  One CLI static getter property U. they are subject to Dispatch Slot Checking (§14.

Length = sqrt((qx-px)*(qx-px) + (qy-py)*(qy-py)) Instead one or more ―let‖ bindings should normally be added: type TwoVectors(pv.A compiled union type may not be inherited from.1 Primary Constructors in Classes An object constructor represents a way of initializing an object. For example. . Object constructors can be used to create values of the type and to partially initialize an object from a subclass. the following is not permitted because the primary constructor arguments contain a nested tuple pattern: type TwoVectors((px.6 Class Type Definitions A class type definition is a type definition that encapsulates values that are constructed by using one or more object constructors. plus any userdefined properties or methods.DY = dy Class definitions with a primary constructor may contain ―let‖ bindings. qy) = qv member v.Length = length member v. nested patterns may not be used in the primary constructor arguments. including those that use let rec. then it has a primary constructor. In F#.Length = sqrt((qx-px)*(qx-px) + (qy-py)*(qy-py)) The ―let‖ bindings of a primary constructor are checked and generalized in order..2) is used to determine the kind of the type. Class types have the form: type type-name patopt as-bindingopt = class class-inherits-declopt class-let-bindingsopt type-defn-elements end The class/end tokens can be omitted.DX = dx member v. 8. (qx. 108 . because it has at least one assembly-private constructor and no public constructors. the following type has a primary constructor: type Vector2D(dx : float. in which case Type Kind Inference (§8. Classes have object constructors through an optional primary constructor and zero or more additional object constructors.. simple-pat) for zero or more simple-pat where each is of the form: simple-pat := | ident | simple-pat : type That is. dy : float) = let length = sqrt(dx*x + dy*dy) member v. A compiled union type will have the methods needed to implement its auto-generated interfaces. The pattern for a primary constructor must be of the form (simple-pat.6. For example. If a type definition has a pattern immediately after the type-name and any accessibility annotation. py). qv) = let (px. class types are implicitly marked serializable unless the AutoSerializable(false) attribute is used. qy)) = member v. 8. py) = pv let (qx..

the inheritance and ―let‖ bindings of the type are evaluated in order. The compiled representation used for values declared in ―let‖ bindings in classes is either: o A value that is local to the object constructor (if the value is not a syntactic function. function bindings are represented as instance members.2   Inheritance Declarations in Primary Constructors An inherit declaration specifies that a type extends the given type. the binding is called an instance ―let‖ or ―do‖ binding. An instance field in the corresponding CLI type (if the value is not a syntactic function.1).6. ―Let‖ bindings for non-syntactic-function values may be marked mutable. If no inherit declaration is given for a class then the default is System.A with get() = currentA and set v = currentA <.Object. 8. A member of the corresponding CLI type (if the value is a syntactic function). consider this type: 109 . For example.      Instance ―let‖ bindings are lexically scoped (and thus implicitly private) to the object being defined.F() = printfn "hi" let r = new C() // raises InvalidOperationException 8. If not marked static. Classes with primary constructors may include ―let‖ and ―do‖ bindings. For example. o o  Non-function let-bindings that are not used in either the members of a type or a function binding are optimized away and become values that are local to the resulting CLI constructor. The inherit declaration of a type must have arguments if and only if the type has a primary constructor. Likewise.1.6.When a primary constructor is evaluated.v member self. no member on the type may be called prior to the completion of the execution of the last ―let‖ binding in the type. and doing so results in an InvalidOperationException.6. is not mutable and is not used in any function or member). A group of ―let‖ bindings may be marked rec.F()) let y = f self do printfn "construct" member this. the name of the object parameter can be bound throughout the ―let‖ bindings and instance members of a type definition as follows: type X(a:int) as x = let mutable currentA = a let mutable currentB = 0 do x.1.GetResult()= currentA + currentB member self.A + 3 member self. ―Let‖ bindings are generalized.B <. 8.x.6.2  “let” and “do” Declarations in Primary Constructors Each ―let‖ or ―do‖ binding may be marked static (see §8.v During construction. the following code raises this exception: type C() as self = let f = (fun (x:C) -> x.B with get() = currentB and set v = currentB <.2.1 Object References in Primary Constructors For types with a primary constructor. but is used in some function or member).

Z = z member this. respectively: let f w = x + w let f = (fun w -> x + w) ―Let‖ bindings may have attributes as follows:    ―Let‖ bindings in classes that are represented as fields may have attributes that target fields.type C(x:int. For example: type C<'T>() = 110 . A static field in the corresponding CLI type (if the value is not a syntactic function but is used in some function or member). ―Let‖ bindings in classes that are represented as locals may have attributes that target fields. Static ―let‖ bindings are elaborated to a static initializer associated with each generic instantiation of the generated class. o o   Static ―let‖ bindings in classes that are represented as fields may have attributes that target fields. Likewise the function f is represented as a member rather than a field that is a function value. Static ―let‖ bindings in classes that are represented as methods may have attributes that target methods. and no field will be stored for it.1       Static “let” and “do” Declarations in Primary Constructors Static ―let‖ bindings are lexically scoped (and thus implicitly private) to the type being defined.P = 1 // No field generated. Static ―let‖ bindings are computed once per generic instantiation.y:int) = let z = x + y let f w = x + w member this.Obsolete>] let unused = x member __. A group of ―let‖ bindings may be marked rec. a binding is considered to define a syntactic function if it is either a function or its immediate right-hand-side is a anonymous function. no compiled CLI attribute is generated.5. For the purposes of the above. Classes with primary constructors may have ―let‖ and ―do‖ bindings marked as ―static‖:  The compiled representation used for values declared in static ―let‖ bindings in classes is either o A local to the class initializer (if the value is not a syntactic function and is not used in any function or member). Static initializers are executed on demand in the same way as static initializers for implementation files §12. Each let for non-syntactic-function values may be marked mutable.Add(w) = f w The input y is only used during construction. S static member of the corresponding CLI type (if the value is a syntactic function). Static ―let‖ bindings are generalized. 8.2. For example: type C(x:int) = [<System. but these attributes will not be attached to any construct in the resulting CLI assembly. as in the following two examples.6. ―Let‖ bindings in classes that are represented as methods may have attributes that target methods.

s2) = { inherit BaseClass(s1). No call to a base class constructor is required if the base class is System. s2 = s2 } If a primary constructor is present. then additional object constructors must call another object constructor in the same type.P2) (C<string>. s2 = s2 } 111 . These are needed in two situations:   To define classes with more than one constructor. s2 = s2 } new (s2) = { inherit BaseClass(). and specify a call to a base class constructor for any inherited class type. this statement adds a second constructor to a class with a primary constructor: type PairOfIntegers(x:int. Like all types with overrides and interface implementations.P2) 8.Object.13). 8.P = v static member P2 = v+v printfn printfn printfn printfn printfn "check: "check: "check: "check: "check: %d %d %d %d %d = = = = = 3" 3" 3" 6" 6" (new C<int>()). additional object constructors may also be specified.3 Members in Classes Class types may declare members (§8. overrides and interface implementations.x) The next example declares a class without a primary constructor: type PairOfStrings = val s1 : string val s2 : string new (s) = { s1 = s. s2 = s } new (s1. The use of additional object constructors and val fields is required when multiple object constructors exist that must each call different base class constructors.y:int) = new (x) = PairOfIntegers(x.6.P (new C<string>()). If no primary constructor is present. For example: type BaseClass = val s1 : string new (s) = { s1 = s } new () = { s = "default" } type SubClass = inherit BaseClass val s2 : string new (s1.8). they are subject to Dispatch Slot Checking (§14.4 Additional Object Constructors in Classes Although the use of primary object constructors is generally preferred.3 member x.s2) = { s1 = s1.P (new C<int>()).static let mutable v = 2 + 2 static do v <.6. If explicit val fields are specified without the DefaultValue attribute For example. which may be another additional constructor or the primary constructor.P (C<int>. then additional constructors must initialize those val fields of the object that do not have the DefaultValue attribute.

new(x) = PairOfIntegers(x. b = "b" } A warning is given if x occurs syntactically in or before the additional-constr-init-expr of the construction expression. This parameter has a default value of true. For example: type X = val a : (unit -> string) val mutable b : string new() as x = { a = (fun () -> x. the type of the field must admit default initialization (§5. 112 . For example: type PairOfIntegers = val x : int val y : int new(x. y = y} And a static field in an explicit class type: type TypeWithADefaultMutableBooleanField = [<DefaultValue>] static val mutable ready : bool A val specification in a type with a primary constructor must be marked mutable and have the DefaultValue attribute.b). They are generally used only for classes without a primary constructor. or for mutable fields with default initialization.8). If any member is called prior to the completion of execution of the additional-constr-init-expr within the additional-constr-expr throws a InvalidOperationException. For example: type PairOfIntegers(x:int. and often only occur in generated code. x) then printfn "Initialized with only one integer" The name of the object parameter can be bound within additional constructors. y) = {x = x.6. side effects can be performed after the initialization of the fields of the object by using the additional-constr-expr then stmt form. 8. for example: type X() = [<DefaultValue>] val mutable x : int This attribute takes a parameter check that indicates whether checking should be applied to ensure that unexpected null values are not created by this mechanism.Additional object constructors are implemented using a restricted subset of expressions that ensure that the code generated for the constructor is valid according to the rules of object construction for CLI objects. For classes without a primary constructor.4. Note that precisely one additional-constr-init-expr occurs for each branch of a construction expression.y:int) = // This additional constructor has a side effect after initialization.5 Additional Fields in Classes Additional field declarations indicate a value stored in an object. If this parameter is true.

Interface types may be arranged hierarchically by specifying inherit declarations. It is initially zero. The presence of any non-abstract members or constructors means a type is not an interface type.2) is used to determine the kind of the type. such a field is initially assigned the zero value for its type (§6. IEvent. [<DefaultValue>] static val mutable count : int // Increment the count each time an object is created do MyClass.9. For example: type IA = abstract One: int -> int type IB = abstract Two: int -> int type IC = inherit IA 113 .count + 1 static member NumCreatedObjects = MyClass. for example. in which case Type Kind Inference (§8.7 Interface Type Definitions An interface type definition is a type definition that represents a contract that may be implemented by an object. They are made up only of abstract members. type MyNullable<'T>() = [<DefaultValue>] static val mutable ready : bool [<DefaultValue(false)>] static val mutable uninitialized : 'T At runtime. the following type is rejected: type MyClass<'T>() = [<DefaultValue>] static val mutable uninitialized : 'T However.'U> = interface abstract First: 'T abstract Second: 'U end type IThinker<'Thought> = abstract Think: ('Thought -> unit) -> unit abstract StopThinking: (unit -> unit) The interface/end tokens can be omitted when lightweight syntax is used. For example. However this convention is not followed as strictly in F# as in other CLI languages.Name = name 8. By convention interface type names start with I. For example: type MyClass(name:string) = // Keep a global count.2).MyClass. For example: type IPair<'T.count member x.For example. in compiler-generated and hand-optimized code it is sometimes essential to be able to emit fields that are completely uninitialized.count <.

R = r member x. this is possible only for structs without a primary constructor. val imaginary: float member x. x.0) Structs fields may be mutable.I = x. Like all types with overrides and interface implementations.8 Struct Type Definitions A struct type definition is a type definition whose instances are stored inline inside the stack frame or object of which they are a part. For example: [<Struct>] type Complex(r : float. 0. imaginary = i } Struct types may declare members. However.inherit IB abstract Three: int -> int Each inherit declaration must itself be an interface type.2). The type is represented as a CLI struct type.r. 114 .2) is used to determine the kind of the type.R = r member x.imaginary member x.I = i new(r : float) = new Complex(r. Structs undergo type kind inference (§8.imaginary end The struct/end tokens can be omitted when lightweight syntax is used. val mutable imaginary : float member x.Change(r.I = i Structs may have primary constructors: [<Struct>] type Complex(r : float.real <.imaginary <.i new (r. I : float) = member x.R = x.R = x. Structs may not have inherit declarations. overrides and interface implementations.real member x. For example: type Complex = struct val real: float. so the following is valid: [<Struct>] type Complex(r:float. they are subject to Dispatch Slot Checking (§14. I : float) = member x. Structs may have additional constructors. For example: [<Struct>] type MutableComplex = val mutable real : float. also called a value type.I = x. i) = x. 8.real member x. i:float) = member x. i) = { real = r. in which case Type Kind Inference (§8. There may be no circular references between inherit declarations based on the named types of the inherited interface types.R = r member x.8).I = i Structs with primary constructors must accept at least one argument.

though F# does not permit their direct use for F# struct types unless all field types admit default initialization. rest) = { data = data. This applies to struct types whose fields all have types which admit default initialization. the Complex type defined above admits default initialization. because the size of BadStruct2 would be infinite: [<Struct>] type BadStruct2 = val data : float. rest = rest } Likewise. in particular.Rest = rest Some struct types have an implicit default constructor which initializes all fields to the default value.Data = data member s.Green. the implied size of the following struct would be infinite: [<Struct>] type BadStruct3 (data : float. 8. the following is valid: [<Struct>] type GoodStruct1 (def : int) = static do System. the following is not valid: [<Struct>] type BadStruct1 (def : int) = do System. the following type definition is not permitted. rest : BadStruct3) = member s. Public struct types for use from other CLI languages should be authored with the existence of the default zero-initializing constructor in mind. A CLI implementation admits default constructors for all struct types. For example. Color. Structs may have static ―let‖ or ―do‖ bindings.Console.9 Enum Type Definitions Occasionally the need arises to represent a type that compiles as a CLI enumeration type An enum type definition is a type definition whose values are represented by integer constants and whose compiled form is a CLI enumeration. For example: type | | | Color = Red = 0 Green = 1 Blue = 2 let rgb = (Color. val rest : BadStruct2 new (data.Console.Red. Color. Enum type definitions are declared by specifying integer constants in a type definition that otherwise has the syntactic form of a union type definition.Structs may not have ―let‖ or ―do‖ bindings. recursively constructed structs are not permitted unless reference-typed indirections are used . For example.WriteLine("Structs cannot use 'do'!") This is because the default constructor for structs would not execute these bindings. This is similar to the way that F# considers some types to have null as an abnormal value.Blue) let show(colorScheme) = 115 . For example. let zero = Complex() Note: The existence of the implicit default constructor for structs is not recorded in CLI metadata and is an artifact of the CLI specification and implementation itself. For example.WriteLine("Structs can use 'static do'") A struct type must be realizable according to the CLI rules for structs.

match colorScheme with | (Color.Red, Color.Green, Color.Blue) -> printfn "RGB in use" | _ -> printfn "Unknown color scheme in use" Each case must be given a constant value of the same type. The constant values dictate the underlying type of the enum, and must be one of the following types:  sbyte, int16, int32, int64, byte, uint16, uint32, uint64, char

The declaration of an enumeration type in an implementation file has the following effects on the typing environment:   Brings a named type into scope. Adds the named type to the inferred signature of the containing namespace or module.

Enum types coerce to System.Enum and satisfy the enum<underlying-type> constraint for their underlying type. The declaration is implicitly annotated with the RequiresQualifiedAccess attribute and does not add the tags of the enumeration to the name environment. type Color = | Red = 0 | Green = 1 | Blue = 2 let red = Red // not accepted, must use Color.Red Unlike unions, enumeration types are fundamentally ―incomplete,‖ because CLI enumerations can be converted to and from their underlying primitive type representation. For example, a Color value not in the above enumeration can be generated by using the enum function from the F# library: let unknownColor : Color = enum<Color>(7)

8.10 Delegate Type Definitions
Occasionally the need arises to represent a type that compiles as a CLI delegate type. A delegate type definition is a type definition whose values are functions represented as CLI delegate values. A delegate type definition is declared using the delegate keyword with a member signature. For example: type Handler<'T> = delegate of obj * 'T -> unit Delegates are often used when interfacing to CLI libraries via P/Invoke: type ControlEventHandler = delegate of int -> bool [<DllImport("kernel32.dll")>] extern void SetConsoleCtrlHandler(ControlEventHandler callback, bool add)

8.11 Exception Definitions
An exception definition defines a new way of constructing values of type exn (a type abbreviation for System.Exception). An exception definition exception ident of types has the following effect:  The identifier ident can be used to generate values of type exn. 116

 

The identifier ident can be used to pattern match on values of type exn. The definition generates a type with name ident that derives from exn.

For example: exception Error of int * string raise (Error (3, "well that didn't work did it")) try raise (Error (3, "well that didn't work did it")) with | Error(sev, msg) -> printfn "severity = %d, message = %s" sev msg The type that corresponds to the exception definition can be used as a type in F# code. For example: let exn = Error (3, "well that didn't work did it") let checkException() = if (exn :? Error) then printfn "It is of type Error" if (exn.GetType() = typeof<Error>) then printfn "Yes, it really is of type Error" Exception abbreviations may abbreviate existing exception constructors. For example: exception ThatWentBadlyWrong of string * int exception ThatWentWrongBadly = ThatWentBadlyWrong let checkForBadDay() = if System.DateTime.Today.DayOfWeek = System.DayOfWeek.Monday then raise (ThatWentWrongBadly("yes indeed",123)) Note: Exception values may also be generated by defining and using classes that extend System.Exception.

8.12 Type Extensions
A type extension associates additional members with an existing type. For example: type System.String with member x.IsLong = (x.Length > 1000) Type extensions may be given for any accessible type definition except those defined by type abbreviations. If the type being extended is in the same module or namespace declaration group as the type definition for the type then it is called an intrinsic extension. Members defined in intrinsic extensions follow the same name resolution and other language rules as members defined as part of the original definition of the type. Otherwise the type extension must be in a module, and it is called an extension member. Opening a module that contains an extension member extends the name resolution of the dot syntax for the type that is extended. That is, extension members are accessible only if the module that contains the extension is open. Name resolution for membersthat are defined in type extensions behaves as follows:   In overload resolution, regular members (that is, members that are part of the original definition of a type, plus intrinsic extensions) are preferred to extension members. Any extension members in scope with the correct name are included in the group of members considered for overload resolution. An intrinsic member is always preferred to an extension member. If an extension member has the same name and type signature as a member in the original type definition, including inherited members, then it will be inaccessible.

117

For example, the following illustrates the definition of one intrinsic and one extension member for the same type: namespace Numbers type Complex(r : float, i : float) = member x.R = r member x.I = i // intrinsic extension type Complex with static member Create(a, b) = new Complex (a, b) member x.RealPart = x.R member x.ImaginaryPart = x.I namespace Numbers module ComplexExtensions = // extension member type Numbers.Complex with member x.Magnitude = ... member x.Phase = ... Extensions may define both instance members and static members. Extensions are checked as follows:   The bindings in an extension are checked along with the members and other bindings in the group of type definitions of which the extension is a part. No two intrinsic extensions may contain conflicting members. This is implicit in the fact that intrinsic extensions are considered part of the definition of the type.    Extensions may not define fields, interfaces, abstract slots, inherit declarations, or dispatch slot (interface and override) implementations. Extension members must be in modules. Extension members are syntactic sugar for static members. Uses of extension members elaborate to calls to static members with encoded names where the object is passed as the first argument.

8.12.1 Imported C# Extensions Members
The CLI language C# defines a notion of an ―extension member‖ which commonly occurs in CLI libraries, along with some other CLI languages. C#-defined extension members are made available to F# code in environments where the C#-authored assembly is referenced and an open declaration of the corresponding namespace is in effect. However, some notable limitations apply:   C# extension members whose ―this‖ parameter is a variable type are not available to F# code in F# 2.0. C# extension members whose ―this‖ parameter is an array type are not available to F# code in this version of F# 2.0.

118

The encoding of compiled names for F# extension members is not necessarily compatible with C# encodings of C# extension members. However, for instance extension methods, the naming can be made compatible. For example: [<System.Runtime.CompilerServices.Extension>] module EnumerableExtensions = [<CompiledName("OutputAll")>] [<System.Runtime.CompilerServices.Extension>] type System.Collections.Generic.IEnumerable<'T> with member x.OutputAll (this:seq<'T>) = for x in _this do System.Console.WriteLine (box x)

8.13 Members
Member definitions describe functions associated with type definitions and/or values of particular types. Member definitions can be used in type definitions. Members can be classified as follows:   Property members Method members

A static member is prefixed by static and is associated with the type, rather than any particular object. An instance member is a member without static. Here are some examples of instance members: type MyClass() = let mutable adjustableInstanceValue = "3" let instanceArray = [| "A"; "B" |] let instanceArray2 = [| [| "A"; "B" |]; [| "A"; "B" |] |] member x.InstanceMethod(y:int) = 3 + y + instanceArray.Length member x.InstanceProperty = 3 + instanceArray.Length member x.InstanceProperty2 with get () = 3 + instanceArray.Length member x.InstanceIndexer with get (idx) = instanceArray.[idx] member x.InstanceIndexer2 with get (idx1,idx2) = instanceArray2.[idx1].[idx2] member x.MutableInstanceProperty with get () = adjustableInstanceValue and set (v:string) = adjustableInstanceValue <- v member x.MutableInstanceIndexer with get (idx1) = instanceArray.[idx1] and set (idx1) (v:string) = instanceArray.[idx1] <- v Here are some examples of static members: type MyClass() static let static let static let = mutable adjustableStaticValue = "3" staticArray = [| "A"; "B" |] staticArray2 = [|[| "A"; "B" |]; [| "A"; "B" |] |]

static member StaticMethod(y:int) = 3 + 4 + y

119

static member StaticProperty = 3 + staticArray.Length static member StaticProperty2 with get() = 3 + staticArray.Length static member MutableStaticProperty with get() = adjustableStaticValue and set(v:string) = adjustableStaticValue <- v static member StaticIndexer with get(idx) = staticArray.[idx] static member StaticIndexer2 with get(idx1,idx2) = staticArray2.[idx1].[idx2] static member MutableStaticIndexer with get (idx1) = staticArray.[idx1] and set (idx1) (v:string) = staticArray.[idx1] <- v Members across a set of mutually recursive type definitions are checked as a mutually recursive group. As with collections of recursive functions, inconsistent type constraints may arise from recursive calls to potentiallygeneric methods: type Test() = static member Id x = x member t.M1 (x: int) = Test.Id(x) member t.M2 (x: string) = Test.Id(x) // error, x has type 'string' not 'int' A full type annotation on a target method makes it eligible for early generalization (§14.6.8). type Test() = static member Id<'T> (x:'T) : 'T = x member t.M1 (x: int) = Test.Id(x) member t.M2 (x: string) = Test.Id(x)

8.13.1 Property Members
A property member is a member-binding in one of the following forms: staticopt staticopt staticopt staticopt staticopt member member member member member ident.opt ident.opt ident.opt ident.opt ident.opt ident ident ident ident ident = expr with get with set with get with set pat = patopt pat = patopt expr pat= expr expr and set patopt pat = expr pat = expr and get pat = expr

A property member in the form staticopt member ident.opt ident with get pat1 = expr1 and set pat2a pat2b is equivalent to two property members of the form: staticopt member ident.opt ident with get pat1 = expr1 staticopt member ident.opt ident with set pat2a pat2b opt = expr2 Furthermore, the following two members are equivalent: staticopt member ident.opt ident = expr staticopt member ident.opt ident with get () = expr And these two are also equivalent: staticopt member ident.opt ident with set pat = expr2
opt

= expr2

120

Setter properties must return type unit.10) applies to method members.opt ident with set () pat = expr Thus.opt must be present if and only if the property member is an instance member.10) determine the compiled form of these members. the identifier ident is bound to the ―this‖ or ―self‖ object parameter associated with the object within the expression expr. which is the type of the value that its getter property returns or its setter property accepts. A property member is an indexer property if patidx is not the unit pattern ().3 Curried Method Members Methods may be written taking multiple arguments in iterated (―curried‖) form. additional argument groups may not use named arguments(§8... If a property member has both a getter and a setter. and neither is an indexer. and so on.Now the body of the member is evaluated each time C.DateTime. When the member is called.GetEnvironmentVariable("COMPUTERNAME") 8.[] notation.opt must be present if and only if the property member is an instance member. The identifier ident is bound to the ―this‖ (or ―self‖) variable associated with the object within the expression expr.opt ident pat1 . Indexer properties called Item are special in the sense that they are accessible via the . If a property has both a getter and a setter. 8.2 Method Members A method member is a member-binding of the form: staticopt member ident.13.4).Time is evaluated. Note: A static property member may also be written with an explicit get method: static member ComputerName with get() = System. For example. patn = expr The ident. property members may be reduced to the following two forms: staticopt member ident. When evaluated.Environment.%s)" s1 s2 The rules of arity analysis (§14. This is because F# members must compile to CLI methods and be compatible with the expected compiled form of CLI methods.staticopt member ident. then either both must be abstract or neither. Static and instance property members are evaluated every time the member is invoked.[i].j]. given type C () = static member Time = System. The following limitations apply to curried method members:   Additional argument groups may not include optional or byref parameters. Property members may be declared abstract. Arity analysis (§14.[i. 121 . An Item property taking one argument is accessed using x. and when taking two arguments via x. which accept only a single fixed collection of arguments. then the signatures of both getter and setter must imply the same property type. For example: static member StaticMethod2 s1 s2 = sprintf "In StaticMethod(%s.opt ident with set patidx pat = expr The ident. Each property member has an implied property type.13.13.opt ident with get patidx = expr staticopt member ident.

the following code resolves the named argument to a settable property: System.13. "Hello {0}") Similarly. For example: type C() = member x. arg2 = 3) The following code is valid: type Foo() = static member M (arg1. The resolution of calls that use named arguments is specified in Method Application Resolution (see §14. For example: System. arg0 = "World") System. 8. The Method Application Resolution (§14. Note: It is not recommended that curried argument members appear in the public API of an F# assembly that is designed for use from other . or from the names used in the signature for a method member.NET method with arguments concatenated into a single argument group.Console.Form(Text = "Hello World") If an ambiguity exists. That is. arg0 = "World") System. These must be a prefix of the original required arguments.4 Named Arguments to Method Members Calls to methods—but not to let-bound functions or function values—may use named arguments. The information about the currying order is not visible to these languages. arg3 not a prefix of the argument list Foo.WriteLine(arg0 = "World". For example. After named arguments have been assigned.M(1.4).Swap(second = 1.first = 2) // result is '(2. Curried members may not be overloaded.WriteLine(arg0 = "World".2)' Named arguments may be used only with the arguments that correspond to the arity of the member. named arguments are associated with matching formal parameters of the same name of ―settable‖ return properties of the same name. the remaining required arguments are called the required unnamed arguments. second) = (second. arg3) = 1 // error: arg1.NET languages.WriteLine("Hello {0}". the following code is invalid: // error: unnamed args after named System. first) let c = C() c.second = 2) c. named arguments may not be used with subsequent curried arguments of the member. during resolution. For example.Forms. arg2.Console. assigning the named argument to a formal parameter takes precedence over settable return properties.WriteLine(format = "Hello {0}".Console. the following code is invalid: type Foo() = static member M (arg1. arg2.Console. format = "Hello {0}") The argument names associated with a method declaration are derived from the names used in the first pattern of a member binding.1)' // result is '(1.Swap(first = 1. arg3) = 1 122 . including optional arguments matched by position. The compiled representation of a curried method member is a .4) rules ensure that:  Named arguments must appear after all other arguments. The rules in that section describe how. because members have an arity only up to the first set of tupled arguments.Windows. 2.Swap(first.

if necessary.M (1.TwoArgs(arg1. For example: let defaultArg x y = match x with None -> y | Some v -> v type T() = static member OneNormalTwoOptional (arg1. These must come at the end of the argument list. arg1 = 0. For example: type C() = static member ThreeArgs : arg1:int * arg2:int * arg3:int -> int abstract TwoArgs : arg1:int * arg2:int -> int default x.13. Optional arguments may not be used in member constraints. such as ?arg2=None or ?arg2=Some(3) or ?arg2=arg2. 3. arg3 = 11) T. 2) T.arg2) = arg1 + arg2 8.OneNormalTwoOptional(0. ?arg3 = Some 11) The resolution of calls that use optional arguments is specified in Method Application Resolution (see §14.OneNormalTwoOptional(arg1 = 3) T. 11) T. In a signature.OneNormalTwoOptional(3. arg1 = 0. This can be useful when building one method that passes optional arguments on to another. By propagating an existing optional value by name. arg3 = 11) T. arg2 = 3) The names of members may be listed in signatures and in the signatures used for abstract members. optional arguments appear as follows: static member OneNormalTwoOptional : arg1:int * ?arg2:int * ?arg3:int -> int Callers may specify values for optional arguments by using the following techniques:   By name. 3.OneNormalTwoOptional(arg1 = 3. such as arg2 = 1.OneNormalTwoOptional(arg1 = 3. ?arg2 = Some 1) T.4).OneNormalTwoOptional(arg2 = 3. unnamed arguments matched by position.OneNormalTwoOptional(arg2 = 3. arg2 = 1) T. 123 . arg1 = 0. ?arg2. arg1 = 0) T. although there is a way to pass a value of type option<argType>.  By using normal. arg3 = 11) T. An optional argument is marked with a ? before its name in the method declaration.5 Optional Arguments to Method Members Members (but not functions declared in ―let‖ bindings) may have optional arguments.OneNormalTwoOptional(?arg2 = Some 3.OneNormalTwoOptional(0. For example: T. ?arg3) = let arg2 = defaultArg arg2 3 let arg3 = defaultArg arg3 10 arg1 + arg2 + arg3 Optional arguments may be used in interface and abstract members. arg3 = 11) T. On the call side the argument is provided with a value of type argType.OneNormalTwoOptional(3) T. 3.OneNormalTwoOptional(arg2 = 3. Inside the member the argument has type option<argType>. 2.OneNormalTwoOptional(0.Foo.

CLI optional arguments can propagate an existing optional value by name..xlRows. The value System. The compiled representation of members varies as additional optional arguments are added. In other words. If it is not. two type-directed conversions are applied at method invocations.  If a formal parameter is of delegate type D. Gallery = XlChartType.. and an actual argument farg has known type ty1 -> .Imported CLI metadata may specify arguments as optional and may additionally specify a default value for the argument..FSharp.. the default value from the CLI metadata is supplied instead.Core. and an actual argument type is not a byref type.13. and the default (zero-bit pattern) value is supplied otherwise for other CLI optional arguments with no default value. If the optional argument is present. CategoryTitle = "Sample Category Type". These are treated as F# optional arguments. Title = "Sample Chart".Reflection. and the number of arguments of the Invoke method of delegate type D is precisely n.6 Type-directed Conversions at Member Invocations As described in Method Application Resolution (see §14. For example: type C() = static member M1(arg: System. > tyn -> rty. If the attribute is applied to an argument. PlotBy = XlRowCol.M2(result) // allowed // allowed // not allowed 124 . it has no effect and callers must provide all of the arguments. ?ValueTitle = Some (…).Action) = () static member M2(arg: byref<int>) = () C. argn -> farg arg1 .OptionalArgument attribute (§16.4).Chart.1.Object that do not have a corresponding CLI default value.1) to a required argument. For example.  If a formal parameter is an out parameter of type byref<ty>.Value is supplied for any CLI optional arguments of type System. 8. Otherwise. below is a fragment of a call to a Microsoft Excel COM automation API using named and optional arguments. an F# reference cell can be passed where a byref<ty> is expected. ValueTitle = "Sample Value Type") Note that CLI optional arguments are not passed as values of type Option<_>. 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. Adding the [<OptionalArgument>] attribute to a parameter of type 'a option in a virtual method signature is equivalent to using the (?x:'a) syntax in a method definition.Missing. for example. Marking an argument as optional is equivalent to adding the Microsoft.xl3DColumn. its value is passed. HasLegend = true. This attribute is added implicitly for optional arguments. then the parameter is interpreted as if it had been written new D(fun arg1 .M1(f) let result = ref 0 C.. then the actual parameter is interpreted as if it had type ref<ty>. it should be applied to all subsequent arguments to the function.M1(fun () -> ()) let f = (fun () -> ()) in C. argn).. chartobject.ChartWizard(Source = range5.

Form() member x.IntegerOutParam(res2). This check ignores return types except for members named op_Implicit or op_Explicit.text System.ChangeText(text: string) = x.Text <. 8.MessageBox.13.Forms. The interior address of the heap-allocated cell associated with such a parameter is passed as the pointer argument. the abstract signature can be implemented as follows: let x = {new D() with IntegerOutParam(res : int byref) = res <.Windows.Forms. consider the following C# code: public class C { static public void IntegerOutParam(out int x) { x = 3.Action>.ChangeText(text: string. For example.Windows. } } public class D { virtual public void IntegerOutParam(out int x) { x = 3.Text <. For example. Methods that take curried arguments may not be overloaded.13. the conversion can apply: type GenericClass<'T>() = static member M(arg: 'T) = () GenericClass<System. A member may not have the same name and signature as another method in the type. } } This can be called by the following F# code: let res1 = ref 0 C. In calls to a function that accepts a byref parameter. a value of type ref<ty> may be passed.M(fun () -> ()) // allowed Note: These type-directed conversions are primarily for interoperability with existing member-based .4} let res2 = ref 0 x.text member x. // res2.Show ("changing text due to " + reason) Methods must be distinct based on their name and fully inferred types.The first of these conversions applies according to the known type of the argument when the argument expression is checked. after erasure of type abbreviations and unit-of-measure annotations.8 Naming Restrictions for Members A member in a record type may not have the same name as a record field in that type.NET libraries and do not apply at invocations of functions defined in modules or bound locally in expressions. For example: type MyForm() = inherit System.contents now equals 3 Likewise. reason: string) = x. 125 . if an explicit type instantiation is given.7 Overloading of Methods Multiple methods of the same name may appear in the same type definition or extension.IntegerOutParam(res1) // res1.contents now equals 4 8.

Control. events are first-class values.FSharp. The F# compiler determines the type arguments.Add(fun args -> printfn "OnRedraw") form._>() [<CLIEvent>] member self. and event is not a keyword.Windows. folding.Control. tyargs>.9 Members Represented as Events Events are the CLI notion of a ―listening point.Control. Event declarations are not built-in to the F# language. that is.ChannelChanged = channelChanged.Delegate > = abstract AddHandler : 'del -> unit abstract RemoveHandler : 'del -> unit type IEvent<'Del.13. The definition of the type is as follows: type IDelegateEvent<'del when 'del :> System. property members marked with the CLIEvent attribute and whose type coerces to Microsoft.8. they are objects that mediate the addition and removal of listeners from a backing list of listeners.FSharp. However.FSharp.IEvent<_. often by some external action such as a mouse click or timer tick.Run(form) Events from CLI languages are revealed as object properties of type Microsoft._>() interface I with 126 .Redraw.FSharp.IDelegateEvent<tydelegate> are compiled to include extra CLI metadata and methods that mark the property name as a CLI event. 'T> The following shows a sample use of events: open System. For example.Forms type MyCanvas() = inherit Form() let event = new Event<PaintEventArgs>() member x. creating and composing events. a configurable object holding a set of callbacks.Delegate > = abstract Add : event : ('T -> unit) -> unit inherit IDelegateEvent<'del> type Handler<'T> = delegate of sender : obj * 'T -> unit type IEvent<'T> = IEvent<Handler<'T>.Publish Similarly.unit> and 'del :> System. The F# library supports a type Microsoft. which are derived from the CLI delegate type that is associated with the event.‖ that is.'T when 'Del : delegate<'T. which can be triggered._> and a module Microsoft.IEvent<tydelegate.Publish override x.OnPaint(args) = event. the following shows the definition and implementation of an abstract event: type I = [<CLIEvent>] abstract ChannelChanged : IEvent<ChannelChanged.Trigger(args) let form = new MyCanvas() form.int> type ImplI() = let channelChanged = new Event<ChannelChanged.Activate() Application. in the following the ChannelChanged property is currently compiled as a CLI event: type ChannelChangedHandler = delegate of obj * int -> unit type C() = let channelChanged = new Event<ChannelChangedHandler.Event that contains operations for mapping.Control. In F#.Redraw = event.

[<CLIEvent>] member self.Item = match x with | Some x -> x | None -> failwith "Option.Publish 8. consider the following type: [<CompilationRepresentation(CompilationRepresentationFlags.ChannelChanged = channelChanged. This can affect the view of the type when seen from other languages or from System. in certain situations an instance member may be compiled as a static method.  The member is an extension member.14.Instance) on the member. However. This happens when either of the following is true:  The type definition uses null as a representation by placing the CompilationRepresentation(CompilationRepresentationFlags. For example.10 Members Represented as Static Members Most members are represented as their corresponding CLI method or property. 8.13. 8. For example: type IX = abstract M : int -> int A class definition may contain abstract member definitions.UseNullAsTrueValue)>] type option<'T> = | None | Some of 'T member x.UseNullAsTrueValue) attribute on the type declaring the member.Instance)>] member x.1 Abstract Members An abstract member definition in a type definition represents a promise that an object will provide an implementation for a dispatch slot. A member that might otherwise have a static representation can be reverted to an instance member representation by placing the attribute CompilationRepresentation(CompilationRepresentationFlags. but must be labeled with the AbstractClass attribute: [<AbstractClass>] type X() = abstract M : int -> int An abstract member definition has the form abstract accessopt member-sig 127 . The Item property is represented as an instance property.Reflection.Item" The IsNone and IsSome properties are represented as CLI static methods.14 Abstract Members and Interface Implementations Abstract member definitions and interface declarations in a type definition represent promises that an object will provide an implementation for a corresponding contract.IsSome = match x with Some _ -> true | _ -> false [<CompilationRepresentation(CompilationRepresentationFlags.IsNone = match x with None -> true | _ -> false member x.

AbstractMethod 6 The combination of an abstract slot declaration and a default implementation of that slot create the F# equivalent of a ―virtual‖ method in some other languages—that is.AbstractMethod n = n + x let v1 let v2 = BaseClass() // not allowed – the class is abstract = (SubClass(7) :> BaseClass) // evaluates to 13 v2.. For example: [<AbstractClass>] type BaseClass() = abstract AbstractMethod : int -> int type SubClass(x: int) = inherit BaseClass() override obj. patn = expr Implementation members implement dispatch slots. get and the curried signature has the form args-spec1 -> . set | ident typar-defnsopt : curried-sig with set..Where a member signature has one of the following forms | ident typar-defnsopt : curried-sig | ident typar-defnsopt : curried-sig with get | ident typar-defnsopt : curried-sig with set | ident typar-defnsopt : curried-sig with get. and if both are specified then it is equivalent to two abstract members. an abstract member that is guaranteed to have an implementation.. -> args-specn -> type For n ≥ 2 then args-spec2 … args-specn must all be patterns without attribute or optional argument specifications.AbstractMethodWithDefaultImplementation n = n type SubClass1(x: int) = inherit BaseClass() override obj. For example: type BaseClass() = abstract AbstractMethodWithDefaultImplementation : int -> int default obj.AbstractMethodWithDefaultImplementation n = n + x type SubClass2() = inherit BaseClass() let v1 let v2 let v3 = BaseClass() = (SubClass1(7) :> BaseClass) = (SubClass2() :> BaseClass) 128 ... one with get and one with set.ident pat1 . then the abstract member is a property member.14. If get or set is specified.ident pat1 . 8..2 Members Implementing Abstract Members An implementation member is of the form: override ident. patn = expr default ident.

AbstractProperty = 3 + x override obj.AbstractSettableProperty with get() = data1b + x and set v = data1b <. set abstract AbstractPropertyWithDefaultImplementation : int default obj.x Note: The keywords override and default are synonyms. For example: type ChannelChangedHandler = delegate of obj * int -> unit [<AbstractClass>] type BaseClass() = [<CLIEvent>] abstract ChannelChanged : IEvent<ChannelChangedHandler.x override obj.ToString() = "I'm an instance of SubClass" Implementations may include properties: [<AbstractClass>] type BaseClass() = let mutable data1 = 0 let mutable data2 = 0 abstract AbstractProperty : int abstract AbstractSettableProperty : int with get. int>() with get.v . Implementation members may also implement CLI events (§8.AbstractMethod 6 // evaluates to 6 // evaluates to 13 // evaluates to 6 Implementations may override methods from System.AbstractPropertyWithDefaultImplementation = 3 abstract AbstractSettablePropertyWithDefaultImplementation : int default obj.AbstractSettablePropertyWithDefaultImplementation with get() = data2b + x and set v = data2b <. This records the intended role of the member implementation. int> type SubClass() = inherit BaseClass() let mutable channel = 7 let channelChanged = new Event<ChannelChangedHandler. the override or default should be marked with the CLIEvent attribute.9).v .v type SubClass(x: int) = inherit BaseClass() let mutable data1b = 0 let mutable data2b = 0 override obj. set 129 .13.AbstractMethod 6 v2. override should be used in other cases. it is recommended that default be used only when the implementation is in the same class as the corresponding abstract definition.AbstractPropertyWithDefaultImplementation = 6 + x override obj. In this case.v1.ToString() = "I'm an instance of BaseClass" type SubClass(x: int) = inherit BaseClass() override obj.Object: type BaseClass() = override obj.AbstractSettablePropertyWithDefaultImplementation with get() = data2 and set v = data2 <. However.AbstractMethod 6 v3.

Dispatch Slot Inference (§14.IComparable<string> with member x. even in an abstract class. an interface must be completely implemented.3 Interface Implementations An interface implementation specifies how objects of the given type support the given interface.Channel with get () = channel and set v = channel <. For example: type IIncrement = abstract M : int -> int type IDecrement = abstract M : int -> int type C() = interface IIncrement with member x. either directly or through inheritance.[<CLIEvent>] override self. if a class C implements interface I. In particular.1 No type may implement multiple different instantiations of a generic interface.IComparable<int> with member x. type C() = interface IIncrement with member x.CompareTo(n : int) = 0 interface System.Publish member self. An interface in a type definition indicates that objects of the given type support the given interface.1 All interface implementations are made explicit and where implemented for the first time.v. some. For example: type I1 = abstract V1 : string abstract V2 : string type I2 = inherit I1 130 .M(n) = n .7) is applied. the value x has type C.14. and a base class of C implements interface I. However. For example. then C does not need to implement all the methods of I: it can implement all. channelChanged.ChannelChanged = channelChanged.M(n) = n . or none of the methods instead.CompareTo(n : string) = 1 Each member of an interface implementation is checked as follows:    The member must be an instance member definition. The member is checked under the assumption that the ―this‖ variable has the enclosing type. In the following example.Trigger(self.M(n) = n + 1 interface IDecrement with member x. the following is not permitted: // This type definition is not permitted because it implements two instantiations // of the same generic interface type ClassThatTriesToImplemenTwoInstantiations() = interface System. interface implementations may be inherited from a base class. channel) 8.M(n) = n + 1 interface IDecrement with member x.

1 + 1)) = hash (R (1. 3) <> R (1. (1. C3 implements I2 but not I1. 1 + 1) = (1. 3) 3) 1) 0) 131 . (2. union. (1. For example.15 Equality. 2) evaluates to true. (2. (1. and Comparison Functional programming in F# frequently involves the use of structural equality. structural hashing. 2) 2) 2) 2) < < < > R R R R (1. 2)) R R R R (1.V1 = "C1" member this. (2. (1. (1. because tuple types support structural equality. (1. (1. arrays. Hashing. and user-defined record. 2) 2) 2) 2) < < < > (1. options. Likewise these two function calls return identical values: hash (1. 1 + 1) = R (1.V3 = "C3" // This is also OK. 2) R (1.2) Likewise an ordering on constituent parts of a tuple induces an ordering on tuples themselves. (2. so all the following evaluate to true: (1. and struct types whose constituent field types permit structural equality.V2 = "C2b" 8.V2 = "C2" // This is OK type C2() = inherit C1() // This is also OK. given: type R = R of int * int then all of the following also evaluate to true: R (1. 2) hash (R (1. (1. and structural comparison. 3) 3) 1) 0) The same applies to lists. and comparison. 1 +1 ) hash (1. type C4() = inherit C1() interface I1 with member this.abstract V3 : string type C1() = interface I1 with member this. C4 implements one method in I1. For example: (1. hashing. type C3() = inherit C1() interface I2 with member this.

These implicit declarations are divided into the following for structural equality and hashing: override x.IStructuralComparable with member x.1 Equality Attributes The equality behavior of types can be affected by the following attributes: Microsoft. and exception type definitions.IStructuralEquatable with member x.. member x. interface System.Core. o o o override Equals(obj: obj) interface System.FSharp. 132 . and all structural field types must ty satisfy ty : equality If a type has the CustomEquality attribute.FSharp.GetHashCode() = .CompareTo(y:obj) = . Implicit declarations are never generated for interface. The defaults for System.Collections. Enum types implicitly derive support for equality. class. then o o  o  it must be a structural type.. and the type does not satisfy the ty : equality constraint.IComparer) = ..CustomEquality These have the following effect:  If a type has the NoEquality attribute.IEqualityComparer) = .Core.. or enum types.Core. by default. hashing. otherwise a structural type defaults to StructuralEquality if all structural field types F satisfy F : equality.FSharp. A structural type defaults to NoEquality if any structural field type F fails F : equality. and the following for structural comparison: interface System. That is.IStructuralEquatable  If a type has none of the above equality attributes.GetHashCode(comparer: System... delegate. then no equality or hashing bindings are generated. 8.Equals(y:obj) = . override x..Collections. comparer: System.IComparable with member x.Collections.FSharp. then it must have an explicit implementation of override Equals(obj: obj) A structural type with an explicit implementation of any of the following contracts must specify the CustomEquality attribute.IEqualityComparer) = . and comparison.Collections.In order to facilitate this.NoEquality Microsoft.CompareTo(yobj: obj.Collections.Core. then o o o A non-structural type defaults to ReferenceEquality. and comparison through their underlying representation as integers. struct.. Equality inference also determines the constraint dependencies of a generic structural type. then no equality or hashing bindings are generated. implicitly include compiler-generated declarations for structural equality.. interface System.  If a type has the ReferenceEquality attribute... union.  If a type has the StructuralEquality attribute.Equals(yobj: obj..StructuralEquality Microsoft. called structural types.15.IEquatable<_> interface System. record.ReferenceEquality Microsoft.Object will implicitly be used instead. comparer: System. hashing.

This check also determines the constraint dependencies of a generic structural type.IComparable interface System.Core. 8.Collections. then the EqualityConditionalOn constraint dependency is inferred for 'T. then: o o o o A non-structural type defaults to NoComparison.FSharp. Otherwise a structural type defaults to StructuralComparison if all structural field types F satisfy F : comparison.CustomComparison The comparison attributes have the following effect:  If a type has the NoComparison attribute. An exception type may not have the StructuralComparison attribute.FSharp.  If a type has the CustomComparison attribute.Core. and the type does not satisfy the ty : comparison constraint.o If a structural type has a generic parameter 'T and T : equality is necessary to make the type default to StructuralEquality. and all structural field types must ty satisfy ty : comparison.2 Comparison Attributes The comparison behavior of types can be affected by the following attributes: Microsoft. then the ComparisonConditionalOn constraint dependency is inferred for 'T. then it must have an explicit implementation of at least one of o o interface System. An exception type defaults to NoComparison.IStructuralComparable A structural type with an explicit implementation of one of the above contracts must specify the CustomComparison attribute. then no comparison bindings are generated.  If a type has the StructuralComparison attribute.Core.  If a type has none of the above comparison attributes. StructuralComparison>] type X = X of (int -> int) gives: The struct. For example: [<StructuralEquality. record or union type 'X' has the 'StructuralEquality' attribute but the component type '(int -> int)' does not satisfy the 'equality' constraint 133 . then o o it must be a structural type.15. o If a structural type has a generic parameter 'T and T : comparison is necessary to make the type default to StructuralComparison. excluding exception types.FSharp. Other structural types default to NoComparison if any structural field type F fails F : comparison.NoComparison Microsoft.StructuralComparison Microsoft. That is.

Create() = R1.Core.(=) is invoked on each corresponding pair of fields of x and y in declaration order.  When T is a union type. CustomComparison>] on a structural type [<StructuralEquality. StructuralComparison>] on a structural type 8. If this fails. Microsoft.Equals(y:obj) = . NoComparison>] on a structural type [<CustomEquality.Equals(y : obj) = ((x :> System. and returns false. If T is a reference type. stopping at the first false result and returning false. implementation is as follows. If any of the following attributes are present. 134 . NoComparison>] on a structural type [<ReferenceEquality>] on a non-struct structural type [<ReferenceEquality. CustomComparison>] on a structural type [<StructuralEquality.IComparable.IComparable has been given. the behavior of the generated override x.CompareTo(y) = 0) Otherwise:    The y argument is converted to type T.FSharp.3 Behavior of the Generated Object.Fresh() = R2.For example. First.15. NoComparison>] on a non-struct structural type [<StructuralEquality.Core.(=) is invoked first on the index of the union cases for the two values.FSharp.Make() all evaluate to true.Operators.. NoComparison >] type R3 = { someType : System. given type R1 = { myData : int } static member Create() = { myData = 0 } [<ReferenceEquality>] type R2 = { mutable myState : int } static member Fresh() = { myState = 0 } [<StructuralEquality. NoComparison>] on any type [<CustomEquality. they may only be used in the following combinations:           no attributes [<NoComparison>] on any type [<NoEquality. When T is a struct or record type. and y is null. if an explicit implementation of interface System.IComparable).Make() = R3. stops at the first false result.CompareTo: override x.Type } static member Make() = { someType = typeof<int> } then R1.Create() not (R2.Equals Implementation For a type definition T.Fresh()) R3. then just call System.Operators.. Microsoft. then false is returned. then false is returned. then on each corresponding field pair of x and y for the data carried by the union case.

compare is invoked first on the index of the union cases for the two values. Microsoft.6 Behavior of hash.(=) is invoked on the index of the tags for the two values.FSharp.Core.IComparable with member x. = and compare.15.1 Pseudo code for Microsoft. then on each corresponding field pair of x and y for the data carried by the union case.4 Behavior of the Generated CompareTo Implementations For a type T. fast (but semantically equivalent) code is emitted for direct calls to (=). yobj with | null...FSharp. This code ensures:    Ordinal comparison for strings Structural comparison for arrays Natural ordering for native integers (which do not support System.15. the behavior of the generated System. and comparison declarations described in the previous section make use of the F# library functions hash. and compare The generated equality. and faster paths are used for comparing most arrays.15. If T is a reference type. 8.Core.compare is invoked on each corresponding pair of fields of x and y in declaration order.5 Behavior of the Generated GetHashCode Implementations For a type T. The behavior of these library functions is defined by the pseudocode later in this section. If this fails an InvalidCastException is raised. Note: The first lines of this code can be written: interface System. then 1 is returned. and y is null.Core. hashing.  When T is a union type. =.Operators. stopping at the first false result and returning false.IComparable. 8. 8.IComparable) 8. open System /// Pseudo code for code implementation of generic comparison. returning the first non-zero result. Microsoft.CompareTo implementation is as follows:    The y argument is converted to type T .Operators. null -> 1 135 .FSharp. compare. When T is an exception type.Object.compare Note: In practice.6. and hash for all base types.CompareTo(y:obj) = let y = (obj :?> T) in match obj with | null -> 1 | _ -> . The first non-zero result is returned.Operators.FSharp. let rec compare x y = let xobj = box x let yobj = box y match xobj. null -> 0 | null. Microsoft. then on each corresponding field pair for the data carried by the exception.Operators. _ -> -1 | _. the behavior of the generated System.Core. When T is a struct or record type.15.GetHashCode() override is to implement an combination hash of the structural elements of a structural type.

// Check for IComparable | (:? IComparable as x). (:? float as f2) -> .FSharp..yobj with | null.Equals. | _ -> xobj.Operators.....CompareTo(yobj) | _.// Use Ordinal comparison for strings | (:? string as x).CompareOrdinal(x.(:? string as y) -> String.. This is reference equality // for reference types unless an override is provided (implicitly // or explicitly).. compare the unsigned integers x and y.(:? nativeint as y) -> . IEEE equality on f1 and f2.CompareTo(xobj))) // Otherwise raise a runtime error | _ -> raise (new ArgumentException(. compare the native integers x and y..(:? unativeint as y) -> .. lengths and elements . and hash for all base types.. | (:? unativeint as x).2 Pseudo code for Microsoft.. compare the arrays by rank.. (:? float32 as f2) -> ..._ -> false | _.)) 8.null -> true | null.. // Otherwise use Object.(=) Note: In practice.. fast (but semantically equivalent) code is emitted for direct calls to (=)._ -> x.. IEEE equality on f1 and f2. y) // Special types not supporting IComparable | (:? Array as arr1)....... | (:? nativeint as x). and faster paths are used for comparing most arrays open System /// Pseudo code for core implementation of generic equality. // Ensure NaN semantics on recursive calls | (:? float as f1).6.(:? IComparable as yc) -> -(sign(yc. | (:? float32 as f1). let rec (=) x y = let xobj = box x let yobj = box y match xobj...null -> false // Special types not supporting IComparable | (:? Array as arr1). lengths and elements ..15.Core... (:? Array as arr2) -> . compare.Equals(yobj) 136 . (:? Array as arr2) -> . compare the arrays by rank.

quotient. such as m^3 -.product.dimensionless measure-literal := _ -. kg ( measure-literal-simp ) -.named measure.9 Units Of Measure F# supports static checking of units of measure.variable measure. they differ from types in that they play no role at runtime (in fact.power of measure.named measure e. can contain variables (as in float<'U>). such as m^3 measure-literal-seq := measure-literal-power measure-literal-power measure-literal-seq measure-literal-simp := measure-literal-seq -. such as m s^-2 measure-literal-simp * measure-literal-simp -.implicit product.3) is extended to support numeric constants with units of measure and the syntax of types is extended with measure type annotations.reciprocal. and are supported by special syntax.. such as 'U 'V^3 -. The syntax of constants (§4.product. However.parenthesized measure.parenthesized measure. such as N m -------- 8-bit integer constant 16-bit integer constant 32-bit integer constant 64-bit integer constant single-precision float32 constant double-precision float constant decimal constant -. they are erased). such as 'U * 'V -.anonymous measure measure-literal-simp const := . measure-literal-atom := long-ident -. vector<m/s>. such as m/s^2 / measure-literal-simp -. Units of measure.power of measure. or measuresfor short. add<m>). such as (N m) measure-literal-power := measure-literal-atom measure-literal-atom ^ int32 -. sbyte < measure-literal > int16 < measure-literal > int32 < measure-literal > int64 < measure-literal > ieee32 < measure-literal > ieee64 < measure-literal > decimal < measure-literal > measure-atom := typar long-ident ( measure-simp ) measure-power := measure-atom measure-atom ^ int32 measure-seq := measure-power measure-power measure-seq measure-simp := measure-seq measure-simp * measure-simp measure-simp / measure-simp -. are like types in that they can appear as parameters to other types and values (as in float<kg>. such as kg -. such as 'U / 'V 137 . such as 'U -. they obey special rules of equivalence (so N m can be interchanged with m N). and are checked for consistency by the type-checker.simple measure.quotient. such as m * s^3 measure-literal-simp / measure-literal-simp -.implicit product. such as /s 1 -..g. such as (N m) -.

Quotient measures. and ^ binds tighter still. indicating the measure can be inferred by the compiler from the context. float.0 let distanceTravelled (speed:float<m/s>. written measure ^ int. written measure / measure. 138 . because non-parameterized types such as float are aliases for the parameterized type with 1 as parameter. from long identifiers such as SI. Integer powers of measures. but juxtaposition binds tighter than both * and /. The primitive types sbyte. such as 'U 'V Measure definitions use the special attribute Measure on type definitions.1 Measures Measures are built from       Atomic measures. float = float<1>.reciprocal. consider the following function definitions: let sqr (x:float<_>) = x*x let sumOfSquares x y = sqr x + sqr y The inferred types are: val sqr : float<'u> -> float<'u ^ 2> val sumOfSquares : float<'u> -> float<'u> -> float<'u ^ 2> Measures are type-like annotations such as kg or m/s or m^2.anonymous measure -. 9.feet. that is.kg or MyUnits./ measure-simp -. For example. Variable measures. Measure parameters use the syntax of generic parameters with the same special attribute Measure to parameterize types and members by units of measure. Dimensionless measures indicate ―without units. written 'u or 'U. juxtaposition as shorthand for product.simple measure. int64. * and / have the same precedence. The / symbol can also be used as a unary reciprocal operator. including anonymous measures _. such as /'U 1 -. As with floating-point expressions.dimensionless measure (no units) measure := _ measure-simp -. written 1. Product measures. Dimensionless measures. written measure measure (juxtaposition ) or measure * measure. F# can infer that functions are generic in their units. int16. and ^ for integer powers. and associate to the left. Here is a simple example: [<Measure>] type m // base measure: meters [<Measure>] type s // base measure: seconds [<Measure>] type sqm = m^2 // derived measure: square meters let areaOfTriangle (baseLength:float<m>. height:float<m>) : float<sqm> = baseLength*height/2. int32.‖ but are rarely needed. They have a special syntax that includes the use of * and / for product and quotient of measures. time:float<s>) : float<m> = speed*time As with ordinary types. float32 and decimal have nonparameterized (dimensionless) and parameterized versions.

inverses and abbreviation. For example. Note: These are the laws of Abelian groups together with expansion of abbreviations. kg m / s^2 is the same as m kg / s^2.0f<_> Constants with units of measure are assigned a corresponding numeric type with a measure parameter as specified in the suffix. including one involving unit parameters. or as the product of kg and m s. Here are some examples: let earthGravity = 9.2 Constants Annotated by Measures Floating-point constants can be annotated with their measure by following the constant by a literal measure in angle brackets. followed by measure identifiers. identity. so for example kg^3 is equivalent to kg kg kg. Two measures are indistibuishable if they can be made equivalent by repeated application of the following rules:   Commutativity.    Identity.0<N m^-2> let zero = 0.9. atmosphere is assigned the type float<N/m^2> and zero is assigned the type float<'U>. Atomic measures are ordered as follows: measure parameters first. measures are maintained in the following normalized form: measure-int := 1 | long-ident | measure-par | measure-int measure-int | / measure-int Powers of measures are expanded. reduce each to normalized form by using the rules of commutativity. ordered alphabetically. in error messages). so parentheses are not required.3 Relations on Measures Once parsed and checked. For example. associativity. but with the following restrictions:  Powers are positive and greater than 1. the measure expression m^1 kg s^-1 would be normalized to kg m / s. It is particularly useful if reserved for the constant zero. which can be assigned an arbitrary measure. This splits the measure into positive powers and negative powers. long-ident is equivalent to measure if there is in scope a measure abbreviation of the form [<Measure>] type long-ident = measure.81f<m/s^2> let atmosphere = 101325. In the example above. separated by /. Abbreviation. measure-int / measure-int is equivalent to 1. measures are presented in the normalized form that appears at the beginning of this section.  For example. earthGravity is assigned the type float32<m/s^2>. 139 . Associativity. kg m s can be split as the product of kg m and s. 1 measure-int is equivalent to measure-int. measure-int1 measure-int2 is equivalent to measure-int2 measure-int1. Inverses. Measure annotations on constants may not include measure variables. ordered alphabetically. This normalized form provides a convenient way of checking the equality of measures: given two measure expressions measure-int1 and measure-int2. It does not matter what grouping is used for juxtaposition (product) of measures. For presentation purposes (for example. 9. and then compare the syntax.

9. Y: float<'U>.6. For example: val sqr<[<Measure>] 'U> : float<'U> -> float<'U^2> type Vector<[<Measure>] 'U> = { X: float<'U>. distinct from other measures.3.1 Constraint solving The mechanism described in §14. y : float<s>) -> x + y would (eventually) result in the constraint m^2 = s. tyarg2n> is reduced to a series of constraints tyarg1i = tyarg2i. indicating a type error.9.9). the following is not a valid measure definition: [<Measure>] type X = X^2 Measure definitions and abbreviations may not have type or measure parameters. rather than types. For example: [<Measure>] [<Measure>] [<Measure>] [<Measure>] type type type type kg m s N = kg / m s^2 A primitive measure abbreviation defines a fresh. repeatedly eliminating measure abbreviations in favor of their equivalent measures must not result in infinite measure expressions.5 is extended to support equational constraints between measure expressions. For example. For example. define new names for existing measures. a generalization procedure produces measure variables over which a value. For the arguments that are measures.2 Generalization of Measure Variables Analogous to the process of generalization of type variables described in §14. which cannot be solved. 140 .. Also like type abbreviations. the rules listed above are applied to obtain primitive equations of the form 'U = measure-int where 'U is a measure variable and measure-int is a measure expression in internal form.8. the parameter name is prefixed by the special attribute Measure. then a type error is produced. 9. the expression fun (x : float<m^2>..5 Measure Parameter Definitions Measure parameter definitions can appear wherever ordinary type parameter definitions can (see §5.. which would be further reduced to the primitive equation 'U = m/s.3. function or member can be generalized. The variable 'U is then replaced by measure-int wherever else it occurs.. These arise from equations between parameterized types—that is. 9. If an explicit parameter definition is used.. Measure abbreviations. For example. Z: float<'U>} type Sphere<[<Measure>] 'U> = { Center:Vector<'U>. If constraints cannot be solved.. tyarg1n> = type<tyarg21.2.4 Measure Definitions Measure definitions define new named units-of-measure by using the same syntax as for type definitions.. named measure.. when type<tyarg11. like type abbreviations. the equation float<m^2/s^2> = float<'U^2> would be reduced to the constraint m^2/s^2 = 'U^2. with an additional attribute.

System.IConvertible. System. This is used when checking the actual arguments to types and other parameterized definitions. Reflection is with respect to erased types. and corresponding generic interfaces.IComparable<float<'u>> and System.7 Type Definitions with Measures in the F# Core Library The following types are defined in the F# core library: type type type type type type type float<[<Measure>] 'U> float32<[<Measure>] 'U> decimal<[<Measure>] 'U> int<[<Measure>] 'U> sbyte<[<Measure>] 'U> int16<[<Measure>] 'U> int64<[<Measure>] 'U> These type definitions have the following special properties:   They extend System. measure parameters are not exposed in the metadata that is interpreted by the runtime.IFormattable.Radius:float<'U> } type Disc<[<Measure>] 'U> = { Center:Vector<'U>.6 Measure Parameter Erasure In contrast to type parameters on generic types. 141 . System. 9. instantiated at the given type—for example.  Their compiled form is (through erasure) the corresponding primitive type. instead they are erased. 9. Note: The F# core library definitions above are called measure annotated base types and are marked by the MeasureAnnotatedAbbreviation attribute in the implementation of the library. Radius:float<'U>. Erasure has several consequences:    Casting is with respect to erased types. rejecting ill-formed types such as float<int> and IEnumerable<m/s>. Overload resolution is with respect to erased types. Norm:Vector<1> } type SceneObject<[<Measure>] 'U> = | Sphere of Sphere<'U> | Disc of Disc<'U> Internally. They explicitly implement System.ValueType.IEquatable<float<'u>> (so that you can invoke. for example.IComparable. the type-checker distinguishes between type parameters and measure parameters by assigning one of two sorts (Type or Measure) to each parameter. CompareTo after an explicit upcast). The MeasureAnnotatedAbbreviation attribute is not for use in user code and in future revisions of the language a warning or error may result if this attribute is used.

abs. (*). and decimal are assumed to have additional static members with measure types as follows (here N is any of these types. Abs and op_UnaryNegation and op_UnaryPlus have type N<'U> -> N<'U>.(~+). (-). sign. For the purposes of constraint solving and other logical operations on types. int16. Sign has type N<'U> -> int. op_Multiply has type N<'U> -> N<'V> -> N<'U 'V>. 142 . op_Division has type N<'U> -> N<'V> -> N<'U/'V>.(~-). a type equivalence holds between the unparameterized primitive type and the corresponding measured type definition instantiated at <1>: sbyte = int16 = int32 = int64 = float = float32 decimal sbyte<1> int16<1> int32<1> int64<1> float<1> = float32<1> = decimal<1>  The measured type definitions sbyte. int32. Atan2 has type F<'U> -> F<'U> -> F<1>.(%). float32. atan2 and sqrt. int64. float. (/). This mechanism is used to support units of measure in the following math functions of the F# library: (+). F is either float32 or float): o o o o o o o Sqrt has type F<'U^2> -> F<'U>. op_Addition and op_Subtraction and op_Modulus have type N<'U> -> N<'U> -> N<'U>.

. a file may contain multiple namespace declaration groups..10 Namespaces and Modules F# is primarily an expression-based language.1 Namespace Declaration Groups With respect to naming. Each such contribution to a namespace is called a namespace declaration group. New components may contribute entities to existing namespaces.elements within no namespace module-defn := attributesopt module accessopt ident = module-defn-body module-defn-body := begin module-elemsopt end module-elem := module-let-binding type-defns exception-defn module-defn module-abbrev import-decl compiler-directive-decl -------top-level let or do bindings type definitions exception definitions module definitions module abbreviations import declarations compiler directives module-let-binding := attributesopt let recopt bindings attributesopt do expr import-decl := open long-ident module-abbrev := module ident = long-ident –.. For example. modules and types in an F# program are organized into namespaces. module-elem access := private internal public 10.side-effect binding compiler-directive-decl := # ident string . However.. These also have corresponding forms in signatures. some of which can contain further declarations. The definition of the various elements of an environment is found in §14. namespace-decl-group := namespace long-ident module-elems namespace global module-elems -.elements within a namespace -. Declarations are grouped using namespace declaration groups. which finally contain expressions. and the types and modules may contain members and―let‖ bindings.binding -. F# source code units are made up of declarations. 143 .1. each of which defines types and modules. Declaration elements are processed with respect to an environment. type definitions. string module-elems := module-elem . and module definitions.

Part2.MyLibrary module Values1 = let x = 1 A namespace declaration group is the basic declaration unit within F# implementation files and contains a series of module and type definitions that contribute to the indicated namespace.x + 1 namespace Utilities. MyOtherLibrary.Part2 namespace is not in scope: namespace Utilities.x + 2 Within a namespace declaration group.Part2 module Module2 = let x = Utilities. the individual declarations are checked in order and an overall namespace declaration group signature Nsig is inferred for the module.Module1.Part1. as in this example: namespace MyCompany.Part1 module Module1 = let x = Utilities.Module2. the declaration of x in Module1 generates an error because the Utilities.9).MyOtherLibrary type MyType() = let x = 1 member v. This rules out invalid recursive definitions. so that later namespace declaration groups are not in scope when earlier ones are processed.Collections type MyCollection(x : int) = member v.P = x + 2 module MyInnerModule = let myValue = 1 namespace MyCompany.P = x A namespace declaration group can contain types and modules.P = x+2 let id x = x + 1 // allowed // not allowed: values are not allowed in namespaces module MyInnerModule = // allowed let myValue = 1 When a namespace declaration group N is checked in an environment env. namespace MyCompany. In the following example. but not values. An implementation file may contain multiple namespace declaration groups. An entry for N is then added to the ModulesAndNamespaces table in the environment env (see §14. namespace declaration groups are processed sequentially rather than simultaneously.For example: namespace MyCompany. For example: // error (Part2 not yet declared) 144 . Like module declarations. For example.MyLibrary type MyType() = let x = 1 member v.1. the namespace itself is implicitly opened if any preceding namespace declaration groups or referenced assemblies contribute to it.

MyLibrary module Values1 = let x = 1 namespace MyCompany.StorageCache() module Part2 = type StorageCache() = member cache.MyLibrary // Implicit open of MyCompany. so that later namespace declaration groups are not in scope when earlier ones are processed.namespace MyCompany.‖ ―Let‖ bindings in modules may declare explicit type variables and type constraints: 145 ..MyLibrary brings Values1 into scope module Values2 = let x = Values1. Grouping code in modules helps keep related code together and helps avoid name conflicts in your program.x 10. An entry for M is then added to the ModulesAndNamespaces table in the original environment env0. and bindingn For example: module M = let x = 1 let id x = x let rec fib x = if x <= 2 then 1 else fib (n . For example: module MyModule = let x = 1 type Foo = A | B module MyNestedModule = let f y = y + 1 type Bar = C | D When a module definition M is checked under an input environment env0.1) + fib (n . module Part1 = let x = Part2. // error (Part2 not yet declared) 10. Like namespace declaration groups. Adding the attribute [<CompilationRepresentation(CompilationRepresentationFlags.. and function values. the individual declarations are checked in order and an overall module signature Msig is inferred for the module.ModuleSuffix)>] adds the suffix Module to the name of a module for the purposes of this check.2) Values and functions defined by ―let‖ bindings are referred to simply as ―values.2 Module Definitions A module definition is a named collection of declarations such as values.Clear() = () No two types or modules may have identical names in the same namespace. types. module definitions are processed sequentially rather than simultaneously. let recopt binding1 and .2.1 “let” Bindings in Modules ―Let‖ bindings in modules introduce named values and functions.

141592654 Literal values may be used in custom attributes and pattern matching.Monday [<MyAttribute(StartOfWeek)>] let feeling(day) = match day with | StartOfWeek -> "rough" | _ -> "great" A value marked with the Literal attribute is subject to the following restrictions:    It may not be marked mutable or inline.    Each defined value can be used to satisfy the requirements of any signature for the module (§11.2 Literal Definitions in Modules ―Let‖ bindings in modules may be given the Literal attribute. The default accessibility annotation of a ―let‖ binding in a module is public. b) = (1. Externally accessible values have a guaranteed compiled CLI representation of these bindings in compiled CLI binaries. ―Let‖ bindings may specify attributes for values. 'U>(x) = unbox<'U>(box<'T>(x)) A non-function value with explicit type variables is called a type function (§10.DayOfWeek. with the following adjustments:   Each defined value may have an accessibility annotation (§10. [<System. The right-hand side expression must be a literal constant expression made up of either: 146 .Obsolete("Don't use this")>] let pear v = (v. x) let dispose<'T when 'T :> System. Values may have attributes.Dispose() let convert<'T.3). including the ThreadStatic or ContextStatic attributes.IDisposable>(x : 'T) = x.Obsolete("Don't use this")>] let (a.2). Each defined value is externally accessible if it has an accessibility annotation of public and is not hidden by an explicit signature.6).let pair<'T>(x : 'T) = (x.10).count + 1. [<System. v) If more than one value is defined by a ―let‖ binding through pattern matching then the attributes apply to each value. For example: [<Literal>] let PI = 3.2. 10. For example: [<Literal>] let StartOfWeek = System.2.5). 2) Values may be declared mutable: let mutable count = 1 let FreshName() = (count <. count) ―Let‖ bindings in modules are processed in the same way as let and let rec bindings in expressions (§14. It may not be given the ThreadStatic or ContextStatic attributes. Each defined value is subject to arity analysis (§14.

byte array literals. empty sets and maps. // count = 1 let x1 = r<int> // count = 2 let x2 = r<int> // count = 3 let z0 = x1 // count = 3 The elaborated form of a type function is that of a function definition taking one argument of type unit.Type val sizeof<'T> : int module Set = val empty<'T> : Set<'T> module Map = val empty<'Key. expressions. no explicit function parameters) is called a type function.8) and signature conformance (§11. and user-defined numeric literals. 147 . However.. Pure functions whose result is independent of inferred type arguments. with the exception of (). and are generally attributed with one of the RequiresExplicitTypeArguments and GeneralizableValue attributes. Some example type functions from the F# library are: val typeof<'T> : System.6.4 Active Pattern Definitions in Modules ―Let‖ bindings of values with an active-pattern-op-name within modules introduce pattern-matching tags into the environment when that module is accessed or opened.'Value> : Map<'Key.2. Set.empty) A value with explicit generic parameters but arity [] (that is. Type functions are rarely used in F# programming. be used only for computations that do not have observable side effects. though are very convenient when necessary. Type functions may not be defined inside types. For example.3 Type Function Definitions in Modules ―Let‖ bindings of values within modules may be given explicit generic parameters. the elaborated form of let ident typar-defns = expr is the same as the compiled form for the following declaration: let ident typar-defns () = expr References to type functions are elaborated to be invocations of such a function.count + 1). ref ([] : 'T list). for example. unsigned native integer literals. For example: let empty<'T> : (list<'T> * Set<'T>) = ([]. 10.o a simple constant expression. native integer literals. and computation expressions because ―let‖ bindings at these points may not include explicit generic parameters. Type functions are treated specially with respect to generalization (§14. Type functions should.2. or o a reference to another literal. type functions may still perform computations. BigInteger literals.2). 10. That is. For example: let mutable count = 1 let r<'T> = (count <. as a rule.'Value> Type functions are typically used for:   Pure functions that compute type-specific information based on the supplied type arguments.

. ty is asserted to be equal to unit.Collections open System Import declarations can be used in:   Module definitions and their signatures Namespace declaration groups and their signatures An import declaration is processed by first resolving the long-ident to one or more namespace declaration groups and/or modules [F1. For example: module Ops = Microsoft. 10.Form() System.Generic may resolve to one or more namespace declaration groups—one for each assembly that contributes a namespace declaration group in the current environment.FSharp. 10. System.Application. 148 . For example: open Microsoft.Windows. ―Do‖ bindings may be given attributes.1. . B and C into the PatItems table in the name resolution environment.Operators Module abbreviations can be used in:   Module definitions and their signatures Namespace declaration groups and their signatures Module abbreviations are implicitly private to the module or namespace declaration group in which they appear.Collections. Fn] by Name Resolution in Module and Namespace Paths (§14.. Each Fi is added to the environment successively using the technique specified in §14.3 Import Declarations Namespace declaration groups and module definitions can include import declarations..Windows. After checking expr. An error is given if any Fi is a module has the RequireQualifiedAccess attribute. If this attempt fails.1. This warning is suppressed for plain expressions without do in script files (that is. For example.Run(form) [<STAThread>] do main() 10.Forms.let (|A|B|C|) x = if x < 0 then A elif x = 0 then B else C introduces pattern tags A.fsscript files). These make elements of other namespace declaration groups and modules accessible via unqualified names..4 Module Abbreviations Module abbreviations define a local name for a module long identifier.FSharp.fsx and .Core.Forms.2. For example: let main() = let form = new System.2).5 “do” Bindings in Modules A ―do‖ binding within a module may have the form: do expr The expression expr is checked with an arbitrary initial type ty. a warning rather than an error is reported.9.

The default accessibilities are public. have restricted lexical scope. internal Access is only permitted from within the enclosing assembly A. 10. Modules.‖ The CLI compiled form of all non-public entities is internal.5. The list is then appended to the set of names associated with ident in the ModulesAndNamespaces table. it comes before the identifier: module private M = let x = 1 Similarly for concrete type definitions: 149 . Some bindings may not be given an accessibility and.‖ private on a type.1 Permitted Locations of Accessibility Modifiers An accessibility modifier always comes before mutable and inline in ―let‖ bindings in modules: let private x = 1 let private inline f x = 1 let private mutable x = 1 In a concrete module. type definitions.‖ private on a ―let‖ binding in a module means ―private to the module or namespace declaration group. Module abbreviations may not be used to abbreviate namespaces. by their nature.1). Module type abbreviations are lexically available only within the module or namespace declaration group being defined. Note that:    private on a member means ―private to the enclosing type or module. type definitions. Access is only permitted from the enclosing type. module or type representation in a module means ―private to the module. and on members in types. Note: Declaring family and protected specifications are not supported in this version of the F# language. and only from the point of their definition onward. and only from their point of their definition onward. In particular:   ―Let‖ bindings in classes are lexically available only within the class being defined. and exception definitions in namespaces are public. or namespace declaration group. or from assemblies whose strong name is listed using an InternalsVisibleTo attribute in the current assembly. Members in type definitions are public. and exception definitions in modules are public. module.5 Accessibility Annotations Accessibilities may be specified on declaration elements in namespace declaration groups and modules. 10. The permitted user-specified accessibilities are: public private No requirements on access.A module abbreviation module ident = long-ident is processed by first resolving the long-ident to a list of modules by Name Resolution in Module and Namespace Paths (see §14. Specifically:    ―Let‖ bindings.

X = 1 On explicit property get/set in classes: member v.type private C = A | B type private C<'T> = A | B     Not on inherit definitions (always the same as enclosing class) Not on interface definitions (always the same as enclosing class) Not on abstract definitions (always the same as enclosing class) Not on individual union cases On ―val‖ definitions in classes: val private x : int On explicit ―new‖ definitions in classes: private new () = { inherit Base } On implicit ―new‖ definitions in classes: type C private() = . On members in classes: member private x..Item with private get i = 1 and private set i v = () On type representations: type Cases = private | A | B 150 ..

.submodule signature -.. and . and specifies the functionality that is implemented by its corresponding implementation file. module-signature-element module-signature-body = begin module-signature-elements end type-signature := abbrev-type-signature record-type-signature union-type-signature anon-type-signature class-type-signature struct-type-signature interface-type-signature enum-type-signature delegate-type-signature type-extension-signature type-signatures := type-signature ...11 Namespace and Module Signatures A signature file contains one or more namespace or module signatures. namespace-decl-group-signature := namespace long-ident module-signature-elements module-signature = module ident = module-signature-body module-signature-element := val mutableopt curried-sig val binding type type-signatures exception exception-signature module-signature module-abbrev import-decl ----- value signature literal value signature type(s) signature exception signature -.local alias for a module -..locally import contents of a module module-signature-elements := module-signature-element .. It also serves to hide functionality contained within its corresponding implementation file. type-signature type-signature-element := attributesopt accessopt new : uncurried-sig attributesopt member accessopt member-sig attributesopt abstract accessopt member-sig attributesopt override member-sig attributesopt default member-sig attributesopt static member accessopt member-sig interface type abbrev-type-signature := type-name '=' type union-type-signature := type-name '=' union-type-cases type-extension-elementssignatureopt record-type-signature := type-name '=' '{' record-fields '}' type-extension-elementssignatureopt anon-type-signature := type-name '=' begin type-elements-signature end class-type-signature := type-name '=' class type-elements-signature end -------- constructor signature member signature member signature member signature member signature static member signature interface signature 151 .

Part2. in an interface type: type IMap = interface abstract Forward : index1: int * index2: int -> string abstract Backward : name: string -> (int * int) end 152 . signature declarations are processed sequentially rather than simultaneously.struct-type-signature := type-name '=' struct type-elements-signature end interface-type-signature := type-name '=' interface type-elements-signature end enum-type-signature := type-name '=' enum-type-cases delegate-type-signature := type-name '=' delegate-sig type-extension-signature := type-name type-extension-elements-signature type-extension-elements-signature := with type-elements-signature end The begin and end tokens are optional when lightweight syntax is used. A type definition signature may include one or more member signatures. Like module declarations. so that later signature declarations are not in scope when earlier ones are processed.2 Type Definition Signatures Type definition signatures indicate the existence of a corresponding type definition in the implementation. in the signature of a module: module MyMap = val mapForward : index1: int * index2: int -> string val mapBackward : name: string -> (int * int) 11.StorageCache namespace Utilities.Part1 module Module1 = val x : Utilities.1.1 Value Signatures Value signatures indicate the existence of a value in the implementation. 11.1 Signature Elements A namespace or module signature declares one or more value signatures and one or more type definition signatures. Note: This section does not yet document all constructs that may be used in signatures in F# 2.Part2 type StorageCache = new : unit -> unit // error (Part2 not yet declared) 11. in addition to other elements of type definitions as specific by the signature grammar at the start of this chapter.1. For example. namespace Utilities.0. For example.

all. The arities must match (see next section).2. Any type that is revealed to be an interface. That is..2.1 Signature Conformance for Values If a value with a given name is present in both signature and implementation. 11. and optionally specify names and attributes for parameters.11. abstract dispatch slot declarations. * tyn.An -> rty will result in an arity [A1. This means that F# makes a deliberate distinction between the following two signatures: val F: int -> int and val F: (int -> int) 153 .. then:   The declared accessibilities. Member specifications must specify argument and return types. a type abbreviation type T = ty in an implementation does not match type T (without an abbreviation) in a signature.2 Signature Conformance Note: This section does not yet document all checks made by the F# 2. Furthermore.A1 * .  11.0 language implementation. of their fields in a signature..3 Member Signatures Member signatures indicate the existence of a corresponding member on the corresponding type definition in the implementation.An] for F. Arities of values are implicit in module signatures. A signature containing: val F : ty1. Values. or none. with the following exceptions:  Type abbreviations may not be hidden by signatures.1. and mutable modifiers must be identical. The types and type constraints must be identical up to renaming of inferred and/or explicit generic parameters.tyn.    The number of inferred and/or explicit generic parameters must be identical.. inline. and members that are present in implementations can be omitted in signatures. 11. or a type that is a class or struct with one or more constructors may not hide its inherit declaration. Arities in a signature must be equal or shorter than corresponding arities in an implementation. Types whose representations are classes may reveal some. in the same order as that specified in the implementation..ty1. types.1.  Any type whose representation is a record or union must reveal either all or none of its fields or cases. If either has the [<Literal>] attribute then both must have this attribute..1. and the prefix must match.1 Arity Conformance for Values Arities of values must conform between implementation and signature. the declared literal value for each must be identical.. or abstract interface declarations..1.

154 . Thus. by default.[x] else let res = x * x myTable.6. The first signature can only be satisfied by a true function.Generic.8). generalizable (§14.int>(4) fun x -> if myTable. the implementation may currently also be: let F = fun x -> x + 1 The signature val F: (int -> int) can be satisfied by any value of the appropriate type. the implementation let empty<'T> : list<'T> = printfn "hello". some kind of information in signatures is needed to reveal the desired arity of a method as it is revealed to other CLI programming languages. For example: let f = let myTable = new System. [] conforms to this signature: val empty<'T> : list<'T> but not to this signature: val empty : list<'T> Note: The rationale for this rule is that the second signature indicates that the value is.res res or let f = fun x -> x + 1 or // throw an exception as soon as the module bindings are executed let f : int -> int = failwith "failure" Note: In either case you can still use the functions as first-class function values from client code—the parentheses simply act as a constraint on the implementation of the value. rather than to fields that are function values.2 Signature Conformance for Type Functions If a value is a type function.ContainsKey x then myTable. For example.The parentheses indicate a top-level function which might be a first-class computed expression that computes to a function value.Dictionary<int. then its corresponding value signature must have explicit type arguments. 11.2. rather than a compile-time function value.Collections. the implementation must be a lambda value as in let F x = x + 1 Note: Because arity inference also permits right-hand-side lambdas.[x] <.1. The rationale for this interpretation of types in value and member signatures is that CLI interoperability requires that F# functions compile to methods. that is.

2. Abstract members must be present in the signature if a representation is given for a type. The static. If a member with a given name is present in both signature and implementation. then both must be.2 Signature Conformance for Members Note: This section does not yet document all checks made by the F# 2. then both must be. and override qualifiers must match precisely. If one is a property. If one is a constructor. then:       If one is an extension member. then both must be. 155 . The types must be identical up to alpha-conversion (as for values).11.0 language implementation. abstract.

namespace-decl-group named-module anonynmous-module script-file := implementation-file -. modules.  The resulting environment then becomes the active environment for the first file to be processed. impl-envi is identical to impl-envi-1. called the referenced assemblies. First.script file.  If the file is an implementation file file. which gives signature Sigfile. th 156 .fsscript) files.fsi. and namespaces that are referenced by the attribute (in that assembly alone) and add these to the environment. namespace-decl-group-signature anonynmous-module-signature named-module-signature named-module := module long-ident module-elems anonymous-module := module-elems named-module-signature := module long-ident module-signature-elements anonymous-module-signature := module-signature-elements script-fragment := module-elems -. Then..2).fs. then it is checked against environment sig-envi-1. which gives elaborated namespace declaration groups Implfile.. and an interspersed sequence of signature (..fsx or . an initial environment sig-env0 and impl-env0 is formed by adding all assembly references to the environment in the order in which they are supplied to the compiler. modules. The signature Sigfile is added to sig-envi-1 to produce sig-envi. sig-envi is identical to sig-envi-1. This means. implementation (. and interactively executed code fragments. This makes it available for use in later signature files. For each AutoOpen attribute in the assembly. o If a corresponding signature Sigfile exists then Implfile is checked against Sigfile during this process (§11.. Sigfile is then added to impl-envi-1 to produce impl-envi. for each referenced assembly. for each file:  If the i file is a signature file file. then it is checked against environment impl-envi-1. and namespaces to the environment.interactively entered code fragment A sequence of implementation and signature files is checked as follows. implementation-file := namespace-decl-group . find the types. additional directives allowed signature-file:= namespace-decl-group-signature .fs) files. script (.fsi) files. F# assemblies are made up of a set of static references to existing assemblies. the following procedure is applied:   Add the top level types.12 Program Structure and Execution F# programs are made up of a collection of assemblies. This makes the signature-constrained view of the implementation file available for use in later implementation files.

and the preceding identifiers are interpreted as the namespace. Anonymous implementation files are those without either a leading module or namespace declaration. this defines a single namespace declaration group with an implied module. For example: module MyCompany. Given an initial environment env0.MyLibrary. 157 .1 Implementation Files Implementation files are made up of a number of namespace declaration groups.MyModule let x = 1 is equivalent to: namespace MyCompany.exe) may be anonymous. a corresponding implementation file must occur after the file in the compilation order. The namespace declaration groups in the file are checked with respect to envi-1 and incrementally added to the environment (§10.P = x If an implementation file begins with a module declaration. Only the scripts and the last file within an implementation group for an executable image (. MyOtherLibrary. an implementation file is checked as follows:   A new constraint solving context is created. The extension is removed and the first letter is capitalized. For example: namespace MyCompany.P = x + 2 module MyInnerModule = let myValue = 1 namespace MyCompany. Script files may not be given signatures.Collections type MyCollection(x : int) = member v. This makes it available for use in both later signature and implementation files. and the name of the module is implicit from the name of the source file that contains the module.MyLibrary module MyModule = let x = 1 The final identifier is interpreted as the module name.1) to give a new environment envi. If the file name contains characters that are not part of an F# identifier then the resulting module name is unusable and a warning is given. For every signature file. The signature file for an implementation must occur before the implementation file in the compilation order. 12.MyOtherLibrary type MyType() = let x = 1 member v. to produce sig-envi and impl-envi.o If the implementation file has no signature file. An anonymous implementation file contains module definitions that are implicitly placed in a module. the Implfile is added to both sig-envi-1 and implenvi-1.

except that each script is 158 . the name of which is implicit from the name of the source file that contains the module. constructor. Script files may add to the set of referenced assemblies with the #r directive. The extension is removed and the first letter is capitalized.fsx and .Settings is opened by default. then an error is reported. The assembly FSharp. The result of checking a signature file is a set of elaborated namespace declaration group types.2).Compiler.  The inferred signature of the implementation file is checked against any required signature by using Signature Conformance (§11. All remaining type variables in the elaborated form are processed left-to-right and a minimal type solution is found that is consistent with constraints on that type variable. Default solutions are applied to any remaining type inference variables that include default constraints. and script files to the list of sources with the #load directive. implementation.FSharp.Settings.fs with the following exceptions:    Side effects from all scripts are executed at program startup. If no unique minimal solution exists for a type variable. then FSharp. Files are compiled in the same order that was passed to the compiler.dll should be referenced explicitly. a ―value restriction‖ error is reported. if so. Anonymous signature files are those without either a leading module or namespace declaration. The resulting signature of an implementation file is the required signature. otherwise it is the inferred signature. These solutions are applied in the order that the type variables appear in the type-annotated text of the checked namespace declaration groups. if it is present. Each namespace-decl-group-signaturei is checked in envi-1 and the result added to give a new environment envi.3 Script Files Files with extension . Script files may add other signature.Settings.Interactive. If the script uses the script helper fsi object. but is not referenced by default by the F# compiler. 12. The inclusion of a signature file in compilation implicitly applies that signature type to the contents of a corresponding implementation file.fsscript are script files and are processed in the same way as files with extension .Interactive. or type function must not contain any free inference type variables. If the file name contains characters that are not part of an F# identifier then the resulting module name is unusable and a warning is given.2 Signature Files Signature specify the functionality implemented by a corresponding implementation file and contain a sequence of namespace-decl-group-signature elements.   The resulting signature of any item that is not a member. function. Arbitrary choice solutions are applied to any remaining type inference variables in the elaborated form of an expression.dll is referenced automatically by F# Interactive. 12. a signature file is checked as follows:   A new constraint solving context is created.Interactive. Anonymous signature files contain module-elems that are implicitly placed in a module. Given an initial environment env. The namespace Microsoft.Compiler. The result of checking an implementation file is a set of elaborated namespace declaration groups.Compiler.

string. If a file is found multiple times. in the order they appear in the script.fsi" "core.0. Loads a set of signature and implementation files into the script execution engine.searched for #load directives and the loaded files are placed before the script.fs) files. Inputs processed by the F# compiler will have the COMPILED compilation symbol defined. turns off warnings within this lexical scope. The following directives are valid in script files: Directive #r #reference Example #r "System. it is placed in the list only once.. #I @"c:\Projects\Libraries\Bin" Adds a path to the search paths for DLLs used within this entire script.. Script files may have #nowarn directives.fsi) files and implementation (. #else. For script (.fs" #time #time #time "on" #time "off" #help #help Asks the script execution environment for help. #endif and #indent "off" are similar to compiler directives but are dealt with elsewhere in this specification. Version=2.fsx or .Core. Short Description References a DLL within this entire script.dll" #r @"c:\NUnit\Nunit. The lexical directives #if.Core.core. Culture=neutral. 12.2.dll" #r "nunit. at the position it first appeared. The following directives are valid in all files: Directive #nowarn Example #nowarn "54" Short Description For signature (. These disable the warning for the entire compilation. 159 .2.Core" #r @"Nunit.4 Compiler Directives Compiler directives are declarations in non-nested modules or namespace declaration groups of the form # id string .fsscript) files. Inputs processed by the F# Interactive will have INTERACTIVE defined.fs" #load "core. Script files may not have corresponding signature files. PublicKeyToken=96d09a1eb7f44a77" #I #Include #load #load "library. Toggles or sets timing on or off. turns off warnings globally.

FSharp. or the defaultof<_> operator from Microsoft.1 Execution of Static Initializers Each implementation file. A use of the typeof<_> or sizeof<_> operators from Microsoft.5. and script fragment involves a static initializer. Bindings with observable initialization in nested modules and types are included in the static initializer for the overall file. a simple constant expression is an expression whose elaborated form is:    A constant expression. 160 . F# Interactive executes the static initializer for each program fragment immediately. the static initializer for the last file that appears on the command line is the body of the implicit entry point function. Other bindings are said to have observable initialization. or object constructors that the assemblies and script fragments define. values. The following ―let‖-bound values in modules do not have observable initialization:      Functions that have a static arity Type functions Literals Generalized values Non-mutable. script file.Directive #q #quit Example #q #quit Short Description Requests the script execution environment to halt execution and exit. In the above specification.EXE) files that have an implicit entry point. Execution of the CLI program can utilize the functions. static members. non-thread-local values that are bound to a simple constant expression (see later in this section). At runtime. the static initializer for the last file that appears on the command line is forced immediately as the first action in the execution of the entry point function.Operators. The execution of the static initializer is triggered as follows:  For executable (. 12. the bindings in the file that have observable initialization according to the rules that follow. For scripts.Core. or first access to any member of any type in the file that has at least one ―static let‖ or ―static do‖ declaration. A null expression. the static initializer evaluates. in order.    For executable (. 12. For all other implementation files.Operators.5 Program Execution Execution of F# code occurs in the context of an executing CLI program into which one or more compiled F# assemblies or script fragments is loaded.FSharp. the static initializer for the file is executed on first access of a value that has observable initialization according to the rules that follow.Unchecked.Core.EXE) files that have an explicit entry point function.  A let expression where the constituent expressions are simple constant expressions.

then the execution of the static initializer is not yet triggered. >>>. If these are accessed using CLI reflection before the execution of the corresponding binding. not. then the execution of the static initializer is triggered because the body refers to the value data and this value has observable initialization.FSharp.Core. +.int>() let size = 3 let id x = x let f() = data 161 . then each static initializer runs as a mutual exclusion region. Values that have observable initialization have implied CLI fields that are private to the assembly. >=. For example. |||.      A use of a [<Literal>] value. A use of a nullary case from a union type. <>. <<<. respectively. then references to values that are defined by ―static let‖ bindings in the generic class will evaluate to the default value. Note that in the case of arithmetic. ~~~.Operators on one or two arguments.int>() If external code calls id or accesses size in the example below. module LibraryModule printfn "hello" let data = new Dictionary<int. Within implementation files. that are simple constant expressions. <. compare. <=. These initializers are executed immediately before the first dereference of the static fields for the generic type. The use of a mutual exclusion region ensures that if another thread attempts to access a value that has observable initialization. generic types that have ―static let‖ or ―static do‖ bindings are given a static initializer for each generic instantiation. and each target is simple constant expression. ^^^. or the use of a value that is defined by a ―let‖ or ―match‖ expression within the expression itself. A use of a value that is defined in the same assembly and does not have observable initialization. If the static initializer for the enclosing file is first triggered in a ―static let‖ or ―static do‖ binding in a generic class. enum<_>. subject to any limitations present in the specific CLI implementation being used. these are unchecked operators. excluding operations on decimals or strings. then the static initializer is executed and "hello" is printed. &&&. A use of a unary or binary operator =. A match expression where the input is a simple constant expression. then the default value for the type of the field will be returned. If the execution environment supports the concurrent execution of multiple threads of F# code. and prefix + from Microsoft. and that the operators % and / are not included because their use can raise division-by-zero exceptions. -. each case is a test against a constant. A static initializer runs only once. that thread pauses until the execution of the static initializer is complete. module LibraryModule printfn "hello" let data = new Dictionary<int. A use of a case from an enumeration type. prefix –. * . However if external code calls f(). >. if external code accesses data in the example below. on the first thread that acquires entry to the mutual exclusion region.

The function is asserted to have type string[] -> int before checking.Environment.Friday 1.exe) file may additionally contain an explicit entry point. and this function must be the last declaration in the last file processed on the command line. all of the following represent bindings with non-observable initialization. and the body of the function is then evaluated.  At runtime. an error is reported. let let let let let let let let let let let let let let let x x x x x x x x x x x x x x x = = = = = : : = = = = = = = = System.2 Explicit Entry Point The last file specified in the compilation order for an executable (.defaultof<int> Unchecked. If this assertion fails. The function becomes the entry point to the program.5. the static initializer for the file in which the function is declared is immediately forced.Likewise.defaultof<string> sizeof<int> 12. The entry point is indicated by annotating a function in a module with EntryPoint attribute:    The attribute can be applied only to a ―let‖-bound function in a module.DayOfWeek. minus the first entry in that array. Only one function may be given this attribute. the entry point is passed one argument at startup: an array that contains the same entries as System.0 "two" enum<System. 162 . It cannot be a member.DayOfWeek>(0) 1 + 1 int list = [] int option = None compare 1 1 match true with true -> 1 | false -> 2 true && true 42 >>> 2 typeof<int> Unchecked. The function may be in a nested module.GetCommandLineArgs(). When evaluated.

which is found on the attribute class itself. Attributes on parameters are given as follows: let foo([<SomeAttribute>] a) = a + 5 Custom attributes on return values are given as follows: let foo a : [<SomeAttribute>] = a + 5 Custom attributes on primary constructors are given before the arguments and before any accessibility annotation: type Foo1 [<System.1 Custom Attributes CLI languages support the notion of custom attributes which can be added to most declarations.Reflection libraries. . Custom attributes are not permitted on ―let‖ bindings in expressions or computation expressions.Bar() = 1 type Foo2 [<System. attribute >] attributes := attribute-set . This chapter describes these mechanisms for F#.. They also allow entities to be attributed by static data. and these attributes may be accessed and read by tools and running programs. ..Obsolete("don't use me")>] private () = member x. An error occurs if an attribute is attached to a language construct that does not allow that attribute.Bar() = 1 163 . Attributes are given by the following grammar: attribute := attribute-target:opt object-construction attribute-set := [< attribute . These are added to the corresponding elaborated and compiled forms of the constructs to which they apply.Obsolete("don't use me")>] () = member x.. Custom attributes can be applied only to certain target language constructs according to the AttributeUsage attribute. attribute-set attribute-target := assembly module return field property param type constructor event 13..13 Custom Attributes and Reflection CLI languages make guarantees about how compiled entities appear at runtime through the use of the metadata inspection and the System.

let main() = let form = new System.Form() System. The compiled module. and not for ―let‖-bound function definitions. custom attributes attached to items in F# signature files (. the STAThread attribute should be placed immediately before a top-level “do” binding.fsi files) are combined with custom attributes on the corresponding element from the implementation file according to the following algorithm:  Start with lists AImpl and ASig containing the attributes in the implementation and signature.Type object is returned by typeof<type>.Application. remove the attribute from ASig. 164 . The compiled assembly. unless the target of the attribute is field.  Check each attribute in AImpl against the available attributes in ASig.1 Custom Attributes and Signatures During signature checking.  A custom attribute on a union case ABC for a type T is compiled to a custom attribute on a static method on the CLI type definition T.1.  By default. and likewise for the assembly.  Custom attributes that appear immediately preceding ―do‖ bindings in modules anywhere in an assembly are attached to one of the following:    The main entry point of the program. For example.Forms. If it is valid for the attribute to be attached to either the main method or the assembly.Forms. in which case it becomes a custom attribute on the underlying backing field for the CLI property that is named _F. in declaration order. then ignore the attribute in the implementation. whose System. if a target is given. Custom attributes on generic parameters are not propagated. o If ASig contains an attribute that has the same attribute type but is not an exact match. This method is called: o o  get_ABC if the union case takes no arguments ABC otherwise Custom attributes on arguments are propagated only for arguments of member definitions. then give a warning and ignore the attribute in the implementation. a custom attribute on a record field F for a type T is compiled to a custom attribute on the CLI property for the fieldthat is named F. Custom attributes are attached to the main entry point if it is valid for them to be attached to a method according to the AttributeUsage attribute that is found on the attribute class itself. the main method takes precedence. and continue checking.Windows. o If ASig contains an attribute that is an exact match after evaluating attribute arguments.Custom attributes are mapped to compiled CLI metadata as follows:   Custom attributes map to the element that is specified by their target. A custom attribute on a type type is compiled to a custom attribute on the corresponding CLI type definition.Run(form) [<STAThread>] do main() 13.Windows.

They may be removed by optimization.Type.Reflection operations return results that are consistent with the erasure of F# type abbreviations and F# unit-of-measure annotations. The compiled element contains the compiled forms of the attributes from the signature and the retained attributes from the implementation.  The definition of new units of measure results in corresponding compiled CLI type declarations with an associated System. and the attribute appears in the compiled assembly. then a warning is given.Type object for an F# type definition. 13. Additional internal and private compiled type and member definitions may be present in the compiled CLI assembly as necessary for the correct implementation of F# programs.  When a signature has an attribute X("abc") and the implementation is missing the attribute. If this operation is supported in a particular implementation of F#.Type object. According to typical implementations of the CLI execution environment.2 Reflected Forms of Declaration Elements The typeof and typedefof F# library operators return a System. then the following rules describe which declaration elements have corresponding System. keep the attribute in the implementation.  When an implementation has an attribute X("abc") and the signature has attribute X("def").o  Otherwise. In addition:  F# modules are compiled to provide a corresponding compiled CLI type declaration and System. However:   Internal and private module ―let‖ bindings are not guaranteed to be given corresponding compiled CLI metadata definitions. Private and internal members and types are included.Type definitions. the System.Type object is not accessible by using the typeof operator. then no warning is given. then no warning is given and the attribute appears in the compiled assembly. This means:  When an implementation has an attribute X("abc") and the signature is missing the attribute. and only X("def") appears in the compiled assembly.  The System. properties or events.Type object in turn can be used to access further information about the compiled form of F# member declarations. Type abbreviations are not given corresponding System.Reflection objects:    All member declarations are present as corresponding methods. although the System. 165 .

in the default type-checking environment. For example. then the assemblies are added to the name resolution environment in the order in which the references are specified on the command line.1.Collections may map to one namespace declaration group signature for each referenced assembly that contributes to the System. 166 .14 Inference Procedures 14. the resolution of System. if a module called System. This may return multiple types.1 Name Environments Each point in the interpretation of an F# program is subject to an environment. where an item is: o o o A union case (for use when pattern matching on data) An active pattern case name (for use when specifying active patterns) A literal definition  Types: a table that maps names to type definitions.  ExprItems: a table that maps names to items. This returns at most one type. the resolution of System. Each signature is either a namespace declaration group signature or a module signature.1 Name Resolution 14.Collections is declared or in a referenced assembly. where an item is: o o o o   A value A union case (for use when constructing data) An active pattern result tag (for use when returning results from active patterns) A type name (for each class or struct type) FieldLabels: a table that maps names to sets of field references for record types PatItems: a table that maps names to items.Tuple returns multiple tuple types. The environment encompasses:   All referenced external DLLs (assemblies).Tuple with n = 2 returns a single type. if two assemblies define the type MyNamespace. For example. in the default typechecking environment. Find a type by name and generic arity n. This matters only if ambiguities arise in referencing the contents of assemblies—for example. ModulesAndNamespaces: a table that maps long-idents to a list of signatures. and to a module signature. If multiple assemblies are referenced.C. System. For example. Two queries are supported on this table: o Find a type by name alone. o  ExtensionsInScope: a table that maps type names to one or more member definitions The dot notation is resolved during type checking by consulting these tables.Collections namespace.

2 Name Resolution in Module and Namespace Paths Overview: Given an input long-ident and environment env..._> as a value or other expression item. An exception constructor in F. 14.. then return this type. Details: If long-ident is a single identifier ident then:   Look up ident in the ExprItems table and return the result and empty rest. A list of modules and namespace declaration groups is returned.Generic. For the identifiers that remain. including those implied by AutoOpen attributes. consider each module signature or namespace declaration group signature F in the list that is produced by resolving namespace-or-module-path by using Name Resolution in Module and Namespace Paths. Return this item and rest. If rest is empty. in which the namespace-or-module-path becomes successively longer..ident[. Return this item and rest. fail. For example. attempt to resolve ident[. with rest as the residue..Collections. environment env. o For each such division. System. then terminate the search:     A value in F. look up ident in the Types table. and System. if the environment contains two referenced DLLs. If any resolution succeeds.  Otherwise..rest:   If ident exists as a value in the ExprItems table. each with namespace declaration groups for the namespaces System.. and return this type and empty rest. Otherwise._>. and all results are concatenated. otherwise resolve using Name Resolution for Members.1.Collections. consider the following backtracking search: o Consider each division of long-ident into [namespace-or-module-path]. 167 .rest] in the following order.1. the declared modules and submodules of these fragments are consulted recursively. Name Resolution in Module and Namespace Paths computes the result of interpreting long-ident as a module or namespace.3 Name Resolution in Expressions Overview: Given an input long-ident. Recursively resolve rest against the contents of this module. If the long-ident starts with the special pseudo-identifier keyword global. then return the result. and an optional count n of the number of subsequent type arguments <_. If long-ident is made up of more than one identifier ident.Collections returns the two entries for that namespace. and a residue path rest..rest]. o For each such F. the identifier is resolved with respect to the ModulesAndNamespaces table ignoring all open directives.14. with generic arity matching n if available. then Name Resolution in Module and Namespace Paths for System. Return this item and rest. Name Resolution in Expressions computes a result that is composed of the interpretation of a prefix of long-ident<_. Details: A prefix of long-ident is resolved to a list of modules and namespace declaration group signatures by consulting the ModulesAndNamespaces table. A type in F.  A [sub-]module in F. Otherwise. A union case in F.

Prop2 = 3 let C = 5 open M let C = 4 let D = 6 let let let let let test1 test2 test3 test4 test5 = = = = = C C.C M.   Otherwise. If rest is empty then return this type.ToString() M. look up ident in the ExprItems table and return the result and residue rest. then resolve to this type. otherwise resolve using Name Resolution for Members.C. and this contains no field or property "C" error: the value C does not have a property Prop resolves to M. fail.Data.Data. Otherwise. If no generic arity n is available. Ambiguities are resolved by the first result that the name resolution process returns.C M.Prop1 = 3 member x. give an error.Prop1 = 3 type Data = | C of string | E member x.C // // // // // // // // resolves to the value C resolves to the value C with residue ToString resolves to the value M.Prop1 let test7 = M. Otherwise.  Otherwise.E.  Otherwise. then give a warning that the generic arguments cannot be inferred from the type of the item.C. look up ident in the Types table: o o If a generic arity matching n is available. if ident is a symbolic operator name then resolve to an item that indicates an implicitly resolved symbolic operator. and rest is non-empty.  If the Types table contains a unique type ident with generic arguments.C resolves to the union case M. then simply look up any type matching ident and n. and then a property lookup let test6 = C.Prop2 168 .E. consider the following cases: module M = type C = | C of string | D of string member x. For example. then:  If the Types table contains a type ident without generic arguments.C error: first part resolves to the value M. if the overall result of the Name Resolution in Expressions operation is an item and the generic arguments do not appear in either the return or argument types of the item. However. then resolve to this type.

C. resolves gives an error no error.P. resolves gives an error no error.C.C<int. resolves no error. warning given The above rules lead to the fact that value names are preferred over module names for single identifiers. resolves resolves resolves resolves resolves resolves resolves resolves resolves resolves to to to to to to to to to to C C<'T> C C C<'T> C C<'T> C C C<'T> The following example shows a case where a warning is given for an incomplete type.int>() M.C<int>() M.'U> C<'T> C<'T.C() new M. error. error. because it does not appear at all in the type of the resolved element M.C< >() M. module M = type C<'T>() = static member P = 1 let _ = M.C<_>.C<_.P // no error.C< >._>.C<_>() M.P. error. error. error.P M.'U> to C<'T> to C<'T.P M.C<_>. error.C() M.P // // // // // // // // // // no no no no no no no no no no error. resolves no error.C< >() M.'U> The following example shows how the resolution behavior differs slightly if one of the types has no generic arguments. For example.C<int>() M.C() new M.C. consider this case: let Foo = 1 module Foo = let ABC = 2 let x1 = Foo // evaluates to 1 169 . resolves to C<'T>. error.P // // // // // // // // // // gives an error no error. resolves to C<'T> to to to to C<'T> C<'T.P.C() M.P M. error.C._>() M.C<_.C<_>() M. error.P M. because the type parameter 'T cannot be inferred from the use M.'U>() = static member P = 1 let let let let let let let let let let _ _ _ _ _ _ _ _ _ _ = = = = = = = = = = new M. module M = type C() = static member P = 1 type C<'T>() = static member P = 1 let let let let let let let let let let _ _ _ _ _ _ _ _ _ _ = = = = = = = = = = new M.C<int>() M. resolves no error. resolves no error.The following example shows the resolution behavior for type lookups that are ambiguous by generic arity: module M = type C<'T>() = static member P = 1 type C<'T.C<'T>.C<int>() M.

by consulting the ExtensionsInScope table.1. or union case called member-ident causes any methods or other entities of that same name from base types to be hidden. the existence of a property.Foo(1) // resolves to method in A b. Try to resolve member-ident to a property group of type. the long-ident may represent a new variable binding in the pattern. If it does not.4 Name Resolution for Members Overview: Name Resolution for Members is a sub-procedure used when resolving . At each type: o o o o o o Try to resolve member-ident to a union case of type.rest] to a member. The long-ident must resolve to a union case. 170 .  Method groups are combined with method groups from base types.Object to the given type. event.5 Name Resolution in Patterns Overview: Name Resolution for Patterns is used when resolving long-ident in the context of pattern expressions. Recursively resolve . by consulting the ExtensionsInScope table. consider this case: let Foo = 1 type Foo() = static member ABC = 2 let x1 = Foo.ABC // evaluates to 2 let x2 = Foo() // evaluates to a new Foo() 14. o Try to resolve member-ident to a method group of extension members of type. Try to resolve member-ident to an event of type. For example type A() = member this. in the context of a particular type type. exception label. o Try to resolve member-ident to a nested type type-nested of type.rest if present.  At any type.Foo(s : string) = 1 let b = new B() b.The rules. otherwise return type-nested.1. Try to resolve member-ident to a property group of extension members of type.Foo(i : int) = 0 type B() = inherit A() member this. Details: The member-ident is resolved as follows:   Search the hierarchy of the type from System.Foo("abc") // resolves to method in B 14. For example.member-ident[. because these type names are added to the ExprItems table. Details: The member-ident is resolved by using the same process as Name Resolution in Expressions except that the PatItems table is consulted instead of the ExprItems table. prefer type names for single identifiers. field. Try to resolve member-ident to a field of type. literal value or active pattern case name. Try to resolve member-ident to a method group of type. however.

The result is a type definition and a possible residue rest. A generic arity matching n is always available.  For each such division. attempt to resolve ident[. given: module M = type C<'T. "abc") the name C on the last line resolves to the named type M. C = %d" C will result in "matched. C = 4".rest]. C = %d" C | _ -> sprintf "no match. A [sub-]module in F.rest] in the following order. Recursively resolve rest against the contents of this module For example. string> = (1. C = %d" C will result in "no match. then:  Consider each division of long-ident into [namespace-or-module-path].1.rest] then look up ident in the Types table.  For each such F. in which the namespace-or-module-path becomes successively longer. If ident is not present in this table. because C is present in the PatItems table. and hence becomes a bound variable.C<_. C = %d" C | _ -> sprintf "no match. with generic arity n. Details: Given ident[. For example: let C = 3 match 4 with | C -> sprintf "matched. 'U> = 'T * 'T * 'U module N = type C<'T> = 'T * 'T open M open N let x : C<int.ident[. because it is a literal._>.6 Name Resolution for Types Overview: Name Resolution for Types is used when resolving long-ident in the context of a syntactic type. If any resolution succeeds. In contrast. 171 . 14. Return this type and residue rest.Note: This means that values do not pollute the namespace used to resolve identifiers in patterns. terminate the search: o o A type in F. 1. because C is not present in the PatItems table. consider each module and namespace declaration group F in the list produced by resolving namespace-or-module-path using Name Resolution in Module and Namespace Paths. and return the result and residue rest. C = 3". [<Literal>] let C = 3 match 4 with | C -> sprintf "matched.

g2 "4" checks correctly: g1 is generalized. Thismapping ensures that multiple uses of the same type variable name map to the same type inference variable.11) in F is added to the ExprItems and PatItems tables in the original order of declaration in F. g1 "3".1. Details: Look up all fields in all available types in the Types table and return the set of field declarations. The type variable 'T on the second line refers to a different type inference variable. o Add the type to the TypeNames table.1. items are added to the name environment as follows:  Each exception label for each exception type definition (§8. (y:'T) the identifiers x and y are assigned the same static type—that is.9 Opening Modules and Namespace Declaration Groups When a module or namespace declaration group F is opened. which is eventually constrained to be type string. If the type definition is a record. o 172 . unless the type has the RequireQualifiedAccess attribute. This is apparent becauseit is applied to both integer and string types. . add any record field labels to the FieldLabels table. fieldN = expr }.8 Field Label Resolution Overview: Field Label Resolution specifies how to resolve identifiers such as field1 in { field1 = expr. If the type has a CLI-mangled generic name such as List`1 then an entry is added under both List and List`1.14..  Each type definition is added in the original order of declaration in F.1. It is initially empty for any member or any other top-level construct that contains expressions and types. add any union cases to the ExprItems and PatItems tables. 14. for let f x y = (x:'T)..7 Name Resolution for Type Variables Whenever syntactic types and expressions are processed. Entries are eliminated from the map after they are generalized. so let f () = let g1 (x:'T) = x let g2 (y:'T) = (y:string) g1 3. the same type inference variable associated with the name 'T. For example. 14. a context is assumed that contains a mapping from identifiers to inference type variables. o If the type is a union. then add the type name to the ExprItems table. The full inferred type of the function is: val f<'T> : 'T -> 'T -> 'T * 'T The mapping is used throughout the processing of expressions and types in a left-to-right order. unless the type has the RequireQualifiedAccess attribute. Adding a type definition involves the following procedure: o If the type is a class or struct type (or an abbreviation of such a type).

AutoOpen attribute are themselves opened.I. then the tags of that active pattern are added to the PatItems table according to the original order of declaration.Core.type application projection 173 . (g) f x decomposes into f and projection x Note: In this specification we write sequences of projections by juxtaposition.H. o o The value is added to the ExprItems table.dot lookup projection -. If any value is an active pattern. for example.j that make use of dot notation are resolved using a set of rules that take into account the many possible shapes and forms of these expressions and the ambiguities that may occur during their resolution. . Each value is added in the original order of declaration in F.long-ident-or-op expr <types> For example: x.longident<types>(expr).rest projs otherwise. then apply Unqualified Lookup on long-ident with projections projs.H. We also write (. giving an elaborated expression expr.y.2 Resolving Application Expressions Application expressions such as x. -. After decomposition:  If expr is a long identifier expression long-ident. 14.I. Then process expr . To check an application expression.  Any sub-modules marked with Microsoft. The projections are each of the following form: .  The member contents of each type extension in Fi are added to the ExtensionsInScope table according to the original order of declaration in Fi.M and projections <int>.Z(g).y.M<int>(g) decomposes into x.j x.Z(g).  If not. check the expression against an arbitrary initial type ty.H.application projection -.Z and projections (g). o If the value is a literal it is added to the PatItems table. resulting in projs if rest is empty and . the expression is first repeatedly decomposed into a leading expression expr and a list of projections projs.I.FSharp.j decomposes into x. ty and projs using Expression-Qualified Lookup.rest + projs) to refer to adding a residue long identifier to the front of a list of projections. This section specifies the exact algorithmic process that is used to resolve these expressions.  Each sub-module or sub-namespace declaration group in Fi is added to the ModulesAndNamespaces table according to the original order of declaration in Fi.Y<int>. (expr).

projs. and recursive resolutions resolve any remaining projections.X and a residue long identifier. If the first projection is <types>. 14. For example.2. it is invoked with an unknown number of type arguments.1 Unqualified Lookup Overview: Given an input long-ident and projections projs.projs. N.Environment.Length. Unqualified Lookup is used to resolve the vast majority of identifier references in F# code.projs in an environment env. Item-Qualified Lookup computes the projection item. Details: The item must be one of:          A named value A union case A group of named types A group of methods A group of indexer getter properties A single non-indexer getter property A static F# field A static CLI field An implicitly resolved symbolic operator name If not. an error occurs. Likewise. The first part of this process resolves a prefix of the information in long-ident. long-ident is first resolved using Name Resolution in Expressions (§14. Details: To compute Unqualified Lookup. to complex accesses such as System.1).GetCommandLineArgs().2. Otherwise. Name Resolution in Expressions is invoked with a known number of type arguments.Y may resolve to a value reference v along with a residue long identifier . Name Resolution in Expressions v.Y may resolve to an overloaded method N. If the first projection in projs is <tyargs>. We then apply Item-Qualified Lookup for item and (rest + projs). For example. This returns a name resolution item item and a residue long identifier rest.Y. Note: Name Resolution in Expressions also takes as input the presence and count of subsequent type arguments in the first projection.14.X.X.2 Item-Qualified Lookup Overview: Given an input item item and projections projs. from simple identifiers such as sin.X(args). This is often a recursive process: the first resolution uses a prefix of the information in item. and recursive resolutions typically use Expression-Qualified Resolution to resolve the remainder. 174 . then we say the resolution has a type application <types> with remaining projections. Unqualified Lookup computes the result of ―looking up‖ long-ident.Y.projs.

then use expr as the expression argument. If projs begins with:  <types> expr.   Otherwise the type scheme is freshly instantiated. This generates a new item.  If the first projection is <types>. checking proceeds as follows:  For a value reference v: o The type scheme of v is instantiated. 175 . then explicit type arguments are required. anything else.  o  Insert implicit flexibility for the use of the value (§14. then use <types> as the type arguments and expr as the expression argument. then the types are processed and the results are used as the arguments when instantiating the type scheme. For indexer properties. where projs begins with <types>.  If the value has type byref<ty2>. the underlying getter indexer methods are used for the method group.   expr. o Let fty be the actual return type resulting from Method Application Resolution. then add a byref dereference to the elaborated expression. If the result of Method Application Resolution is labeled with the RequiresExplicitTypeArguments attribute. generating a type ty. We then apply Name Resolution for Members to ty and long-ident. o  For a group of method references or property indexer references: o Apply Method Application Resolution for the method group. which results in a type ty.4.Once item is generated by name resolution. For type name. Apply Expression-Qualified Lookup for type ty and any remaining projections. Apply Expression-Qualified Lookup to fty and any remaining projections. o  For a group of type names where projs begins with <types> or expr: o The types are processed and the results are used as the arguments to instantiate the named type reference. use no expression argument or type arguments. If the value is labeled with the RequiresExplicitTypeArguments attribute. o Apply Expression-Qualified Lookup to item and any remaining projections. then the first projection must be <types>. o Apply Item-Qualified Lookup to item and any remaining projections. Method Application Resolution accepts an optional set of type arguments and a syntactic expression argument. The object construction ty(expr) is processed as an object constructor call in the same way as new ty(expr).long-ident: o The types are processed and the results are used as the arguments to instantiate the named type reference.2). generating a type ty.

176 . Then recheck this entire expression with additional subsequent projects . then use expr as the expression argument. then resolve to the following expressions. o Apply Expression-Qualified Lookup to fty and projs. A CLI event reference: o o o Check the event for accessibility and attributes. Type instantiations may not be applied to arbitrary expressions. Expression-Qualified Lookup computes the ―lookups or applications‖ for expr. otherwise.  For a union case tag.y. respectively: (fun (x:^a) -> (^a : static member (op) : ^a -> ^b) x) (fun (x:^a) (y:^b) -> ((^a or ^b) : static member (op) : ^a * ^b -> ^c) (x. then apply Function Application Resolution (§14.z)) These are static member constraint invocation expressions (§6.8) and enable the default interpretation of operators using type-directed member resolution. Details: If projs is empty. In this case. If projs begins with   expr.2. use no expression argument or type arguments.  For an implicitly resolved symbolic operator name op: o If op is a unary. Take into account the type ty via which the field was accessed. Let fty be the actual type of the field. binary or the ternary operator ?<-. only to generic types. an exception tag or active pattern result element tag: o o Check the tag for accessibility and attributes. For a static field reference: o o Check the field for accessibility and attributes. original application expression is asserted to be ty and checking is complete. Apply Expression-Qualified Lookup to fty and projs. generic methods and generic values. If the projections start with:   (expr2).y)) (fun (x:^a) (y:^b) (z:^c) -> ((^a or ^b or ^c) : static member (op) : ^a * ^b * ^c -> ^d) (x. 14.projs. the type of the overall. then fail.projs. build a function expression for the union case. Let fty be the actual type of the event. o o  Let fty be the actual type of the union case Apply Expression-Qualified Lookup to fty and remaining projs.3). and projections projs. <types>.4.3 Expression-Qualified Lookup Overview: Given an elaborated expression expr of type ty.

with no type arguments and one () argument. apply Method Application Resolution for the method group. use no expression argument or type arguments. 177 . A single instance CLI field. NeverMutates) operation §6. Name Resolution for Members returns a property reference to the CLI instance property System.F.  If item is a non-indexer getter property. resolve long-ident using Name Resolution for Members (§14. then use arg as the expression argument. Produce an elaborated form for expr. In this case.Length. then use <types> as the type arguments and arg as the expression argument. the underlying getter indexer methods are used for the method group.3. The item must be one of:      A group of methods.1. A group of instance getter property indexers. Let fty be the actual return type resulting from Method Application Resolution.9. This returns a name resolution item item and a residue long identifier rest. non-indexer getter property. A single instance. the projections start with . o o Assert that ty is a subtype of the actual containing type of the field. Apply ExpressionQualified Lookup to fty and any remaining projections. (arg). Method Application Resolution accepts an optional set of type arguments and a syntactic expression argument.long-ident. If F is a field in a value type then take the address of expr by using the AddressOf (expr . If projs begins with: o o o <types>(arg). otherwise. For example. o Apply Expression-Qualified Lookup to fty and projs. o o Check the field for accessibility and attributes Let fty be the actual type of the field (taking into account the type ty by which the field was accessed). Checking then proceeds as follows:  If item is a group of methods or a group of indexer properties. For indexer properties.  If item is an instance IL or F# field F.Otherwise. for ty = string and long-ident = Length .String. If not. an error is reported. A single instance F# field.4). Method Application Resolution is invoked for the method group that contains only the getter method for the property.

3 Function Application Resolution Overview: Given expressions f and expr where f has type ty. 14. and given subsequent projections projs.. Method Application Resolution resolves the overloading based on the partial type information of available. Resolves post-hoc property assignments.14. 178 .  Process projs using Expression-Qualified Lookup against ty1. then use these arguments. Resolves ―out‖ arguments. It also:      Resolves optional and named arguments.map System. argN. Function Application Resolution does the following:    Attempts to assert that f has type ty1 -> ty2 for new inference variables ty1 and ty2. If the first assertion fails. then it is a named actual argument. the method call in List. an optional syntactic argument arg. If arg is a syntactic unit value (). an optional syntactic argument obj. Checks expr with the initial type ty1.4 Method Application Resolution Overview: Given a method group M. For each argument:  If arg is a binary expression of the form name=expr. then determine the sets of unnamed and named actual arguments... optional type arguments <tyargs>. then use a zero-length list of arguments. then it is assumed that a use of a method as a first class value is being resolved. then:  Check the expression as the computation expression form f { computation-expr }. for example. If an argument arg is given.Environment.  Otherwise. Inserts ad hoc conversions that are only applied for method calls. giving result type ty1. Note: If no syntactic argument is given. Applies method overload resolution. "USERNAME"] Details:   Restrict the candidate method group M to those methods that are accessible from the point of resolution. arg is an unnamed actual argument.GetEnvironmentVariable ["PATH".. Processes projs using Expression-Qualified against ty2. and overall initial type ty. UnnamedActualArgs and NamedActualArgs: o Decompose arg into a list of arguments as follows:   o If arg is a syntactic tuple arg1 . and expr has form { computation-expr }.

.  Subsequently:  The method application is considered to have one unnamed actual argument for each prospective unnamed actual argument type. then the decomposition of arg to tuple form is ignored and there is one named actual arg which is arg itself. .M(1. by splitting the formal parameters for M into those that have a matching argument in NamedActualArgs and those that do not..dtyN). ()) has one unnamed actual argument x. attempt to produce zero. o If no argument arg is given:  If the method group contains a single accessible method. This results in the FormalTypeArgs for Mpossible. called ActualArgTypes. If dty is unit.  For each candidate method in M. called NamedFormalArgs and UnnamedFormalArgs respectively. then equate this type with a type ty1 -> … tyn -> rty for fresh types ty1 and ty2. then equate this type with a type byref<ty> for a fresh type ty. o If an argument arg is given.M( printfn "hello".  If the argument has the syntactic form of a function expression fun pat1 … patn -> expr after ignoring parentheses around the argument.M(()) has one unnamed actual argument  Determine the named and unnamed prospective actual argument types.   The method application is considered to have no named actual arguments. * dtyN). . one. then generate fresh type inference variables for its generic parameters. the expected overall type of the expression is asserted to be a function type dty -> rty.  If the argument has the syntactic form of an address-of expression &expr after ignoring parentheses around the argument. then the prospective argument types are given by an empty list. then the prospective argument types are (dty1. then the prospective actual argument types are given by fresh type inference variables for each unnamed and named actual argument. x. (y = 2)) has two unnamed actual arguments x. and M has only one candidate method.o If there are no named actual arguments. which accepts only one non-optional argument.M(1. b)) has one unnamed actual argument x. then the prospective unnamed argument types are one fresh type inference variable for each non-optional.M(1. or two prospective method calls Mpossible as follows: o If the candidate method is generic and has been generalized. If dty is a tuple type (dty1 * . o 179 . Otherwise. y = 2) has one unnamed actual argument and one named actual argument x. 2) has two unnamed actual arguments x. Otherwise the prospective argument types are given by dty alone. Determine the named and unnamed formal parameters. non-out parameter that the method accepts.M((a. o Examples: All named arguments must appear after all unnamed arguments.

then it is the target. contains a settable property name. then remove the suffix and call it ImplicitlySuppliedFormalArgs. #UnnamedActualArgs is less than #UnnamedFormalArgs after the above processing steps. then it is the target. then modify UnnamedFormalArgs as follows:  If all formal parameters in the suffix are ―out‖ arguments with byref type.   #ActualTypeArgs.o If #UnnamedFormalArgs exceeds #UnnamedActualArgs. contains a settable field name. then produce two prospective method calls:    one with an empty ParamArrayActualArgs. then assert Mpossible by performing the following steps: o o o Verify that each ActualTypeArgi is equal to its corresponding FormalTypeArgi Verify that the type of obj is a subtype of the containing type of the method M. o No prospective method call is generated if:   A named argument cannot be associated with a target. 180 .  if #UnnamedActualArgs equals #UnnamedFormalArgs-1.  o If the last element of UnnamedFormalArgs has the ParamArray attribute and type pty[] for some pty. If ParamArrayActualArgs has been produced. before the application of any type arguments tyargs. A target is a named formal parameter. if present. then produce a prospective method call named ParamArrayActualArgs that hasthe excess of UnnamedActualArgs removed. then modify UnnamedActualArgs as follows:  if #UnnamedActualArgs exceeds the number of #UnnamedFormalArgs-1.  If the return type of M. verify that the corresponding ActualArgType coerces to the type of the corresponding argument of M. The candidate method is static and obj is provided. one with no ParamArrayActualArgs. attempt to apply initial types prior to argument checking. o If Mpossible uses ParamArray conversion with type pty then for each ParamArrayActualArgi. If all formal parameters in the suffix are ―optional‖ arguments. If only one prospective method call Mpossible exists. a settable return property or a settable return field as follows:  If an argument exists in NamedFormalArgs with name name. does not precisely equal #FormalTypeArgs for M. or the candidate method is an instance method and obj is not provided. then Mpossible is said to use ParamArray conversion with type pty. then remove the suffix and call it ImplicitlyReturnedFormalArgs.  Next. before the application of any type arguments tyargs. verify that the corresponding ActualArgType coerces to pty.  If the return type of M. o Associate each name=arg in NamedActualArgs with a target. For each UnnamedActualArgi and UnnamedFormalArgi. then that argument is the target.

prefer any candidate that has the more specific actual argument types. * tyN. prefer candidates that do not have ImplicitlyReturnedFormalArgs.    Otherwise. In any case. then the formal return type is defined as follows:  If the prospective method call contains ImplicitlyReturnedFormalArgs with type ty1. the overall constraint set is left unchanged as a result of determining the applicability of each Mpossible.  then prefer the second. If an inconsistent constraint set is detected (§14... tyN. if the method is overloaded where multiple overloads accept the same number of arguments. Otherwise. Otherwise.. then the formal return type is rty * ty1 * . prefer candidates that do not have ImplicitlySuppliedFormalArgs.. or ty2i is a System. If the method M has return type rty. Otherwise.. o If a unique applicable Mpossible exists. * tyN.. . If arg is present: o Check and elaborate each unnamed actual argument expression argi. that is.Func type and ty1i is some other delegate type. ty2n where each ty1i either   feasibly subsumes ty2i. Note: The effect of the application of uniquely applicable methods is to propagate information from the expected argument types to the checking of the actual arguments. This is done by attempting to assert Mpossible (see a previous bullet). then prefer the second. o Verify that the prospective formal return type coerces to the expected actual return type. If rty is unit then the formal return type is ty1 * . and pty1 feasibly subsumes pty2..  Otherwise the formal return type is rty... If two candidates both use ParamArray conversion with types pty1 and pty2.o For each of NamedActualArgi that has an associated formal parameter target. choose the unique best Mpossible according to the following rules:  Prefer candidates whose use does not constrain the use of a user-introduced generic type annotation to be equal to another type. 181 .  Check and elaborate argument expressions.Func type to be more specific than any other delegate type. This type information will not be propagated if more than one applicable method exists—that is. verify that the corresponding ActualArgType coerces to the type of the corresponding argument of M. determine whether the method is applicable. prefer candidates that do not use ParamArray conversion. using an initial type given by the corresponding type in ActualArgTypes. then choose that method. use the candidate that has the more precise type.. o Check and elaborate each named actual argument expression argi. using an initial type given by the corresponding type in ActualArgTypes. Otherwise.  Choose a unique Mpossible by the following rules: o For each Mpossible. verify that the corresponding ActualArgType coerces to the type of the property or field..5) by any step of this process. if two candidates have unnamed actual argument types ty11 . ty1n and ty21 . o For each of NamedActualArgi that has an associated property or field setter target. That is. the method is not applicable. and consider any System.

. Two additional rules are applied when checking arguments (see §8. Once a unique best Mpossible is chosen. o For each NamedActualArgs whose target is a settable property or field.. then interpret the parameter in the same way as new D(fun arg1 . prefer candidates that are non-generic over candidates that are generic— that is.9. > tyn -> rty. Otherwise. passing them as byref parameters. those that have empty ActualArgTypes. For more information on the conversions that are automatically applied to arguments. an F# reference cell can be passed where a byref<ty> is expected. This means building an elaborated expression through the following steps: o If the type of obj is a variable type or a value type. o If arg is not present. and building a tuple from these mutable temporaries and any method return value as the overall result. o Build the argument list by:  Passing each argument corresponding to an UnamedFormalArgs where the argument is an optional argument as a Some value.3). argn -> farg arg1 . Otherwise.  Passing a None value for each argument that corresponds to an ImplicitlySuppliedFormalArgs.... argn). commit that method. In other words. prefer the one arising from the most recent use of open.   o    If there is no unique better method. prefer candidates that are not extension members over candidates that are.  o Applying coercion to arguments. and an actual argument farg has known type ty1 -> . between two extension members.6. Bind ImplicitlyReturnedFormalArgs arguments by introducing mutable temporaries for each argument. PossiblyMutates) operation (§6.13.6 for examples):  If a formal parameter is of delegate type D. then take the address of obj by using the AddressOf(obj. and an actual argument type is not a byref type. then an error is reported. Build the resulting elaborated expression.  If a formal parameter is an ―out‖ parameter of type byref<ty>.. assign the value into the property. return a function expression that represents a first class function value. and the number of arguments of the Invoke method of delegate type D is precisely n. 182 . Apply attribute checks. then interpret the actual parameter in the same way as type ref<ty>.13. see §8. Otherwise.

.. then the compiler eliminates application expressions that resolve to calls to members that have the Conditional attribute and ensures that arguments are not evaluated. then it is assumed that the method has one argument. the type is replaced by a fresh type variable ty'ij with a coercion constraint ty'ij :> tyij. flexibility is implicitly added to the expression.Next. and is not a variable type. * ty'mn -> rty but otherwise is semantically equivalent to the first expression. * ty1n -> .  The expression elaborates to an expression of type ty'11 * .. The return type may be checked either on use of the method or definition of the method... named value..Random.2 Implicit Insertion of Flexibility for Uses of Values and Members At each point where a data constructor.Conditional attribute on a method application as follows:   The Conditional("symbol") attribute may be applied to methods only.Diagnostics.  If symbol is not in the current set of conditional compilation symbols. The elimination proceeds as follows: o o  Static members: Type. This is because if the initial type contains no information about the expected number of arguments..M(args)  (fun args -> ()) Instance members: expr. This flexibility is associated with the use of the value or member.M(args)  () Instance members: expr. according to the inferred type of the expression.. -> ty'm1 * ..Note: One effect of the above rules is that a method that is used as a first class function value can resolve even if a method is overloaded and no further information is available.M(args)  () First class uses are eliminated as follows: o o Static members: Type.. gives val roll : int -> int despite the fact that in the standard CLI library. For example: let r = new Random() let roll = r. Methods that have the Conditional attribute must have return type unit.4.4. * tymn -> rty  If the type is not of this form no flexibility is added.1 Conditional Compilation of Member Calls F# respects the presence of the System.. The flexibility added is as follows:  The type of the value or member is decomposed to be of the form: ty11 * .  For each parameter position where tyij is an unsealed type..Next is overloaded. -> tym1 * .M  let _ = expr in (fun args -> ()) 14.. 14. or member is used and forms an expression. * ty'1n -> . System. The positions tyij are called the ―parameter positions‖ for the type. 183 .

It is invoked every time a constraint is added to the set of current inference constraints at any point during checking. M(obj. given the following: let M<'b>(c :'b. M<obj>(str.This means that F# functions whose inferred type includes an unsealed type in argument position may be passed subtypes when called.X // Call f: Base -> int with an instance of type Derived let res = f d // Use f as a first-class function value of type : Derived -> int let res2 = (f : Derived -> int) The insertion of additional flexibility is determined after an explicit instantiation is taken into account. but before any arguments are checked.Y = i let d = new Derived(7) let f (b : Base) = b. Details: Given a type inference context. or type) : (member-sig) typar : (new : unit -> 'T) typar : struct typar : unmanaged 184 . For example. obj) M(str. d :'b) = 1 let obj = new obj() let str = "" these pass type-checking: M<obj>(obj. without the need for explicit upcasts.. the normalized form of constraints is a list of the following primitive constraints where typar is a type inference variable:       typar :> type typar : null (type or . M<obj>(str. str) str) obj) obj) str) These do not. str) M(str.X = 1 type Derived(i : int) = inherit Base() member d.5 Constraint Solving Overview: Constraint solving is the process of processing (―solving‖) non-primitive constraints down to primitive constraints on type variables. because the target type is a variable type: M(obj. For example: type Base() = member b. M<obj>(obj.. obj) 14.

New constraints of the form type<tyarg11... tyarg1n> :> type<tyarg21... where type2 is a sealed type.. are reduced to an equational constraint on two instantiations of type2 according to the subtype relation between type1 and type2.... tyarg2n> or type<tyarg11....     typar : comparison typar : equality typar : not struct typar : enum<type> typar : delegate<type.5. type> Each newly introduced constraint is solved as indicated in the following sections. F# treats these types as invariant for the purpose of constraint solving. tyarg2n> are reduced to the constraints tyarg11 = tyarg21 . and solved again. tyarg1n> = type<tyarg21..2 Solving Subtype Constraints Primitive constraints of the form typar :> obj are discarded.... tyarg2n> where type1 and type2 are hierarchically related.1 Solving Equational Constraints New constraints typar = type or type = typar where typar is a type inference variable cause typar to be eliminated from the constraint problem and replaced by type. 14.. tyarg1n> = type<tyarg21. New constraints of the form type<tyarg11... Likewise... although single-dimensional array types in the CLI are effectively covariant.. New constraints type1 :> type2.. New constraints of the form type1<tyarg11. Note: F# generic types do not support covariance or contravariance. tyarg2n> are reduced to a series of constraints tyarg1i = tyarg2i on identical named types and solved again. Other constraints associated with typar are then no longer primitive and are solved again...... are reduced to the constraint type1 = type2 and solved again. 14. and any CLI variance type annotations on generic interface types and generic delegate types are ignored.... tyarg1n = tyarg2n and solved again... That is. tyarg1n> :> type2<tyarg21.. F# considers CLI delegate types as invariant.5.. 185 .

Collections.Generic. Consequently. System.0 function with a signature such as T Choose<'T>(T x. support multiple instantiations of the same interface type. 14. if MySubClass<'T> is derived from MyBaseClass<list<'T>>.ICollection<'T> and System. where I<'T> is the first interface type that occurs in the tree of supported interface types. a C# 2. Multidimensional array types ty[] are also subtypes of System.IList<'T>. Note: Subtype constraints on single-dimensional array types ty[] :> ty are reduced to residual constraints. Note: These constraints typically occur only in calls to generic code from other CLI languages where a method accepts a parameter of a “naked” variable type—for example.Array. Types from other CLI languages may. CLI variance type annotations on interfaces are ignored. I<string>.Collections. then the constraint MySubClass<'T> :> MyBaseClass<int> is reduced to the constraint MyBaseClass<list<'T>> :> MyBaseClass<list<int>> and solved again. in theory.4.For example. §5. so that the constraint 'T = int will eventually be derived. based on the fact that these types are considered to be subtypes of System. System.5. are reduced to further constraints and resolved according to the requirements for each kind of constraint listed in §5. Such a constraint is reduced to a constraint C :> I<'T>.8. such as C : I<int>. New constraints of the form type :> 'b are solved again as type = 'b. 186 . This is rarely used in practice in F# coding. it is more difficult to solve a constraint such as C :> I<'T>.2.IEnumerable<'T>.Generic. and iterated left-to-right in the order of the declarations in the CLI metadata. T y).Generic. Struct and Other Simple Constraints New constraints of the forms        type : null type : (new : unit -> 'T) type : struct type : not struct type : enum<type> type : delegate<type.Array.3 Solving Nullness.Collections. when the tree is ordered from most derived to least derived. type> type : unmanaged where type is not a variable type. and elsewhere.

sbyte.3. given the following groups of types:  the integral types byte.. A member constraint is satisfied if one of the types in the support set type1 . Cosh. op_Increment.2.   The presence or absence of static matches that of the constraint.4 Solving Member Constraints New constraints of the form (type1 or . op_Multiply. op_Division. a type variable may not be involved in the support set of more than one member constraint that has the same name. or typen) : (member-sig) are solved as member constraints §5.   The floating-point and signed integral types are assumed to define the static member Abs. op_BitwiseOr.5.. int64. The floating-point types are assumed to define static members Sin.. In particular. Log10. uint16.1 Simulation of Solutions for Member Constraints Certain types are assumed to implicitly define static members even though the actual CLI metadata for types does not define these operators. float32. op_UnaryNegation.. A static type type satisfies a member constraint (staticopt member ident : arg-type1 * .. Acos. uint64. Cos. 14. uint64. op_Modulus and op_UnaryPlus. unativeint. op_ExclusiveOr.  The floating-point and integral types are assumed to define static members op_Explicit that take the type as an argument and return nativeint.   the signed integral CLI types sbyte. Tanh. op_Subtraction. The floating-point and signed integral and decimal types are assumed to define the static member Sign. Ceiling.   The signed integral types are assumed to define the static member op_UnaryNegation.  The floating-point and signed integral types are assumed to define the static member op_UnaryNegation. and support set–if it is. float and decimal. The assertion of type inference constraints between the arguments and return types does not lead to a type inference error. * formal-arg-typen -> ret-type) of the given name. int16. int64 and nativeint. Atan. the floating-point CLI types float32 and float. op_RightShift. The members assumed are:  The integral types are assumed to define static members op_BitwiseAnd. int16. op_LeftShift.... The floating-point and integral types and the string type string are assumed to define static members op_Explicit that take the type as an argument and return byte. As mentioned in §5. op_LogicalNot and op_OnesComplement. Sqrt.2. Sinh. which takes n arguments.3. Floor. Asin. int32. sbyte. op_UnaryPlus.4. * arg-typen -> ret-type) if:  type is a named type whose type definition contains a member ([static] member ident : formalarg-type1 * . argument arity.14. staticness. Tan. uint32. op_Decrement. int64. Exp. uint16. Atan2.  The floating-point and integral types are assumed to define static members op_Addition.5. uint32. the argument and return types are themselves constrained to be equal. and Pow. Round. int32.  187 . int16. nativeint and unativeint. typen satisfies the member constraint. int32. Log.

which defines one or more values by matching a pattern against an expression: mutableopt pat :opt typeopt = rhs-expr or a member definition staticopt member identopt ident pat1 . as the grammar shows: | ident pat = expr | pat = expr -. float. 14. generalized and elaborated. int. (+). Each binding is either a function definition: inlineopt ident1 pat1 .6. System.. In addition. resolutions that do not give such a warning are preferred over ones that do give such a warning. For example: type foo = Id of int let Id x = x 188 .5 Over-constrained User Type Annotations An implementation of F# must give a warning if a type inference variable that arises from a user type annotation is constrained to be a type other than another type inference variable.. the following results in a warning because 'T has been constrained to be precisely string: let f (x:'T) = (x:string) During the resolution of overloaded methods. For example. This is deliberate: in the CLI. 14.Note: The decimal type is included only for the Sign static member. This mechanism is used to implement the extensible conversion and math functions of the F# library including sin. patn :opt return-typeopt = rhs-expr or a value definition..function binding -.1 Ambiguities in Bindings An ambiguity exists between the two different kinds of ―let‖ bindings. patn = expr 14.value binding This ambiguity is always resolved as a function binding.6 Checking and Elaborating Bindings This section describes how let. and member bindings are checked.Decimal includes the definition of static members such as op_Addition and the F# compiler does not need to simulate the existence of these methods. ―Let‖ bindings occur in the following contexts:     Module declarations Class type declarations Expressions Computation expressions Recursive ―let rec‖ bindings can also occur in each of these locations. let rec. In particular:ident pat = expr This can be interpreted as either a function or value binding. and (-).. member bindings in a mutually recursive group of type declarations are treated as a group of recursive ―let rec‖ bindings when they are being checked and elaborated.5. cos.

Value definitions may not be inline. If pat is a single value pattern. where tmp is a fresh identifier and each expri arises from the compilation of the pattern pat (§7) against input tmp.In this case.. use the following syntax‖ let v = if 3 = 4 then Id "yes" else Id "no" let (Id answer) = v 14. identm.6. the ambiguity is whether Id x is a pattern that matches values of type foo or is the last line in the function definition of a function called Id.  Otherwise. Each identi (of type tyi) is then generalized (§14.6.v + 1 printfn "v = %d" v These variables are under the same restrictions as values of type byref<_> (§14. In F# this ambiguity is always resolved as a function definition.3 Processing Value Definitions A value definition pat = rhs-expr with optional pattern type type is processed as follows:  The pattern pat is checked against a fresh initial type ty (or type if such a type is present). This check results in zero or more identifiers ident1 . 14. the resulting elaborated bindings are the following. giving an elaborated form expr... and are similarly implicitly dereferenced. To ensure that this is resolved a pattern.2 Mutable Bindings ―Let‖ bindings may be marked as mutable.9). For example: let mutable v = 0 while v < 10 do v <. each of type ty1 . In addition: o o  All identj must be distinct. the resulting elaborated bindings are:   ident <typars1> = expr body-expr.6. tym.     tmp <typars1… typarsn> = expr ident1 <typars1> = expr1 … identn <typarsn> = exprn 189 .8) and yields generic parameters <typarsj>.    The expression rhs-expr is checked against initial type ty..

a static let-binding or the static member). o  The patterns of functions may not include optional arguments (§8. the defined values are available for use within their own definitions—that is. all previous let-bindings for the type added. then an environment is used with: o o  the instance variable added. bindings are generalized incrementally.6. if one is present. multiple bindings may be defined by using let rec … and …: let rec twoForward count = printfn "at %d. Mutable function values should be written let mutable f = (fun args -> . whether static or instance. This may result in warnings. In addition: o Function definitions may not be mutable. 14. The resulting elaborated binding is  ident1 <typars1> = expr1 14. after each binding in the group is checked (§14. patn : return-type -> rhs-expr) is checked against a fresh initial type ty1 and reduced to an elaborated form expr1. the recursive expressions are analyzed for safety (§14.2. In this case. as with a ―let‖ binding or an instance member. each binding has at least one argument pattern.14.6. Groups of members in a recursive set of type definitions are also implicitly recursive. taking two steps forward" count if count = 1000 then "got there!" else oneBack (count + 2) and oneBack count = printfn "at %d. patn = rhs-expr is processed as follows:  If ident1 is an active pattern identifier then active pattern result tags are added to the environment (§10.5).6.. within all the expressions on the right-hand side of the bindings in bindings. For example. The return type is omitted if the definition does not specify it.6.   The ident1 (of type ty1) is then generalized (§14.  The expression (fun pat1 .6.8). and runtime checks...4). that is.4 Processing Function Definitions A function definition ident1 pat1 . including some reported as compile-time errors. When one or more bindings specifies a value.. then an environment is used with o all previous static let-bindings for the type added.7).5 Processing Member Definitions A member definition is processed as follows:  If the binding is per-instance.13.. 190 .6. taking one step back " count twoForward (count – 1) Each binding in a recursive group normally specifies a member or function.). If the binding is static (that is.8) and yields generic parameters <typars1>. Within recursive groups.6 Processing Recursive Groups of Bindings A group of bindings may be recursive through the use of let rec..

0) -> r). or data construction expression whose field initialization expressions are each safe. A right-hand side expression is safe if it is:   Any function expression.6. If a binding is given a full signature. consider the following declaration: let rec countDown count x = if count > 0 then let a = countDown (count . including interfaces whose member bodies include references to variables being defined recursively. where runtime checks are inserted to locally enforce initialization. A value that is not being recursively bound.Within recursive groups. 191 . for example: type Reactor = React of (int -> React) * int let rec zero = React((fun c let const n = let rec r = React((fun c r -> zero). as described later in this section.1) 1 let b = countDown (count – 1) "Hello" a + b else 1 // constrains "x" to be of type int // constrains "x" to be of type string This declaration is not valid because the recursive uses of f have resulted in inconsistent constraints on x. n) This raises the possibility of invalid recursive cycles that are exercised by strict evaluation. any use of an ungeneralized recursive binding results in immediate constraints on the recursively bound construct. As a field initializer for an immutable field of a record type that is defined in the current assembly.     A lazy delayed expression.8). A value that is being recursively bound and appears in one of the following positions: o o As a field initializer for a field of a record type where the field is marked mutable.6. For example. list. A record. the record fields must be initialized in the same order as their declared type. Any object expression that implements an interface.7 Recursive Safety Analysis A set of recursive bindings may include non-function values. In the case of record fields that contain recursive references to values being bound. For example: module M = let rec f<'T> (x:'T) : 'T = let a = f 1 let b = f "Hello" x 14. then early generalization applies and recursive calls at different types are permitted (§14. such as let rec x = x + 1 Recursive Safety Analysis describes the process that partially checks the safety of these bindings and convert thems to a form that is established by lazy initialization. including ones whose bodies include references to variables that are defined recursively. tuple.

. This check is necessarily approximate because dependencies under function expressions are assumed to be delayed.) constructor might evaluate the callback as part of the construction process. If the original binding is u = expr then a fresh variable (say v) is generated with a delayed binding: v = lazy expr and occurrences of the variables on the right-hand side are replaced by Lazy. mutual references must be hidden inside function expressions.CtrlH) A compiler warning is given for this code because. Delayed computations are covered earlier in this specification. Recursive bindings that involve computation to evaluate the right-hand sides of the bindings are executed as an initialization graph of delayed computations. and services that respond to various inputs. let rec A = B and B = A + 1 + 1 Here. However. a simple approximate static analysis is performed to determine whether immediate cyclic dependencies are certain to occur during the evaluation of a set of recursive bindings. the new MenuItem(. method calls. Shortcut.Windows. Recursive bindings that involve computation are useful when defining objects such as forms. Other right-hand side expressions are elaborated by adding a new delayed computation binding. and in this case the use of a lazy initialization means that runtime checks and forces are inserted. For example. which prints out part of its state when invoked: open System. The following binding for the original variable is added after the let rec:. If runtime self-reference does occur then an exception will be raised. The graph of definite references is determined and an error is reported if such a dependency cycle exists. In addition. this check catches the naive and direct immediate recursion dependencies.Forms library is well-designed. object expressions.force v. In particular the expressions on the right-hand side of a let rec can be applications. that is.Text). a compile-time error is reported. GUI elements that store and retrieve the state of the GUI elements as part of their specification have this behavior. because the System. this does not happen in practice.Windows. u = expr. A simple example is the following menu item. Some recursive references may be checked at runtime because the computations that are involved in evaluating the bindings might actually execute the delayed computations. Any expression that refers only to earlier variables defined by the sequence of recursive bindings.Form let rec menuItem : MenuItem = new MenuItem("&Say Hello". controls.. and other computations. 192 . All references within function expressions. However. hence making the analysis an under-approximation. Explanatory text: F# permits the recursive bindings of non-function values. object expressions and lazy computations. delegate creations. The F# compiler gives a warning for “let rec” bindings that might involve a runtime check. new EventHandler(fun sender e -> printfn "Text = %s" menuItem. constructor invocations. As a result. or delayed expressions are assumed to be indefinite.Force() Bindings are then established by executing the right-hand sides in order. in theory.

member. Such bindings indicate a programmer error. These bindings are rare. and let rec bindings. particularly because bindings are generalizable only when the right-hand-side is either a function or is very simple. if the order of the fields x and y is swapped. the immediate dependency analysis is performed and an error is reported.Note: In F# 2. parent = Some parent. plus a set of bindings that have not yet been checked in the recursive group with prospective types tys. and an environment env. children = children } and children = [{ x = 1. because executing such generic. type annotations can be added to existing non-function recursive bindings.6. thereby making the construct reusable with multiple different types. children = [] }] printf "%A" parent Here. but is instead represented as a generic method. with the exceptions listed later in this section. Details: Generalization takes a set of ungeneralized. Generalization is applied by default at all let. parent = None. except in pathological examples. these bindings are generic because each right-hand-side is generalizable: let rec A = B and B = A In compiled code they are represented as a pair of generic methods.0 means that record fields in recursive data expressions must be initialized in the order they are declared. immediately recursive bindings results in an infinite loop or an exception. For example. A binding can be generalized if its inferred type is closed with respect to any inference variables that are present in the types of bindings that are in the recursive group and that are not yet checked or which. y = 0. Note: A limitation specific to F# 2.8 Generalization Overview: Generalization is the process of giving constructs generic types if possible. Generalization is applied incrementally to bindings in a recursive group after each binding is checked. a type-checking error occurs. For example: type Foo = { x: int y: int parent: Foo option children: Foo list } let rec parent = { x = 0. Generalization is also applied to member bindings that implement generic virtual methods in object expressions. and performs the following steps:  Chooses a set of bindings that can be generalized. much as if the code had been written as follows: let rec A<'T>() = B<'T>() and B<'T>() = A<'T>() As a result the bindings are not executed immediately (unless called). For example: let rec A : int = B and B : int = A After adding these annotations. This is because a generic non-function binding is not executed immediately.0 this check does not apply to bindings that are generic. Where this issue is a concern. in 193 . such as a single value. y = 1. checked bindings. 14.

generalizable expressions represent a subset of expressions that can be freely copied and instantiated at multiple types without affecting the typical semantics of an F# program. o Ungeneralizable type inference variables are:  Any type inference variable ^typar that is part of the inferred or declared type of a binding. that is: (1) Start with all variables that are candidates for generalization. all of whose elements are generalizable A record expression. The variable is explicitly declared as a generic parameter on an item. or in any inferred type of any module in the ModulesAndNamespaces table in env. Informally.turn. (3) Remove these from the set. where the record contains no mutable fields A union case expression. This is an iterative (greatest fixed point) computation where bindings are repeatedly removed from the set of ungeneralized. Note: Generalizable type variables can be computed by a greatest-fixed-point computation. checked bindings until a stable set of generalizable bindings remains. (2) Determine a set of variables U that may not be generalized because they are free in the environment or present in ungeneralizable bindings. An expression is generalizable if it is any of the following:     A function expression An object expression implementing an interface A delegate expression A ―let‖ binding expression in which both the right-hand side of the binding and the body itself are generalizable A ―let rec‖ binding expression in which both the right-hand sides of all the bindings and the body of the expression are generalizable A tuple expression.  Generalizes all type inference variables that are not otherwise ungeneralizable and for which any of the following is true: o o The variable is present in the inferred types of the values. all of whose arguments are generalizable     194 . The variable is a type parameter copied from the enclosing type definition (for members and ―let‖ bindings in classes).  Any type inference variable that appears in a constraint that itself refers to an ungeneralizable type variable. functions and members. (5) Repeat steps (2) through (4). cannot be generalized. all of whose elements are generalizable. as described later in this section. (4) Add to U any inference variables with a constraint involving one of the variables from U.  Any type inference variable in an inferred type in the ExprItems or PatItems tables of env. unless that binding is marked inline.  Any type inference variable that is part of the inferred or declared type of a binding in which the elaborated right-hand side of the binding is not a generalizable expression.

this will result in a function of the following type.. However. o o  Does not occur in any other tyij. For example.. 195 .    An exception expression. consider this function: let f<'T> (x : 'T) y = x During type inference. either remove the explicit generic parameters (if they can be inferred).'U> (x:'T) (y:'U) = x 14..9 Condensation of Generalized Types After a binding is generalized. one additional nullness constraint is permitted if ty satisfies the nullness constraint. In particular. * tymn -> rty   The positions tyij are called the ―parameter positions‖ for the type. Explicit type parameter definitions on value and member definitions can affect the process of type inference and generalization.. or use the required number of parameters: let throw<'T. Occurs as exactly one tyij parameter position.4.. * ty1n -> . Does not occur in the constraints of any condensed typar. Has a single coercion constraint 'a :> ty and no other constraints. all of whose arguments are generalizable An empty array expression A constant expression An application of a type function labeled with the GeneralizableValue attribute. (The removed flexibility is implicitly reintroduced at each use of the binding. its type is ―condensed‖ by removing generic type parameters that give subtype constraints to argument positions. f<'T> : 'T -> '_b -> '_b To permit generalization at these bindings. and then progressively removes type parameters until a minimal set remain that satisfy the above rules.2)). where '_b is a type inference variable that is yet to be resolved.6.see (§14. a declaration that includes explicit generic parameters will not be generalized beyond those generic parameters. A type parameter 'a is condensed if it: o o o Is not an explicit type parameter.. nor in rty. -> tym1 * .  The type of the value or member is decomposed to be of the form ty11 * . This is a greatest-fixed-point computation that initially assumes all generalized type parameters are condensed. All condensed type parameters are removed and replaced with their subtype constraint ty.

For example. let ignore x = () with type ignore: 'a -> unit In particular.map id >> Seq. 196 .IComparable -> int Specifically: F : 'a -> int when 'a :> System. because it is not defined by using a generalizable expression (computed functions such as Seq. generalized type for F is condensed to F : System.IComparable -> R Note: Condensation is not applied to arguments of unconstrained variable type. for F 3 The value 3 is now boxed at uses of the function. This is akin to the error given by the following: let test1 = let ff = Seq. ff [| 1 |]) // error here Here ff is not generalized. consider let test1 = let ff = Seq. ff ["one"]) // error here Again.CompareTo(x) After generalization. for example. condensation affects the points at which value types are boxed.For example: let F x = (x :> System. If a binding is not generalized. the value is inferred to have type F : #System.length (ff [1]. then condensation is not applied. the actual inferred.map id >> Seq.map id >> Seq. ff is not generalized.IComparable In this case. and its use with arguments of type int list and string list is not permitted.length are not generalizable).IComparable). This means that its inferred type.length (ff [1]. is F : '_a -> int when '_a :> seq<'_b> where the type variables are not generalized and are unsolved inference variables. after processing the binding. For example. this is not condensed to ignore: obj -> unit In rare cases. The application of ff to [1] equates 'a with int list. making the type of F F : int list -> int The application of ff to an array type then gives an error.

because the interface IA is included in both IB and IC.argN).M(arg1.. For example. given: type IA = interface abstract P : int end type IB = interface inherit IA end type ID = interface inherit IB end Then the following object expression is legal. 197 .argN) in type tyi. let x = { new ID interface IB with member x. After dispatch slots are assigned to types.. Each dispatch slot is placed under the most-specific tyi relevant to that dispatch slot. tyn .. Details: The types ty0 ..argN)..ToString(_:unit) = . member obj. and hence the implementation mapping for P must be listed under IB.7 Dispatch Slot Inference Overview: Dispatch Slot Inference is applied to object expressions and type definitions before the processing of members. an error is given.M(arg1..atyN -> rty with name M.. even though the argument type is unit: member obj...M(arg1.P = 2 interface IC with member x. each of which has a set of required dispatch slots SlotsR of the form abstract M : aty1.. In both cases the input is a type ty0 that is being implemented. If there is no most-specific type for a dispatch slot. a set of members override x.... and for each tyi a further set of members override x. tyn together imply a collection of required types R.. o Argument counts are determined by analyzing the syntax of patterns andlooking specifically for tuple and unit patterns. So the following members have argument count 1. Dispatch slot inference associates members with a unique abstract member or interface member that is defined by or inherited by the collected types tyi. a set of additional interface types ty1 . the implementation of IB is the most-specific implemented type encompassing IA. and hence the implementation mapping for P would be ambiguous... This is called dispatch slot inference.  For each binding member x.P = 2 } The ambiguity can be resolved by explicitly implementing interface IA.. and most-specific implementing type tyi.atyN -> atyrty.14. attempt to find a single dispatch slot abstract M : aty1. let x = { new ID interface IB with member x..ToString(() | ()) = . an attempt is made to associate each member with a dispatch slot based on name and number of arguments. argument count N. member obj..ToString(():unit) = ..P = 2 } But given: type type type type IA IB IC ID = = = = interface interface interface interface abstract P inherit IA inherit IB inherit IB : int end end end inherit IC end then the following object expression gives an error.

. The signature or body of let-bound functions in expressions. The construction of the dispatch map for any particular type is as follows:  Where the type definition or extension gives an implementation of an interface. Byref values may not be used in: o o o o The argument types or body of function expressions (fun … -> …). the implementation relation is checked for the types being implemented. then a mapping is added for the associated abstract member slot.8 Dispatch Slot Checking Overview: Dispatch Slot Checking is applied to object expressions and type definitions to check consistency properties.Collections. which is ignored when determining argument counts: member obj. Details: To ensure the safety of byref arguments.ToString() : string = . tuple values are used for multiple return values. byref values can result when calling or overriding CLI methods that have signatures involving byref values. such as ensuring that all abstract members are implemented. given let obj1 = { new System.. However. and are hence both inferred to be int. A one-to-one mapping must exist between dispatch slots and implementing members based on exact signature matching. the following checks are made:   Byref types may not be used as generic arguments. Each object expression and type definition results in an elaborated dispatch map that is keyed by dispatch slot. The member implementations of object expressions.o Members may have a return type.Generic. then mappings are added for each member of the interface. The interface methods and abstract method slots of a type are collectively known as dispatch slots. Byref pointers are not often used in F#. Where the type definition or extension gives a default or override member. The signature or body of let-bound functions in classes.m(). Dispatch slots are qualified by the declaring type of the slot.Compare(a.9 Byref Safety Analysis Overview: ―Byref‖ arguments are pointers that are possibly stack-bound and are used to pass values by reference to procedures in CLI languages. 198 .m() and I2. For example. 14. Details: After all bodies of all methods are checked.  14.b) = compare (a % 7) (b % 7) } the types of a and b are inferred by looking at the signature of the implemented dispatch slot. so a type may supply different implementations for I.IComparer<int> with member x. often to simulate multiple return values. more typically.

members within types and ―let‖ bindings within modules are inferred to have an arity.1] 199 .. When faced with these restrictions. The elaborated form of partial applications of module-bound functions and members. the following has an arity of [1]: let f = fun x -> x + 1 and let f x = fun y -> x + y has an arity of [1. The elaborated form of computation expressions..... Arities are inferred as follows. For example: let f x (y. As a result.An]. 2]. a byref-typed expression can occur only in these situations:   As an argument to a call to a module-defined function.10   Arity Inference During checking. class-defined function.z) = x + y + z is given arity [1.. An arity is: The number of iterated (curried) arguments n.An]. A function definition of the form let ident pat1 .. that is. On the right-hand-side of let-binding for a byref-typed local. These restrictions also apply to uses of the prefix && operator for generating native pointer values. and copied back after the closure has been executed. A tuple length of zero indicates that the corresponding argument is of type unit. In addition:    No generic type may be instantiated by a byref type.Note that function expressions occur in: o o o The elaborated form of sequence expressions.. No static field or module-bound value may have a byref type. 14. and A tuple length for each of these argument types for the inferred type [A1. patn = . byref arguments can be dereferenced first.... stored in a local value (which can be used by inner closures). No object field may have a byref type. is given arity [A1. Note: Arities are also inferred from function expressions that appear on the immediate right of a “let” binding. where each Ai is derived from the tuple length for the final inferred types of the patterns..

a3: string) = () // compiles as a static method taking 3 arguments let test2 (aTuple : int * float * string) = () // compiles as a static method taking 3 arguments let test3 ( (aTuple : int * float * string) ) = () // compiles as a static method taking 3 arguments let test4 ( (a1: int.. For example.. a3: string) ) = () // compiles as a static method taking 1 tupled argument static member Test5 (a1. a2.. mentioned below.An -> rty will be elaborated to a CLI static method definition with signature rty F(ty1.. a2: float..A1 > . a2..A1. * ty1. * tyn. int z)....Arity inference is applied partly to help define the elaborated form of function definitions.1 * . Arity inference on function definitions is fully type-directed.. a function let AddThemUp x (y... a3 : int * float * string) = () type Bar() = // compiles as a static method taking 3 arguments static member Test1 (a1: int.An)...1 * . ty1.. tyn. -> tyn.1 * ... . * ty1. z) = x + y + z in a module will be compiled as a CLI static method with C# signature int AddThemUp(int x.  F# instance (respectively static) methods that have arity [A1.. -> tyn. . tyn.1..An -> rty will be elaborated to a CLI instance (respectively static) method definition with signature rty F(ty1.1 * . a3 : int * float * string) = () 200 . ty1..A1).. a2: float..1. which is the form that other CLI languages see...An] and type ty1. a2: float... subject to the syntactic restrictions arising from the patterns defining the member. Arity inference applies differently to function and member definitions. . a3: string) = () // compiles as a static method taking 1 tupled argument static member Test2 (aTuple : int * float * string) = () // compiles as a static method taking 1 tupled argument static member Test3 ( (aTuple : int * float * string) ) = () // compiles as a static method taking 1 tupled argument static member Test4 ( (a1: int.. a2: float. . In particular:  A function value F in a module that has arity [A1.. For example: module Foo = // compiles as a static method taking 3 arguments let test1 (a1: int.1...An] and type ty1..A1 -> . a3: string) ) = () // compiles as a static method taking 3 arguments let test5 (a1. int y.. * tyn. while arity inference on members is limited when parentheses or other patterns are used to specify the member arguments.

value) requiring C : comparison.Array.IndexOf requiring C : equality System. For each use of the following constructs. for any overload that does not take an IEqualityComparer<_> 201 .B>() requiring C : comparison. for any overload that does not take an IEqualityComparer<T> No constraints are added for the following operations.Equals(yobj) requires type ty : equality for the static type of x x.B>() requiring A : comparison. because they are common in F# programming and cause extremely difficult-to-find bugs. You should consider writing wrappers around these functions to improve the type safety of using the operations.Sort<'T>(array) requiring C : comparison.11 Additional Constraints on CLI Methods Some specific CLI methods and types are treated specially by F#.Array. System.Array.14.BinarySearch<T>(array.Array.GetHashCode() requires type ty : equality for the static type of x new Dictionary<A. for any overload that does not take an IEqualityComparer<T> new SortedList<A.LastIndexOf(array.B>() requires A : equality. for any overload that does not take an IComparer<T> System. for any overload that does not take an IEqualityComparer<T> new SortedDictionary<A. the F# compiler imposes additional ad hoc constraints: x.T) requiring C : equality System.

except on a single line of its own to terminate entries to F# Interactive. The lightweight syntax option is a conservative extension of the explicit language syntax. This can make a surprising difference in the readability of code. with this option. because the compiler reports many indentation problems with your code and ensures a regular. printf "World".r1. Compiling your code with the indentation-aware syntax option is useful even if you continue to use explicit tokens. The token after the "=" // of a 'let' definition begins a new block. Comments act entirely as if they were replaced by whitespace characters. let SimpleSample() = let x = 10 + 12 . where // the pre-parser inserts an implicit separating 'in' // token between each 'let' binding that begins at // the same column as that token. // #indent "off" let SimpleSample() = let x = 10 + 12 ..y. The "in" is optional when // the light syntax option is used... for.r2) // Without the light syntax option // "done" is required #indent "off" let FunctionSample() = let tick x = printfn "tick %d" x let tock x = printfn "tock %d" x let choose f g h x = if f x then g x else h x for i = 0 to 10 do choose (fun n -> n%2 = 0) tick tock i let FunctionSample() = let tick x = printfn "tick let tock x = printfn "tock let choose f g h x = if f x then g x else h for i = 0 to 10 do choose (fun n -> n%2 = %d" x in %d" x in x in 0) tick tock i 202 . x%3 in (x.. The use of .y. x%3 (x.1 Basic Lightweight Syntax Rules by Example The basic rules applied during processing of lightweight processing are shown below." to // terminate interactive entries to fsi.r2) // // // // When the light syntax option is enabled "done" is optional and the scope of structured constructs such as match. For example: let f x = let y = x + 1 y + y // the ‘in’ token is not required on this line Note: Do not use .3 in let y = x * 2 + 1 in let r1. because the parser takes indentation into account.r2 = x/3. This means that the indentation position of comments is irrelevant and ignored. printf "Hello" printf "World" // When the light syntax option is // enabled "in" is optional. // // #indent "off" printf "Hello".15 Lexical Filtering 15. illustrated by example.1. though // this is added automatically when using F# // Interactive from Visual Studio. comments are considered pure whitespace. // Without the light syntax option "in" // is very often required.3 let y = x * 2 + 1 let r1..1 Lightweight Syntax F# supports the use of lightweight syntax through the use of whitespace to make indentation significant. Tab characters cannot be used in F# files.exe.. In the processing of lightweight syntax.r1. in the sense that it simply lets you leave out certain tokens such as in and . NOTE: you still need to enter ". 15. // Without the light syntax option the // source code must contain ".r2 = x/3.." since every construct // starting at the first column is implicitly a new // declaration. is not needed. while and if/then/else is determined by indentation. // When the light syntax option is // enabled top level expressions do not // need to be delimited by ". clear formatting style.." to separate top-level // expressions.

2 Inserted Tokens Some hidden tokens are inserted by lexical filtering.ToUpper(c) if c >= 'A' && c <= 'Z' then let i = Char.1 do let c = data. printfn "done!" // When the light syntax option is // enabled the scope of if/then/else is implicit from // indentation. let f () = match 1+1 with | 2 -> printf "ok" | _ -> failwith "no!" <-.[i] + 1 printfn "done!" Here are some examples of how the offside rule is applied to F# code: // "let" and "type" declarations in // modules must be precisely aligned.results. These are shown below.printfn "done!" done.Length .warning FS0058: possible incorrect indentation: this token is offside of context at position (2:1) // The "|" markers in patterns must align.ToUpper(c) in if c >= 'A' && c <= 'Z' then begin let i = Char.Char.results. // The first "|" should always be inserted. OBLOCKEND and ORIGHT_BLOCK_END // Note: also called OBLOCKSEP // Note: also called HIGH_PRECEDENCE_APP // Note: also called HIGH_PRECEDENCE_TYAPP Note: The following tokens are also used in the Microsoft F# implementation.code 'A' results. let x = 1 let y = 2 <-.create numLetters 0 in let data = "The quick brown fox" in for i = 0 to data.3 Grammar Rules Including Inserted Tokens Additional grammar rules take into account the token transformations performed by lexical filtering: expr +:= | let binding $in expr | while expr do expr $done | if expr then $begin expr $end | for pat in expr do expr $done 203 . printfn "done!" // Without the light syntax option // "begin"/"end" or parentheses are often needed // to delimit structured language constructs #indent "off" let ArraySample() = let numLetters = 26 in let results = Array.syntax error 15. let ArraySample() = let numLetters = 26 let results = Array.1.code c .code 'A' in results.[i] + 1 end done.Chars(i) in let c = Char.[i] <.unmatched 'let' let z = 3 <-.Length .Char.code c .1 do let c = data.Chars(i) let c = Char. token token token token token token token $in $done $begin $end $sep $app $tyapp // Note: also called ODECLEND // Note: also called ODECLEND // Note: also called OBLOCKBEGIN // Note: also called OEND.[i] <.create numLetters 0 let data = "The quick brown fox" for i = 0 to data.1. They are translations of the corresponding input tokens and are used to give better error messages for lightweight syntax code: tokens $let $use $let! $use! $do $do! $then $else $with $function $fun 15.

4 Offside Lines Lightweight syntax is sometimes called the ―offside rule‖. 204 . in particular at the following places:   The column of the first token after the then in an if/then/else construct. if and module token. module-elem $end module-abbrev +:= | module ident = $begin long-ident $end module-defn +:= | module ident = $begin module-defn-body $end module-signature-elements +:= | $begin module-signature-element . offside lines occur at column positions. } and end) automatically terminate offside contexts up to and including the context introduced by the corresponding ―opening‖ token. 15.| for expr to expr do expr $done | try expr $end with expr $done | try expr $end finally expr $done | | | | expr $app expr // equivalent to "expr(expr)" expr $sep expr // equivalent to "expr.1. expr" expr $tyapp < types > // equivalent to "expr<types>" $begin expr $end // equivalent to ‚expr‛ elif-branch +:= | elif expr then $begin expr $end else-branch +:= | else $begin expr $end class-or-struct-type-body +:= | $begin class-or-struct-type-body $end // equivalent to class-or-struct-type-body module-elems +:= | $begin module-elem .   The column of the first token of a (.   When a column position becomes an offside line. and uses a stack of contexts.. In F# code. an = token associated with let introduces an offside line at the column of the first non-whitespace token after the = token... For example.. -> and with (in a match/with or try/with) and with (in a type extension).1. The column of the first token after a try. else. module-signature-element $end module-signature +:= | module ident = $begin module-signature-body $end 15. The start of a let. a ―context‖ is pushed.5 The Pre-Parse Stack The lightweight syntax option is implemented as a pre-parse of the token stream that comes from a lexical analysis of the input text (according to the lexical rules above). Other structured constructs can also introduce offside lines. ―Closing‖ bracketing tokens (). { or begin token.

pushed when the then keyword is encountered. pushed when the member. pushed when the fun keyword is encountered. Function pushed when the function keyword is encountered. class.. Namespace Module Member although only when not already in a Member context. Try. abstract. Immediately after an interface. pushed when the while keyword is encountered. tokens is automatically inserted as necessary between the elements. pushed when the namespace keyword is encountered. pushed when the type keyword is encountered. pushed when the else keyword is encountered. Then. Immediately after a -> token is encountered in a MatchClauses context. or struct token is encountered in a type declaration. The following contexts are associated with particular nested constructs introduced by the specified keywords:        Let If Try Lazy Fun pushed when the let keyword is encountered. default. interface or object expression whose members use the syntax { new Foo member x.M() = 1 member x. Immediately after an infix token is encountered. This context is pushed at the following times: o o o o o o Immediately after the start of a file. excluding lexical directives such as #if. First. from the expression new x() 205 . or override keyword is encountered. pushed when an if or elif keyword is encountered.  WithAugment pushed when with is encountered as part of an extension. Also pushed when ‗(‘ is the next token after a new keyword. This distinguishes the member declaration new(x) = . WithLet pushed when with is encountered as part of a record expression or an object expression whose members use the syntax{ new Foo with M() = 1 and N() = 2 }. Immediately after an = token is encountered in a Let or Member context. WithAugment. N() = 2 }. because multiple tokens may be present. Finally. Else. pushed when the lazy keyword is encountered.6 Full List of Offside Contexts The full list of offside contexts that is kept on the pre-parse stack is as follows. Do context is pushed. pushed when the module keyword is encountered. This indicates a sequence of items which must be column-aligned.1. pushed when the do keyword is encountered. and where a delimiter that replaces the regular in and . pushed when the try keyword is encountered. the following context is the primary context of the analysis:  SeqBlock. pushed when the for keyword is encountered.. Immediately after a Paren.           Match For While Then Else Do Type pushed when the match keyword is encountered. Here ―immediately after‖ refers to the fact that the column position associated with the SeqBlock is the first token following the significant token.15.

the following tokens cause contexts to be popped off the offside stack until a condition is reached. Interface. begin. 206 . then enclosing contexts are closed until the token is no longer offside. When a WithAugment context is closed. and the offside token that forced the close is not done.8 Offside Tokens.  When a While or For context is closed. Try. Member.  Paren(token) MatchClauses pushed when (. indicating that the construct is badly formatted. with the exception of the first SeqBlock pushed for the start of the file. The offside limit for the current offside stack is the rightmost offside line for the offside contexts on the context stack. pushed when the with keyword is encountered in a Try or Match context immediately after a function keyword. end pop until enclosing context is one of: WithAugment Paren(interface) Paren(class) Paren(sig) Paren(struct) Paren(begin) . [|. Let. the $done token is inserted. If a token is offside and a context cannot be closed. or quote-op-left is encountered. Contexts are closed as follows:   When a Fun context is closed. When a context is popped.   When a Member context is closed. the $end token is inserted. pop all else pop until If elif pop until If done pop until Do in pop until For or Let with pop until Match.7 Balancing Rules When processed. and Closing Contexts When a token occurs on or before the offside limit for the current offside stack. the $end token is inserted. 15. Token Insertions. and a permitted undentation does not apply. the $end token is inserted. [.1. struct. MatchClauses.  Vanilla pushed whenever an otherwise unprocessed keyword is encountered in a SeqBlock context. extra tokens may be inserted to indicate the end of the construct.. This may result in the insertion of extra delimiting tokens. then an ―undentation‖ warning or error is given. Type finally pop until Try ) pop until Paren(() } pop until Paren({) ] pop until Paren([) |] pop until Paren([|) quote-op-right pop until Paren(quote-op-left) 15. the $end token is inserted.1. or Do context is closed. sig. {. When a SeqBlock.

which pops the context and inserts $end. The 1 pushes a Vanilla context.. so a $seq token is inserted. then. =. That is.". The = token in a Let context pushes a SeqBlock context and inserts a $begin token. An initial SeqBlock is pushed immediately after the start of the file. The same also applies to end. an infix token may be offside by the size of the token plus one. the infix token |> that begins the last line is not considered a new element in the sequence block on the right-hand side of the definition. )) The first ) token here does not indicate a new element in a sequence of items.map (fun x -> x + 1) In particular.Tokens are also inserted in the following situations. For example. in a SeqBlock context. is offside from the Vanilla context. new EventHandler(fun _ _ -> . 207 .. the $in token is inserted. any infix token is permitted to align precisely with the offside line of the SeqBlock without being considered offside. the $sep token is inserted.1.  When a token other than and appears directly on the offside line of Let context. and rightparenthetical operators. with an offside line on column 0. in the following examples. despite the fact that it is precisely aligned with the sequence block that started at the start of the argument list. and.9 Exceptions to the Offside Rules Some exceptions are made when a token is analyzed to determine whether it is offside from the current context:  In a SeqBlock context. It is directly aligned with the SeqBlock context.. which inserts another $end token. which pops that context. It is also offside from the SeqBlock context. This token plays the same role as . The final token. For example: new MenuItem("&Open. It is also offside from the Let context. x and an end-of-file marker eof. consider this source text: let x = 1 x The raw token stream is let.  When a SeqBlock context is pushed. x. and the next surrounding context is a SeqBlock.. The let token pushes a Let context. For example: let someFunction(someCollection) = someCollection |> List. 1. x. at the first token in the file. the infix tokens are permitted to be offside: let x = expr + expr + expr + expr let x = expr |> f expr |> f expr  Similarly. in the grammar rules. with. the $begin token is inserted. with the exception of the first SeqBlock pushed for the start of the file. 15.  When a token occurs directly on the offside line of a SeqBlock on the second or subsequent lines of the block.

without being considered offside. For example: for i = 1 to 3 do expr done  Upon entry to a SeqBlock. on the right-hand side of an arrow for a match expression—a token is permitted to align precisely with the match. an and token is permitted to align precisely with the let. and else tokens are permitted to align precisely with the if. a done token is permitted to align precisely with the for. For example: if big then callSomeFunction() elif small then callSomeOtherFunction() else doSomeCleanup() 208 . For example: match x with | Some(_) -> 1 | None -> match y with | Some(_) -> 2 | None -> 3  In an Interface context. For example: type X = | A | B with member x.Seven = 21 / 3 end and Y = { x : int } and Z() = class member x. without being considered offside. For example: let rec x = 1 and y = 2 x + y  In a Type context. then. meaning that a long series of matches does not cause increased indentation. the }. an end token is permitted to align precisely with the interface. In a Let context. end. without being considered offside. This allows the last expression to be aligned with the match. and. For example: interface IDisposable with member x. and | tokens are permitted to align precisely with the type. Match context—that is. without being considered offside.Eight = 4 + 4 end  In a For context. without being considered offside.Dispose() = printfn "disposing!" done  In an If context. without being considered offside. elif.

For example: let HashSample(tab: Collections.1.%O)" c v) The block must not undent past other offside lines.1 Undentation of Bodies of Function Expressions The bodies of functions may be undented from the fun or function symbol. undentation is permitted as described in the following subsections. In particular. let IfSample(day: System.Monday then ( printf "I don't like Mondays" ) 209 . finally and with tokens are permitted to align precisely with the try. For example: try callSomeFunction() finally doSomeCleanup() and try callSomeFunction() with Failure(s) -> doSomeCleanup()  In a Do context. called the ―incremental indentation‖ rule.DayOfWeek. ) or begin . so the following is not accepted because the second line breaks the offside line established by the =: let x = (function (s.10. n) -> (fun z -> s+n+z)) Constructs enclosed in brackets may be undented. the symbol is ignored when determining whether the body of the function satisfies the incremental indentation rule.DayOfWeek) = if day = System. 15.10.10 Permitted Undentations In general. for certain constructs undentation is permitted. end block in an if/then/else expression may be undented when the expressions follow a then or else but may not undent further than the if.HashTable<_._>) = tab.. Warnings or syntax errors will be given where this is not the case. a done token is permitted to align precisely with the do... without being considered offside.Iterate (fun c v -> printfn "Entry (%O.1.. without being considered offside. In a Try context.1. As a result. However. 15. nested expressions must occur at increasing column positions in indentation-aware code. For example: for i = 1 to 3 do expr done 15.2 Undentation of Branches of If/Then/Else Expressions The body of a ( .

.3 Undentation of Bodies of Modules and Module Types Likewise.15.Meth1(arg1.Meth2(arg1. end may be undented. property lookups. arbitrary chains of method applications..10. struct . binding more tightly—than prefix and dot-notation operators. field lookups.C Example 2: B ((e).. }. For example: e. We do not show this symbol in the remainder of this specification and simply show the original source text. Instead.Meth2() Although the grammar and these precedence rules technically allow the use of high-precedence application expressions as direct arguments. class . The entry "f(x)" indicates that in expressions and patterns. Conceptually this means that Example 1: B(e) is analyzed lexically as Example 1: B $app (e) where $app is an internal symbol inserted by lexical analysis. end may be undented... interfaces. identifiers that are followed immediately by a left parenthesis without intervening whitespace form a ―high precedence‖ application. and function applications can be used in sequence provided that the arguments of method applications are parenthesized and immediately follow the method name.arg2) e. the bodies of modules and module types that are delimited by begin . end.C B (e). with no intervening spaces. For example: module MyNestedModule = begin let one = 1 let two = 2 end Likewise the bodies of classes.C 210 . These are parsed with higher precedence—that is. an additional check prevents this. and structs delimited by { . such expressions must be surrounded by parentheses. Furthermore.Prop1.Meth1(arg1... This means that Example 1: Example 2: are parsed as Example 1: (B(e)).[3].arg2).arg2) B(e). or interface ..arg2)) e.. end. For example.arg2)) (e. For example: type MyNestedModule = interface abstract P : int end 15.1. indexer lookups (..Meth2(arg1.Meth1(arg1.Prop2.[]).C) respectively.2 High Precedence Application The entry f x in the precedence table from §4 refers to a function application in which the function and argument are separated by spaces. f must be written f (e.

C<int>(e). indexer.Value = 1 let b = new Foo< >() // valid let c = new Foo<>() // invalid 211 .‖ (such as >. or >>>.C is returned as the following stream of tokens: Example 1: B $app <int> . >>.C $app <int>(e). [. or >>>) is treated as a series of individual > tokens. or identifier tokens. whitespace. *. A character sequence such as ―< >‖ with intervening whitespace should be used to indicate an empty list of generic arguments. For example: f e. ].. A final > token.‖.) is treated as a series of individual > tokens followed by a ―..Prop2.However.3 Lexical Analysis of Type Applications The entry f<types> x in the precedence table (§3. any token made up only of > characters (such as >. field. If an identifier is followed by a sequence of tokens of this kind then lexical analysis marks the construct as a high precedence type application and subsequent grammar rules ensure that the enclosed text is parsed as a type. During this analysis. The lexical analysis of type applications does not apply to the character sequence ―<>‖.C where $app is an internal symbol inserted by lexical analysis. Likewise. A parentheses ( or < token followed by any tokens until a matching parentheses ) or > is encountered.[3] 15. . '. and property dot-notation lookups may be used as arguments without adding parentheses.Prop1 e.7) refers to any identifier that is followed immediately by a < symbol and a sequence of:    _. Conceptually this means that Example 1: B<int>. We do not show this symbol elsewhere in this specification and simply show the original source text. >>. any token made up only of > characters followed by a ―. type Foo() = member this.

ParamArrayAttribute [<ParamArray(.1... in referenced assemblies authored in F#. System.ContextStaticAttribute [<ContextStatic(.1 Custom Attributes Recognized by F# The following custom attributes have special meanings recognized by the F# compiler.AttributeUsageAttribute [<AttributeUsage(.)>] Attaches version metadata to the compiled form of the assembly. This attribute may be used in both F# and imported assemblies.ConditionalAttribute [<Conditional(.ThreadStaticAttribute [<ThreadStatic(.)>] Marks a mutable static value in a class as thread static.)>] Ensures that calls to the method are emitted only when the corresponding conditional definition is made.)>] When applied to an argument of a method.ObsoleteAttribute [<Obsolete(. 16. System.AssemblyInformationalVersionAttribute [<AssemblyInformationalVersion(... This attribute may be used in both F# and imported assemblies. This attribute may be used in both F# and imported assemblies. Reflection. This attribute may be used in both F# and imported assemblies.16 Special Attributes and Types This chapter documents attributes and types of special significance to the F# compiler.)>] Marks a mutable static value in a class as context static. Attribute System. System.. or in assemblies that are authored in other CLI languages...)>] Description Indicates that the construct is obsolete and gives a warning or error depending on the settings in the attribute.)>] Specifies the attribute usage targets for an attribute. This attribute may be used in both F# and imported assemblies. System. 212 . System. indicates that special language rules apply to the processing of method applications that allow the method to act as a variable-argument method.. This attribute may be used in both F# and imported assemblies.. Except where indicated.. System. This attribute may be used in both F# and imported assemblies... the attributes may be used in F# code...Diagnostics.

This attribute may be used in both F# and imported assemblies. 213 .... such as the ―FileDescription‖ attribute in the Win32 version resource for the assembly. AssemblyCompanyAttribute [<AssemblyCompany(.)>] Attaches metadata to the compiled form of the assembly.. Reflection. such as the ―ProductName‖ attribute in the Win32 version resource for the assembly. AssemblyTitleAttribute [<AssemblyTitle(.)>] Attaches metadata to the compiled form of the assembly.)>] Indicates to the F# compiler how to sign an assembly.)>] Description Attaches version metadata to the compiled form of the assembly.. This attribute may be used in both F# and imported assemblies. This attribute may be used in both F# and imported assemblies.. System. such as the ―LegalTrademarks‖ attribute in the Win32 version resource for the assembly. Reflection. AssemblyKeyFileAttribute [<AssemblyKeyFile(. AssemblyCopyrightAttribute [<AssemblyCopyright(.... AssemblyTrademarkAttribute [<AssemblyTrademark(. This attribute may be used in both F# and imported assemblies. AssemblyProductAttribute [<AssemblyProduct(.AssemblyDescriptionAttribute [<AssemblyDescription(. System.AssemblyFileVersionAttribute [<AssemblyFileVersion(. System. such as the ―LegalCopyright‖ attribute in the Win32 version resource for the assembly. such as the ―LegalCopyright‖ attribute in the Win32 version resource for the assembly. This attribute may be used in both F# and imported assemblies.Attribute System.. This attribute may be used in both F# and imported assemblies... Reflection.)>] Attaches metadata to the compiled form of the assembly. Reflection. such as the ―Comments‖ attribute in the Win32 version resource for the assembly.)>] Attaches metadata to the compiled form of the assembly. Reflection. System... This attribute may be used in both F# and imported assemblies. Reflection.. System.)>] Attaches metadata to the compiled form of the assembly.. Reflection. Reflection. System.)>] Attaches metadata to the compiled form of the assembly. System. This attribute may be used in both F# and imported assemblies.

specifies the name of the indexer property for that type..Runtime..CompilerServices.DefaultMemberAttribute [<DefaultMember(.. This attribute may be used in both F# and imported assemblies. This attribute may only be used in imported non-F# assemblies.Runtime.Reflection.. Indicates the compiled form of a C# extension member.)>] Description When applied to a type.TypeForwardedToAttribute [<TypeForwardedTo(. This attribute may be used in both F# and imported assemblies. System..InteropServices.CompilerServices. System.Runtime. System..)>] When applied to a function definition in a module. Its use in F# code is not permitted. This attribute may be used in both F# and imported assemblies. that the specification of "custom" marshallers are not supported by F#.Runtime. causes the F# compiler to ignore the implementation of the binding. This attribute may be used in both F# and imported assemblies.InteropServices.ExtensionAttribute [<Extension(... specifies the marshalling attribute for a CLI P/Invoke stub declaration.Attribute System.InternalsVisibleToAttribute [<InternalsVisibleTo(.)>] System. Note. This attribute may be used in both F# and imported assemblies. System.InteropServices.InteropServices. specifies the CLI Out attribute. However. This attribute may be used in both F# and imported assemblies.OutAttribute [<Out>] When applied to a parameter. it has no specific meaning in F# beyond changing the corresponding attribute in the CLI compiled form.InAttribute [<In>] When applied to a parameter.. System.. and instead compile it as a CLI P/Invoke stub declaration. This attribute may only be used in imported non-F# assemblies.Runtime.CompilerServices. however.)>] Indicates a type redirection. Its use in F# code is not permitted. System.DllImportAttribute [<DllImport(. but has no specific meaning in F# beyond changing the corresponding attribute in the CLI compiled form. 214 .Runtime.)>] When applied to a parameter or return type.. specifies the CLI In attribute..)>] Directs the F# compiler to permit access to the internals of the assembly.Runtime.MarshalAsAttribute [<MarshalAs(.

specifies the CLI Optional attribute. This attribute should only be used in F# assemblies. This attribute should only be used in F# assemblies.OptionalAttribute [<Optional(.FieldOffsetAttribute [<FieldOffset(.Runtime. Microsoft.InteropServices. specifies the field offset of the underlying CLI field..NonSerializedAttribute [<NonSerialized>] When applied to a field. When applied to a module without a string argument. but has no specific meaning in F# beyond changing the corresponding attribute in the CLI compiled form.. 215 .)>] Controls the compiled name of an F# language construct.FSharp. This attribute may be used in both F# and imported assemblies.)>] Specifies the layout of a CLI type..)>] When applied to a field.. disables the behavior where F# makes the type serializable by default. This attribute should only be used in F# assemblies. This attribute may be used in both F# and imported assemblies.FSharp. This attribute may be used in both F# and imported assemblies. Microsoft. When added to a type with value false.)>] Description When applied to a parameter.InteropServices.Attribute System.CompilationRepresentationAttribute [<CompilationRepresentation(. System.AutoOpenAttribute [<AutoOpen>] When applied to an assembly and given a string argument.InteropServices.)>] Controls the compiled form of an F# language construct.CompiledNameAttribute [<CompiledName(. This attribute should only be used in F# assemblies.FSharp. System.. causes the module to be automatically opened when the enclosing namespace or module is opened.Core. causes the namespace or module to be automatically opened when the assembly is referenced.AutoSerializableAttribute [<AutoSerializable(false)>] Microsoft.Core..Runtime.Core....FSharp. indicates that the "not serialized" bit should be set for the underlying CLI field.StructLayoutAttribute [<StructLayout(.. System.Runtime. Microsoft.Core. This attribute may be used in both F# and imported assemblies.

Core.. Used to replace the default generated implementation of unverifiable inlined members with a verifiable stub. Microsoft.)>] When applied to an F# field. IsCaseB members should not be generated for that type. This attribute should only be used in F# assemblies. indicates that the default CLI-visible augmentation of IsCaseA. This attribute should only be used in F# assemblies.FSharp.FSharp.NoDynamicInvocationAttribute [<NoDynamicInvocation>] When applied to a function or member binding. This attribute should be used only in F# assemblies.CustomComparisonAttribute [<CustomComparison>] Description When applied to an F# structural type. This attribute should be used only in F# assemblies. Microsoft.DefaultAugmentationAttribute [<DefaultAugmentation(. Microsoft.)>] When applied to an F# construct.)>] When applied to an F# union type.Attribute Microsoft.CompilerMessageAttribute [<CompilerMessage(.FSharp.. Microsoft. indicates that uses of the attribute can result in generic code through the process of type inference. For example.FSharp. This attribute may be used in F# code...GeneralizableValueAttribute [<GeneralizableValue>] When applied to an F# value.FSharp.FSharp. marks the field as not needing initialization. Set.Core. The field must be mutable. 216 . compiles the value as a CLI literal.FSharp.Core. Microsoft. controls whether the type must define a user-specified comparison implementation. Microsoft. The value must normally be a type function whose implementation has no observable side effects. indicates that the F# compiler should report a message when this construct is used. This attribute may be used in F# code.. replaces the generated code with a stub that throws an exception at runtime.FSharp.Core. Microsoft.Core.DefaultValueAttribute [<DefaultValue(.empty. This attribute should be used only in F# assemblies..Core. which implies that it will be initialized to the zero value.Core.Core.CustomEqualityAttribute [<CustomEquality>] When applied to an F# structural type. This attribute should be used only in F# assemblies. controls whether the type must define a user-specified equality implementation.LiteralAttribute [<Literal>] When applied to a binding.

Core. indicates that the field labels or union cases must be referenced by using a qualified path that includes the type name.FSharp. warns if open is used on that module name.Core. indicates that the function or method must be given explicit type arguments when used.StructAttribute [<Struct>] Description Indicates that a type is a struct type.FSharp. controls whether the type should use reference equality for its default equality implementation. Microsoft.StructuralComparisonAttribute [<StructuralComparison>] When applied to an F# structural type.Core.RequireQualifiedAccessAttribute [<RequireQualifiedAccess>] When applied to an F# module.FSharp.GetReflectedDefinition method.Core. This attribute should be used only in F# assemblies. This attribute should be used only in F# assemblies. controls whether the type uses structural comparison for its default comparison implementation.FSharp. Microsoft.FSharp.RequiresExplicitTypeArgumentsAttribute [<RequiresExplicitTypeArguments>] When applied to an F# function or method. This attribute should only be used in F# assemblies.ClassAttribute [<Class>] Microsoft. This attribute should be used only in F# assemblies. Microsoft. When applied to an F# union or record type. This attribute should be used only in F# assemblies.Core.FSharp.Core.ReflectedDefinitionAttribute [<ReflectedDefinition>] Makes the quotation form of a binding available at runtime through the Microsoft. Microsoft. Microsoft. Indicates that a type or generic parameter is a unit of measure definition or annotation. Indicates that a type is an interface type.FSharp.Quotations.Attribute Microsoft. This attribute should be used only in F# assemblies.Core. This attribute should only be used in F# assemblies.Core.Core. typeof<int>. For example.ReferenceEqualityAttribute [<ReferenceEquality>] When applied to an F# record or union type.FSharp.InterfaceAttribute [<Interface>] Microsoft. This attribute should be used only in F# assemblies.MeasureAttribute [<Measure>] Microsoft. Expr.FSharp. This attribute should be used only in F# assemblies. 217 .FSharp. Indicates that a type is a class type.

2 Custom Attributes Emitted by F# The following custom attributes can be emitted by the F# compiler: Attribute System. Indicates the name of the indexer property for a class.FSharp. they do not affect the behavior of the F# compiler.DefaultMemberAttribute Microsoft.CompilationMappingAttribute Microsoft. Improves debuggability of F# code.3 Custom Attributes Not Recognized by F# The following custom attributes are defined in some CLI implementations and may seem to have meaning relevant to F#. 16.FSharpInterfaceDataVersionAttribute Microsoft. Indicates how a CLI construct relates to an F# source language construct. System.CompilerGeneratedAttribute Description Improves debuggability of F# code. Improves debuggability of F# code. controls whether the CLI volatile prefix is emitted before accesses to the field.Core.FSharp. This attribute should be used only in F# assemblies.FSharp.Core.Diagnostics.Core.Core.DebuggerDisplayAttribute System.Diagnostics.Runtime. Indicates the schema number for the embedded binary resource for F#-specific interface and optimization data.DebuggerBrowsableAttribute System.Runtime.FSharp. This attribute should be used only in F# assemblies.CompilationRelaxationsAttribute System.CompilerServices.OptionalArgumentAttribute 16.Diagnostics.Diagnostics. Indicates optional arguments to F# members.Attribute Microsoft.Core. Improves debuggability of F# code.FSharp. Microsoft. Attribute Description 218 . or their use in F# code may be flagged as an error.1. However.StructuralEqualityAttribute [<StructuralEquality>] Description When applied to an F# structural type. type or property is generated by the F# compiler.DebuggerHiddenAttribute System.VolatileFieldAttribute [<VolatileField>] When applied to an F# field or mutable "let" binding.1. Permits extra JIT optimizations. controls whether the type uses structural equality for its default equality implementation.DebuggableAttribute System.CompilerServices. Indicates a method. and doesn't correspond directly to user source code.Reflection.

UnmanagedFunctionPointerAttribute System.OverflowException. The F# compiler ignores it or returns an error. The F# compiler ignores it or returns an error.IndexOutOfRangeException System. System.Runtime. An explicit conversion from a base type or interface to a derived type failed at run time. Do not use this attribute in F# code.InvalidCastException System.CompilerServices.RequiredAttributeAttribute System.SpecialNameAttribute 16. such as System. A store into an array failed because the actual type of the stored element is incompatible with the actual type of the array. However. The F# compiler ignores it or returns an error. An attempt to index an array failed because the index is less than zero or outside the bounds of the array. Do not use this attribute in F# code.InteropServices. A null reference was used in a way that caused the referenced object to be required. if used in F# code.Runtime. Do not use this attribute in F# code.2 Exceptions Thrown by F# Language Primitives The following exceptions are thrown by certain F# language or primitive library operations.CompilerServices. its effect is to cause some other CLI languages interpret a decimal constant as a compiletime literal.Attribute System.InteropServices.DivideByZeroException and System. The F# compiler ignores it or returns an error. An attempt to divide an integral value by zero occurred.NullReferenceException 219 .ArithmeticException Description Base class for exceptions that occur during arithmetic operations. Do not use this attribute in F# code.Runtime.Runtime. The F# compiler ignores it or returns an error.CompilerServices. Attribute System. Do not use this attribute in F# code.FixedBufferAttribute System.DivideByZeroException System.Runtime.CompilerServices.UnsafeValueTypeAttribute System. System.DefaultParameterValueAttribute System. Do not use this attribute in F# code.CompilerServices.DecimalConstantAttribute Description The F# compiler ignores this attribute.Runtime.ArrayTypeMismatchException System.Runtime. The F# compiler ignores it or returns an error.

System. An arithmetic operation in a checked context overflowed. The execution stack was exhausted because of too many pending method calls.StackOverflowException System.Attribute System.OverflowException System. F# initialization code for a type threw an uncaught exception. typically indicative of very deep or unbounded recursion.OutOfMemoryException Description An attempt to use new to allocate memory failed.TypeInitializationException 220 .

single float.Char 221 .1 Basic Type Abbreviations Type Name obj exn nativeint unativeint string float32.Core.Int16 System.Byte System.Core) 17. See also the online documentation at http://msdn.Single System.Collections Microsoft.Core.String System.UIntPtr System.Core.Object System.100).UInt64 System.IntPtr System.Core Microsoft.Int32 System.Text Microsoft.Exception System.dll The CLI base library mscorlib.ExtraTopLevelOperators Additional namespaces may be opened if AutoOpenAttribute declarations are attached to referenced F# DLLs.microsoft.FSharp.UInt32 System. int8 byte.UInt16 System.SByte System.Int64 System.Operators Microsoft.FSharp.FSharp.Double System.FSharp Microsoft.17 The F# Library FSharp. double sbyte.Core.Core.dll is referenced by all compilations. The F# base library FSharp.FSharp.1.FSharp.aspx.dll is referenced by all compilations. uint8 int16 uint16 int32. The following namespaces are automatically opened for all F# code: open open open open open open open Microsoft.LanguagePrimitives Microsoft. int uint32 int64 uint64 char Description System.FSharp.1 Basic Types (Microsoft.FSharp.com/library/ee353567(VS. 17.

but accepts a unit of measure.2 Basic Types that Accept Unit of Measure Annotations Type Name sbyte<_> Description Underlying representation System. but accepts a unit of measure. but accepts a unit of measure. int32<_> Underlying representation System.Boolean System. decimal<_> Underlying representation System. This only applies if type does not contain any generic type parameters.IntPtr.Double.Single. 17.Decimal.Int16. Otherwise.Int64. it is represented as the CLI type System.1.String is one place where pointer types appear in CLI metadata. nativeptr<_> compiles in different ways because CLI makes restrictions exist about where pointer types can appear. 222 .UIntPtr and nativeptr<'T> using the inlined unverifiable functions in Microsoft. Note: CLI pointer types are rarely used. but accepts a unit of measure. You can convert between System. but accepts a unit of measure.Int32.FSharp. float32<_> Underlying representation System.NativeInterop.3 nativeptr<_> When the nativeptr<type> is used in method argument or return position. float<_> Underlying representation System.Decimal 17. it is represented as a CLI pointer type type* in compiled CIL code. int64<_> Underlying representation System.Type Name bool decimal Description System. but accepts a unit of measure.NativePtr.1. int16<_> Underlying representation System. The unsafe object constructors for the CLI type System.SByte. but accepts a unit of measure.

Overloaded subtraction. For negative numbers.1 Basic Arithmetic Operators The following operators are defined in Microsoft.Operators: Operator/Function Name (+) (-) (*) (/) Expression Form x + y x . Overloaded multiplication. If y is zero.Core.Core. the behavior of this operator also follows the definition of the remainder operator in the C# specification.17.FSharp.Operators) 17.Core.y x * y x / y Description Overloaded addition. For floating-point types. Boolean negation.DivideByZeroException is thrown.2 Basic Operators and Functions (Microsoft.2. the result of x % y is the value produced by x – (x / y) * y.FSharp. This follows the definition of the remainder operator in the C# specification. For integer types. 17. (~-) not -x not x Overloaded unary negation. (%) x % y Overloaded remainder. the behavior of this operator follows the definition of the corresponding operator in the C# specification.2 Generic Equality and Comparison Operators The following operators are defined in Microsoft. The remainder operator never causes an overflow.2.FSharp.Operators: Operator/Function Name (<) (<=) (>) (>=) Expression Form x < y x <= y x > y x >= y Description Generic less-than Generic less-than-or-equal Generic greater-than Generic greater-than-or-equal 223 . a System. Overloaded division.

Operator/Function Name (=) (<>) max min

Expression Form x = y x <> y max x y min x y

Description Generic equality Generic disequality Generic maximum Generic minimum

17.2.3 Bitwise Operators
The following operators are defined in Microsoft.FSharp.Core.Operators: Operator/Function Name (<<<) (>>>) (^^^) (&&&) (|||) (~~~) Expression Form x <<< y x >>> y x ^^^ y x &&& y x ||| y ~~~x Description Overloaded bitwise shift-left Overloaded bitwise arithmetic shift-right Overloaded bitwise exclusive or Overloaded bitwise and Overloaded bitwise or Overloaded bitwise negation

17.2.4 Math Operators
The following operators are defined in Microsoft.FSharp.Core.Operators: Operator/Function Name abs acos asin atan atan2 ceil cos cosh exp floor log log10 (**) pown Expression Form abs x acos x asin x atan x atan2 x y ceil x cos x cosh x exp x floor x log x log10 x x ** y pown x y Description Overloaded absolute value Overloaded inverse cosine Overloaded inverse sine Overloaded inverse tangent Overloaded inverse tangent of x/y Overloaded floating-point ceiling Overloaded cosine Overloaded hyperbolic cosine Overloaded exponent Overloaded floating-point floor Overloaded natural logarithm Overloaded base-10 logarithm Overloaded exponential Overloaded integer exponential

224

Operator/Function Name round sign sin sinh sqrt tan tanh

Expression Form round x sign x sin x sinh x sqrt x tan x tanh x

Description Overloaded rounding Overloaded sign function Overloaded sine function Overloaded hyperbolic sine function Overloaded square root function Overloaded tangent function Overloaded hyperbolic tangent function

17.2.5 Function Pipelining and Composition Operators
The following operators are defined in Microsoft.FSharp.Core.Operators: Operator/Function Name (|>) (>>) (<|) (<<) ignore Expression Form x |> f f >> g f <| x g << f ignore x Description Pipelining Function composition Backward pipelining Backward function composition Computes and discards a value

17.2.6 Object Transformation Operators
The following operators are defined in Microsoft.FSharp.Core.Operators: Operator/Function Name box hash sizeof typeof Expression Form box x hash x sizeof<type> typeof<type> Description Converts to object representation. Generic hashing operator. Computes the size of a value of the given type. Computes the System.Type representation of the given type. typedefof typedefof<type> Computes the System.Type representation of the given type and calls GetGenericTypeDefinition if this is a generic type. unbox ref (!) unbox x ref x !x Converts from object representation. Allocates a mutable reference cell. Reads a mutable reference cell.

17.2.7 The typeof and typedefof Operators
The following operators are defined in Microsoft.FSharp.Core.Operators:

225

Operator/Function Name typeof

Expression Form typeof<type>

Description Computes the System.Type representation of the given type.

typedefof

typedefof<type>

Computes the System.Type representation of the given type and calls GetGenericTypeDefinition if this is a generic type.

17.2.8 Pair Operators
The following operators are defined in Microsoft.FSharp.Core.Operators: Operator/Function Name fst snd Expression Form fst p snd p Description Takes the first element of a pair. Takes the second element of a pair

17.2.9 Exception Operators
Operator/Function Name failwith invalidArg Expression Form Description

failwith x invalidArg x

Raises a FailureException exception. Raises an ArgumentException exception.

raise reraise

raise x reraise()

Raises an exception. Special operator to raise an exception.

17.2.10

Input/Output Handles
Expression Form Stdin Stdout Stderr Description Computes System.Console.In. Computes System.Console.Out. Computes System.Console.Error.

The following operators are defined in Microsoft.FSharp.Core.Operators: Operator/Function Name stdin stdout stderr

17.2.11

Overloaded Conversion Functions
Expression Form byte x sbyte x int16 x Description Overloaded conversion to a byte Overloaded conversion to a signed byte Overloaded conversion to a 16-bit integer

The following operators are defined in Microsoft.FSharp.Core.Operators: Operator/Function Name byte sbyte int16

226

Operator/Function Name uint16

Expression Form uint16 x

Description Overloaded conversion to an unsigned 16-bit integer

int32, int

int32 x int x

Overloaded conversion to a 32-bit integer

uint32

uint32 x

Overloaded conversion to an unsigned 32-bit integer Overloaded conversion to a 64-bit integer Overloaded conversion to an unsigned 64-bit integer Overloaded conversion to an native integer Overloaded conversion to an unsigned native integer Overloaded conversion to a 64-bit IEEE floatingpoint number Overloaded conversion to a 32-bit IEEE floatingpoint number Overloaded conversion to a System.Decimal number Overloaded conversion to a System.Char value Overloaded conversion to a typed enumeration value

int64 uint64

int64 x uint64 x

nativeint unativeint

nativeint x unativeint x

float, double

float x double x

float32, single

float32 x single x

decimal

decimal x

char enum

char x enum x

17.3 Checked Arithmetic Operators
The module Microsoft.FSharp.Core.Operators.Checked defines runtime-overflow-checked versions of the following operators: Operator/Function Name (+) (-) (*) (~-) byte sbyte int16 Expression Form x + y x – y x * y -x byte x sbyte x int16 x Description Checked overloaded addition Checked overloaded subtraction Checked overloaded multiplication Checked overloaded unary negation Checked overloaded conversion to a byte Checked overloaded conversion to a signed byte Checked overloaded conversion to a 16-bit integer

227

Operator/Function Name uint16

Expression Form uint16 x

Description Checked overloaded conversion to an unsigned 16-bit integer

int32, int

int32 x int x

Checked overloaded conversion to a 32-bit integer Checked overloaded conversion to an unsigned 32-bit integer Checked overloaded conversion to a 64-bit integer Checked overloaded conversion to an unsigned 64-bit integer Checked overloaded conversion to an native integer Checked overloaded conversion to an unsigned native integer Checked overloaded conversion to a System.Char value

uint32

uint32 x

int64

int64 x

uint64

uint64 x

nativeint

nativeint x

unativeint

unativeint x

char

char x

17.4 List and Option Types
17.4.1 The List Type
A minimal definition of the F# type Microsoft.FSharp.Collections.list is shown below: type 'T list = | ([]) | (::) of 'T * 'T list static member Empty : 'T list member Length : int member IsEmpty : bool member Head : 'T member Tail : 'T list member Item :int -> 'T with get static member Cons : 'T * 'T list -> 'T list interface System.Collections.Generic.IEnumerable<'T> interface System.Collections.IEnumerable

17.4.2 The Option Type
A minimal definition of the F# type Microsoft.FSharp.Core.option is shown below: [<DefaultAugmentation(false)>]

228

aspx 17.aspx 17.com/ library/ee353813.microsoft.microsoft.com/library/ee370357.Instance)>] member Value : 'T member IsSome : bool member IsNone : bool 17.microsoft.aspx 17.8 Event Types See http://msdn.7 Agents (MailboxProcessor) See http://msdn.11 Reflection See http://msdn.UseNullAsTrueValue)>] type 'T option = | None | Some of 'T static member None : 'T option static member Some : 'T -> 'T option [<CompilationRepresentation(CompilationRepresentationFlags.aspx .com/library/ee370608.aspx 17.com/library/ee370560.12 Quotations 229 See http://msdn.aspx 17.microsoft.com/library/ee370232.6 Asynchronous Computations (Async) See http://msdn.microsoft.microsoft.[<CompilationRepresentation(CompilationRepresentationFlags.aspx 17.9 Immutable Collection Types (Map.microsoft.5 Lazy Computations (Lazy) See http://msdn.com/library/ee370558.com/library/ee353413. Set) See http://msdn.10 Text Formatting (Printf) See http://msdn.com/library/ee353491.microsoft.aspx 17.

17.13
code.

Native Pointer Operations

The namespace Microsoft.FSharp.Core.NativeIntrop contains functionality for interoperating with native

Operator/Function Name NativePtr.ofNativeInt NativePtr.toNativeInt NativePtr.add NativePtr.read NativePtr.write NativePtr.get NativePtr.set NativePtr.stackalloc

Description Returns a typed native pointer for a given machine address. Returns a machine address for a given typed native pointer. Computes an indexed offset from the input pointer. Reads the memory referenced by the input pointer. Writes to the memory referenced by the input pointer. Reads the memory at an indexed offset from the input pointer. Writes the memory at an indexed offset from the input pointer. Allocates a region of memory on the stack.

Use of these functions is unsafe, and incorrect use may generate invalid IL code.

17.13.1
Given

Stack Allocation

stackalloc<ty> n the unmanaged type ty indicates the type of the items that will be stored in the newly allocated location, and n indicates the number of these items. Taken together, these specify the required allocation size. The construct allocates n * sizeof<ty> bytes from the call stack and returns a pointer of type nativeptr<ty> to the newly allocated block. The content of the newly allocated memory is undefined. If n is a negative value, then the behavior of the function is undefined. If n is zero, then no allocation is made, and the returned pointer is implementation-defined. If insufficient memory is available to allocate a block of the requested size, a System.StackOverflowException is thrown. Use of this function is unsafe, and incorrect use might generate invalid IL code. For example, the function should not be used in with or finally blocks in try/with or try/finally expressions. These conditions are not checked by the F# compiler, because this primitive is rarely used from F# code. There is no way to explicitly free memory that is allocated using stackalloc. All stack-allocated memory blocks that are created during the execution of a function or member are automatically discarded when that function or member returns. This behavior is similar to that of the alloca function, an extension commonly found in C and C++ implementations.

230

18 Features for ML Compatibility
F# has its roots in the Caml family of programming languages and has core constructs similar to some other MLfamily languages. As a result F# supports some constructs for compatibility with other implementations of MLfamily languages.

18.1.1 Conditional Compilation for ML Compatibility
The following constructs are supported for conditional compilation: token token token token start-fsharp-token = "(*IF-FSHARP" | "(*F#" end-fsharp-token = "ENDIF-FSHARP*)" | "F#*)" start-ml-token = "(*IF-OCAML*)" end-ml-token = "(*ENDIF-OCAML*)"

The start-fsharp-token and end-fsharp-token tokens are ignored. This means that sections marked (*IF-FSHARP or (*F# ... ENDIF-FSHARP*) ... F#*)

are included during tokenization when compiling with the F# compiler. The intervening text is tokenized and returned as part of the token stream as normal. In addition, the start-ocaml-token token is discarded and the following text is tokenized as string, _ (any character), and end-ocaml-token until an end-ocaml-token is reached. Comments are not treated as special during this process and are simply processed as ―other text‖. This means that text surrounded by the following is excluded when compiling with the F# compiler: (*IF-CAML*) ... (*ENDIF-CAML*) or (*IF-OCAML*) ... (*ENDIF-OCAML*) The intervening text is tokenized as ―strings and other text‖ and the tokens are discarded until the corresponding end token is reached. Comments are not treated as special during this process and are simply processed as ―other text.‖ The converse holds when programs are compiled using a typical ML compiler.

18.1.2 Extra Syntactic Forms for ML Compatibility
The following identifiers are also keywords primarily because they are keywords in OCaml. The /mlcompatibility option permits OCaml keywords that are reserved for future use by F# to be used as identifiers. token ocaml-ident-keyword = asr land lor lsl lsr lxor mod

Note: In F# the following alternatives are available. The precedence of these operators differs from the precedence that OCaml uses. asr land lor lsl lsr lxor mod sig >>> (on signed type) &&& ||| <<< >>> (on unsigned type) ^^^ % begin (that is, begin/end may be used instead of sig/end)

231

The following syntactic forms are added: expr := | ... | expr.(expr) | expr.(expr) <- expr

// array lookup // array assignment

type := | ... | (type,...,type) long-ident // generic type instantiation module-implementation := | ... | module ident = struct ... end module-signature := | ... | module ident : sig ... end An ML compatibility warning is given when these constructs are used. Note: The for-expression form for var = expr1 downto expr2 do expr3 is also permitted for ML compatibility. Lookup expressions are specified in terms of their shallow syntactic translation to uses of operators: e1.(e2) e1.(e2) <- e3 → (.()) e1 e2 → (.()<-) e1 e2 e3

18.1.3 Extra Operators
The following two additional shortcut operators are defined: e1 or e2 e1 & e2 → (or) e1 e2 → (&) e1 e2

18.1.4 File Extensions and Lexical Matters
F# supports the use of extensions .ml and .mli on the command line. The ―indentation awareness off‖ syntax option is implicitly enabled when using file extensions .ml or .mli. Lightweight syntax can be explicitly disabled in .fs, .fsi, .fsx and .fsscript files by using #indent "off" as the first declaration in a file: #indent "off" When lightweight syntax is disabled, whitespace can include tab characters: regexp whitespace = [ ' ' '\t' ]+

232

Glossary
This section contains terminology that is specific to F#. It provides a reference for terms that are used elsewhere in this document.

A
abstract member A member in a type that represents a promise that an object will provide an implementation for a dispatch slot. accessibility The program text that has access to a particular declaration element or member. You can specify accessibilities on declaration elements in namespace declaration groups and modules, and on members in types. F# supports public, private, and internal accessibility. and pattern A pattern that consists of two patterns joined by an ampersand (&). An and pattern matches the input against both patterns and binds any variables that appear in either pattern. anonymous implementation file A file that lacks either a leading module or namespace declaration. Only the scripts and the last file within an implementation group for an executable image can be anonymous. An anonymous implementation file can contain module definitions that are implicitly placed in a module, the name of which is implicit from the name of the source file that contains the module. anonymous variable type with a subtype constraint A type in the form #type. This is equivalent to 'a when 'a :> type where 'a is a fresh type inference variable. anonymous signature file A signature file that does not have either a leading module or namespace declaration. The name of the implied module signature is derived from the file name of the signature file. anonymous variable type A type in the form _. application expression An expression that involves variable names, dot-notation lookups, function applications, method applications, type applications, and item lookups assignment expression An expression in the form expr1 <- expr2. array expression An expression in the form [|expr1;...; exprn |]. array pattern The pattern [|pat ; ... ; pat|] , which matches arrays of a specified length. array sequence expression. An expression that describes a series of elements in an array, in one of the following forms:
[| comp-expr |] [| short-comp-expr |] [| range-expr |] 233

as pattern A pattern in the form pat as ident. The as pattern binds the name ident to the input value and matches the input against the pattern. automatic generalization A technique that, during type inference, automatically makes code generic when possible, which means that the code can be used on many types of data.

B
base type declarations A declaration that represents an additional, encapsulated type that is supported by any values that are formed by using the type definition. binding The association of a name with an expression or value. Typically used in “let binding.” binding expression An expression that uses let or do to associate a name with an expression, such as: let binding in expr block comments Comments that are delimited by (* and *), can span more than one line, and can be nested. block expression An expression in the form begin expr end.

C
class type definition The definition of a type that encapsulates values that are themselves constructed by using one or more object constructors. A class type typically describes an object that can have properties, methods, and events. coercion The changing of data from one type to another. comparison constraint A constraint of the form typar : comparison. compiled name The name that appears in the compiled form of an F# program for a symbolic operator or certain symbolic keywords. conditional expression An expression in the following form
if expr1a then expr1b elif expr3a then expr2b … elif exprna then exprnb else exprlast

The elif and else branches are optional.

234

which is evaluated on demand in response to a . 235 . A constraint of the form typar : delegate<tupled-args-type. custom attribute A class that encapsulates information.cons pattern The pattern pat :: pat. Each object that implements the type provides a dictionary mapping dispatch slots to member implementations.NET framework and can be used in any language that targets the common language runtime. which match any value whose runtime type is the given type or a subtype of the given type. form.Attribute in the . field-labeln = exprn } current inference constraints The set of type constraints that are in effect at a particular point in the program as a result of type checking and elaboration. which is used to decompose a list into two parts: the head. return-type>.Value operation on the lazy value. delegate constraint. Custom attributes derive from System. curried method members Arguments to a method that are written in an interated form. or variable types that refer to the same declaration or are the same type inference variable. F# performs default initialization in only limited circumstances. constraint See type constraint constraint solving The process of reducing constraints to a normalized form so that variables can be solved by deducing equations. and number. often metadata that describes or supplements an F# declaration. copy-and-update record expression An expression in the following form: { expr with field-label1 = expr1 . default initialization The practice of setting the values of particular types to zero at the beginning of execution. dispatch slot A key representing part of the contract of an interface or class type. definitely equivalent types Static types that match exactly in definition. which contains the remaining elements. delayed expression An expression in the form lazy expr. … . dynamic type test pattern The patterns :? type and :? type as ident. which consists of the first element. and the tail. D default constructor constraint A constraint of the form typar : (new : unit -> 'T). Unlike many programming languages.

often by some external action such as a mouse click or timer tick. patn -> expr. The F# library supports the Microsoft. equality constraint. reduced language. 236 . A constraint in the form typar : equality. enumeration constraint A constraint in the form typar : enum<underlying-type>.E elaborated expression An expression that the F# compiler generates in a simpler. feasibly equivalent types Types that are not definitely equivalent but could become so by the addition of further constraints to the current inference constraints. fresh type A static type that is formed from a fresh type inference variable. enumerable values. which limits the type to one that supports equality operations.FSharp.Event module to support the use of events.. function expression An expression of the form fun pat1 .FSharp. function value The value that results at runtime from the evaluation of function expressions.Control. which limits the type to an enumeration of the specified underlying type.Control._> type and the Microsoft. event A configurable object that has a set of callbacks that can be triggered. An elaborated expression contains a fully resolved and annotated form of the source expression and carries more explicit information than the source expression. or could become coercible through the addition of further constraints to the current inference constraints. for use during type inference.IEvent<_. fresh type inference variable A variable that is created during type inference and has a unique identity. enumerable extraction The process of getting sequential values of a static type by using CLI library functions that retrieve individual. F F# Interactive An F# dynamic compiler that runs in a command window and executes script fragments as well as complete programs. feasible coercion Indicates that one type either coerces to another.. floating type variable environment The set of types that are currently defined.

'Value>. functional. tabs. guarded pattern matching rule A rule of the form pat when expr that occurs as part of a pattern matching expression such as match expr0 with rule1 -> expr1 | … | rulen -> exprn. and the statements change the state of the program. import declaration A declaration that makes the elements of another namespace’s declarations and modules accessible by the use of unqualified names.Dictionary<'Key. An imperative program consists of a sequence of actions for the computer to perform. implementation member An abstract member that implements a dispatch slot or CLI property. I identifier A sequence of characters that is enclosed in `` `` double-backtick marks. 237 . imperative programming One of several primary programming paradigms. others include declarative. immutable value A named value that cannot be changed. and double-backtick pairs themselves.Generic.G generic type definition A type definition that has one or more generic type parameters. interface type definition A declaration that represents an encapsulated type that specifies groups of related members that other classes implement. excluding newlines. K keyword A word that has a defined meaning in F# and is used as part of the language itself. The guard expression expr is executed only if the value of expr0 successfully matches the pattern pat.Collections. among others. inference type variable A type variable that does not have a declaration site. For example: System. Import definitions can appear in namespace declaration groups and module definitions. instance member A member that is declared without static. procedural. ground type A type that contains no type variables.

pat]. . indentation-aware syntax in which lines of code that form a sequence of declarations are aligned on the same column. 238 .fs. list expression An expression of the form [expr1. list pattern A data recognizer pattern that describes a list. List sequence expressions can have the following forms: [ comp-expr ] [ short-comp-expr ] [ range-expr ] literal constant expression An expression that consists of a simple constant expression or a reference to another literal. byte array literals..fsx. which matches the empty list. Member definitions can be used in type definitions. with a value or function. and the in and .. Each item contains a pointer to the next item in the sequence. member constraint A constraint that specifies the signature that is required for a particular member function. “let” bindings An expression that associates a name.. method member An operation that is associated with a type or an object.fsscript. lightweight syntax A simplified. . list sequence expression An expression that evaluates to a sequence that is essentially a list. Lightweight syntax is the default for all F# code in files with extension . and [pat .. member signature The “footprint” of a property or method that is visible outside the defining module. which matches the 'cons' case of F# list values.L lambda expression See function expression. F# supports property members and method members. . list An F# data structure that consists of a sequence of items..fsi and . Literal constant expressions cannot include (). introduced by the word let... which represents a series of :: and empty list patterns. or typar) : (member-sig). M member A function that is associated with a type definition or with a value of a particular type. []. or user-defined numeric literals. BigInteger literals. . native integer literals. separators can be omitted. Examples are pat :: pat. Member constraints have the form (typar or . exprn].. unsigned native integer literals..

so that they form logical groups that are associated with a name. and function values. in the form long-ident<ty1. module abbreviation A statement that defines a local name for a long identifier in a module. numeric literal A sequence of Unicode characters or an unsigned byte array that represents a numeric value. which describes the externally visible elements of the group. namespace declaration group The basic declaration unit within an F# implementation file. It contains a series of module and type definitions that contribute to the indicated namespace. 239 . Identifiers must be unique within a namespace. null expression An expression of the form null.tyn>. en). which F# can use in furthy type inference and checking. usually by calling a constructor method on the type.module A named collection of declarations such as values. where long-ident resolves to a a type definition that has formal generic parameters and formal constraints. namespace A way of organizing the modules and types in an F# program. null pattern The pattern null.….. N name resolution environment The collection of names that have been defined at the current point. For example: module Ops = Microsoft. which matches the values that the CLI value null represents. types. which indicates that the type must support the Null literal.Core. The name resolution environment includes namespace declaration groups from imported namespaces in addition to names that have been defined in the current code. O object construction expression An expression in the form new ty(e1 .FSharp. named type A type that has a name. An implementation can contain multiple namespace declaration groups. The module signature describes the externally visible elements of the module. which constructs a new instance of a type.Operators module signature A description of the contents of a module that the F# compiler generates during type inference. namespace declaration group signature The “footprint” of a namespace declaration group. nullness constraint A constraint in the form typar: null..

R range expression An expression that generates a sequence over a given range of values. or set of interfaces. interface. record construction expression An expression that builds a record.. in the form { field-bind1 . Q quoted expression An expression that is delimited in such a way that it is not compiled as part of your program. object expression An expression that creates a new instance of a dynamically created. and they must call the primary constructor. property member A function in a type that gets or sets data about the type.object constructor A member of a class that can create a value of the type and partially initialize an object from a subclass. P parenthesized expression An expression in the form (expr). long-identn = patn}. offside rule Another term for lightweight or indentation-aware syntax. … . anonymous object type that is based on an existing base type. record pattern The pattern { long-ident1 = pat1. such asthe = token associated with let. and its parameters appear in parentheses immediately after the type name. pattern matching A switch construct that supports branched control flow and the binding of new values. 240 . Offside lines are introduced by other structured constructs. Any additional object constructors are specified with the new keyword. . field-bindn }. offside lines Lines that occur at column positions in lightweight syntax. and the first token after then in an if/then/else construct.. pipeline operator The |> operator. . but instead is compiled into an object that represents an F# expression. which directs the value of one function to be input to the next function in a pipeline. The primary constructor contains let and do bindings that appear at the start of the class definition.

enum. constraint solving.GetType() method. simple constant expressions A numeric. The expression has the form expr1. S script A fragment of an F# program that can be run in F# Interactive. function. after expanding type definitions. static type The type that is inferred for an expression as the result of type checking. expr2. A type is a reference type if its outermost named type definition is a reference type. single-line comments A comment that begins with // and extends to the end of a line. or union type. 241 . or unit constant. rigid type variable A type variable that refers to one or more explicit type parameter definitions. referenced assemblies The existing assemblies to which an F# program makes static references. which is available on all F# values.recursive binding expression A let binding expression in which the bound variables can be used within their own definitions. slice expression An expression that describes a subset of an array. A recursive binding expression has the form: let rec bindings $in expr reference type constraint A constraint of the form typar : not struct. tuple. union. as are class types marked with the SealedAttribute attribute. runtime type An object of type System. delegate. Record. signature file A file that contains information about the public signatures and accessibility of a set of F# program elements. The runtime type associated with an objects is accessed by using the obj. struct. and array types are all sealed. tuple. record. reference type A class. and inference. interface delegate. function. sealed type definition A type definition that is concrete and cannot be extended. sequence expression An expression that evaluates to a sequence of values.Type that is the runtime representation of some or all of the information carried in type definitions and static types. Boolean. in one of the following forms seq { comp-expr } seq { short-comp-expr } sequential execution expression An expression that represents the sequential execution of one statement followed by another. string.

.._>. which defines a tuple. which describes a tuple value.. Such a parameter is replaced with an actual type at compile time instead of runtime. tuple type A type in the form ty1 * . or exception type definition. 242 . T tuple An ordered collection of values that is treated as an atomic unit.static member A member that is prefixed by static and is associated with the type. A type annotation has the form expr : type. Syntactic types are converted to static types during the process of type checking and inference.. A tuple allows you to keep data organized by grouping related values together.. type annotation An addition to an expression that specifies the type of the expression. . subtype constraint A constraint of the form typar :> type. syntactic sugar Syntax that makes code easier to read or express. often a shortcut way of expressing a more complicated relationship for which one or more other syntactic options exist. statically resolved type variable A type parameter in the form ^ident. which limits the type of typar to the specified type. type abbreviation An alias or alternative name for a type. tuple expression An expression in the form expr1. without introducing a new type. typar must implement the interface.. structural type A record.. * tyn. or to a type that is derived from that type. If type is an interface. string literal A Unicode string or an unsigned byte array that is treated as a string. union. The elaborated form of a tuple type is shorthand for a use of the family of F# library types System.Tuple<_. rather than with any particular object. struct. string A type that represents immutable text as a sequence of Unicode characters. such as the text “option<_>”. symbolic operator A user-defined or library-defined function that has one or more symbols as a name.. symbolic keyword A symbolic or partially symbolic character sequence that is treated as a keyword.. exprn. syntactic type The form of a type specification that appears in program source code.

type definition kind A class. it hasno explicit function parameters. or abstract type. type extension A definition that associates additional dot-notation members with an existing type. U undentation The opposite of indentation. a placeholder for a specific type that is specified when the generic function. or parameter. type function A value that has explicit generic parameters but arity []—that is. and are supported by special syntax. record. and if that fails matches instead the second pattern. The underlying type of an enum must be sbyte. variable. uint64. rather than data. after expanding abbreviations. 243 . struct.type constraint A restriction on a generic type parameter or type variable that limits the types that may be used to instantiate that parameter. null constraints. comparison constraints and equality constraints. byte. method. union pattern The pattern pat | pat attempts to match the input value against the first pattern. measures can appear as parameters to other types and values. type parameter definition In a generic function. union type A type that can hold a value that satisfies one of a number of named cases. uint16. interface. delegate. can contain variables. type inference A feature of F# that determines the type of a language construct when the type is not specified in the source code. type inference environment The set of definitions and constraints that F# uses to infer the type of a value. however. or type. union. int16. function. int64. enum. value type constraints. such as kilogram or meters per second. measures are erased at runtime. underlying type The type of the constant values of an enumeration. or similar language construct. uint32. type variable A variable that represents a type. or type is instantiated. unit of measure A construct similar to a type that represents a measure. and are checked for consistency by the type-checker. Like types. Unlike types. Example type constraint include subtype constraints. measure. or char. Both patterns must bind the same set of variables with the same types. method. int32. have special equivalence rules. The kind of type refers to the kind of its outermost named type definition.

variable type A type of the form 'ident.unmanaged type The primitive types (sbyte. which represents the name of another type. or a non-generic structure whose fields are all unmanaged types. int64. which matches any input. float. and nativeptr<_>. uint64. uint32. nativeint. int16. and any value of a struct type. which limits the type of typar to a . byte. 244 . int32.NET value type. unativeint. unmanaged constraint An addition to a type parameter that limits the type to an unmanaged type. char. value type constraint A constraint of the form typar : struct. V value signature The “footprint” of a value in a module. floating-point numbers. and decimal). float32. W wildcard pattern The underscore character _. uint16. which indicates that the value exists and is externally visible. Value types include primitive integers. enumeration types. value type A type that is allocated on the stack or inline in an object or array.

127 accessibilities annotations for.fsscript extension. 44 anonymous variable type. 164 Measure. 232 #load directive. 140 MeasureAnnotatedAbbreviation. 156 AutoOpenAttribute. 93 active pattern results. 222 CLIEvent attribute. 95 && native pointer address-of operator. 188. 95 || operator. 124 ReflectedDefinition. 76 assignment expression. 229 attributes AbstractClass. 199 conformance in value signatures. 108 classes. 123 required unnamed. 127 abstract types. 26 __SOURCE_FILE__. 127. 147 RequiresQualifiedAccess. 190 block expressions. 63 array type. 18. 106 characters. 88 agents. 141 NoEquality. 43 basic types abbreviations for. 36 application expressions. 135 abstract members. 105 #indent. 76. 163. 172 RequiresExplicitTypeArguments. token. 64 byref arguments. 146 mapping to CLI metadata. 37 assemblies contents of. 156 AutoOpenAttribute. 212 DefaultValue. 18. 51 byref-address-of expression.fsx extension.Index # flexible type symbol. 188 let rec. 102. 163 automatic generalization. 53. 112 members in. 149 Literal. 183 ContextStatic. 127 AllowNullLiteral. 83 AttributeUsage attribute. 218 EntryPoint. 27 | disjunctive patterns. 106. 163 in type definitions. 126. 72 _ wildcard pattern. 153 array expressions. 138. 44 AttributeUsage. 158 . 101 InternalsVisibleTo. 95 . 95 __LINE__. 78. 158 #nowarn directive. 173 arguments CLI optional. 158 . 41. 122 arity. 22 class types. 122 optional. 146 custom. 43 bindings let. 229 AllowNullLiteral attribute. 82 & byref address-of operator. 86 address-of expressions. 108 additional fields in. 76 assertion expression. 147 grammar of. 201 CLI pointer types. 42 CLI methods.ml extension. 163 AutoOpen.mli extension. 133 CompilationRepresentation. 156 assert. 149 active pattern functions. 42 ThreadStatic. 42 AbstractClass attribute. 221 AutoSerializable attribute. 27 __SOURCE_DIRECTORY__. 221 binding. 72 bprintf function. 86 binding site. 40 OptionalArgument. 188 recursive. 73 = function. 18 . 86 array sequence expression. 218 VolatileField. 116 SealedAttribute. 156 referenced.fs extension. 78. 68 && operator. 162 equality. 12 AutoOpen attribute. 159 % operator. 65. 73 . 126. 232 :: cons pattern. 112 emitted by F# compiler. 124 named. 145 conditional compilation. 81 RequireQualifiedAccess. 82 %% operator. 158 . 71 asynchronous computations. 129 245 . 107.fsi extension. 111 class/end tokens. 68 case names. 146 unrecognized by F#. 132 GeneralizableValue. 129 comparison. 232 . 198 byref pointers. 68 & conjunctive patterns. 68 AddressOf expressions. 59 binding expressions. 221 CLIEvent. 149 default annotation for modules. 78. 188 member. 108 base type. 84. 146 location of modifiers. 18.

79 member. 39. 88 of array expressions. 45 DefaultValue attribute. 148 static. 39 dependency of. 67 delegate type. 88 of try-with expressions. 110 done token. 63 assertion. 88 of union cases. 121 custom attributes effect on signature checking. 229 events. 183 conditional compilation. 40 equational. 50 evaluation of. 184 struct. 101 CustomComparison attribute. 162 EntryPoint attribute. 51 delayed. 51 constants with measure annotations. 186 reference type. 198 dispatch slot inference. 85 of value references. 187 member. 57 delegate constraint. 87 of dynamic type-test expressions. 159 line. 56. 126 exception definitions. 87 event types. 202 compare function. 79 inflexible type. 133 evaluation of active pattern results. 87 of field lookups. 133 CustomEquality attribute. 67 deterministic disposal. 76 assignment. 85 of object expressions. 75 dynamic coercion expressions. 132 declarations base type. 42 deterministic disposal expression. 41 flexible type. 42 equality attributes. 82 expressions address-of. 86 of binding expressions. 42 interface. 135 comparison attributes. 159 lexical. 145 COMPILED compilation symbol. 231 compilation order. 76 block. 87 dynamic type-test expressions. 26 246 preprocessing. 132. 79 directives #load. 88 of static coercion expressions. 20. 80 elaborated. 18. 37 comparison. 39 equality. 83 . 87 elif branch. 86 of for loops. 219 execution of F# code. 38 nullness. 133 enumeration. 20 dispatch slot checking. 135 CompareTo. 86 of method applications.comments. 65 array. 64. 139 constrained types. 73 constant. 68 application. 164 in type definitions. 146 control flow expression. 42 default initialization. 186 solving. 79 dynamic coercion. 72 copy-and-update record expressions. 86 of AddressOf expressions. 185 explicit declaration of. 158 #nowarn. 40 EqualityConditionalOn constraint dependency. 57. 86 of record expressions. 159 compiler directives. 57 Conditional attribute. 133 compatibility features. 183 ML compatibility and. 109. 73 constant expressions. 159 compiler. 133 comparison constraint. 37. 198 do bindings. 39 delegate implementation expression. 80. 115 enumerable extraction. 57 conditional. 116 exceptions. 127. 57 delegate implementation. 45. 40 ContextStatic attribute. 74 enums. 37 constraints. 86 of function applications. 86 of dynamic coercion expressions. 39 simple. 85 of function expressions. 73 entry points. 40 current inference. 72 builder. 112 delayed expression. 159 computation expression. 116 delegates. 85 of while loops. 162 enum types. 35 default constructor. 20. 132 equality constraint. 87 of try-finally expressions. 80 dynamic type-test. 71 binding. 73 else branch. 55 curried form. 157 CompilationRepresentation attribute. 49. 39 delegate. 49 computation. 78. See array expression array sequence. 38. 186 subtype. 58 checking of. 86 of sequential execution expressions. 197 dispatch slots. 231 conditional expressions. 40 ComparisonConditionalOn constraint dependency. 80. 185 unmanaged. 160 expression splices.

18 ML compatibility and. 66 operator. 232 parsing. 148 long. 188. 149 intrinsic extensions. 229 implementation files anonymous. 75 function. 45 of objects. 209 indexer properties. 73 if/then/else expression undentation of body. 63 lookup. 209 GeneralizableValue attribute. 47 try-finally. 131 hidden tokens. 55. 55 list. 72 shortcut and. 167 null. 86 format strings. 199 dispatch slot. 135 247 hashing. 69 member constraint invocation. 77 indentation. 157 contents of. 52 INTERACTIVE compilation symbol. 109 ambiguous. 42 internal accessibility. 109. 104 kind of type definition. 79 syntactical elements of. 93 undentation of. 68 lazy computations. 78. 190 function expressions. 160 instance members. 67. in classes. 70 name resolution in. 203 identifiers. 34 guarded rules. 118 field lookups. 231 symbolic. 147 generalization. 53 recursive binding. 202 incremental. 209 immutability. 159 interface type definitions. 43. 52 type-annotated. 204 rules for. 113 interface types. 117 defined by C#. 121 inference arity. 157 implementation members. 221 F# base. 73 slice. 108 static. 232 files implementation. 172 filename extensions. 75 extension members. 63 list type. 30 OCaml keywords as. 53 list sequence. 75 tuple. 146 . 183 flexible types. 51 range. 43. 189 static. 78 reraise. 79 while-loop. 42 late binding. 86 fields additional. 148 in token. 202 line directives. 23 kind anonymous. 193 generic types. 21 local names for. 70 ground. 193 GetHashCode. 105 floating type variable environment. 135 GetSlice. 145 mutable. 76 sequence. 35 for loop. 75 for loops. 130 interface/end tokens. 202 balancing rules for. 62 sequence iteration. 26 list expression. 128 import declarations. 32 quoted. 49. 26 if statement. 228 Literal attribute. 86 function values. 64 object. 149 internal type abbreviations. 18. 78. 53 list sequence expression. 10. 85 function definitions. 112 name resolution for labels. 119 compilation as static method. 117 keywords OCaml. 73 sequential execution. See object expressions object construction. 74 sequential conditional. 206 disabling.for loop. 127 integer literals. 68 parenthesized. 35 function applications. 221 lightweight syntax. 97 hash function. 73 shortcut or. 105 InternalsVisibleTo attribute. 72 pattern-matching. 43 inherit declaration. 229 let bindings. 157 signature. 73 precedence in. 64 fprintf function. 110 libraries CLI base. 113 initialization. 231 replacement of. 11 immutable collection types. 64 fresh type. 113 interfaces. See signature files flexibility. 188 in modules. 12 functions active pattern. 62 record construction. 70 static coercion. 197 inference variables. 76 try-with.

222 nativeptr-address-of expression. 138. 140 defined.FSharp. 141 measures. 89 offside contexts. 31 splicing. 93 . 207 operations underspecified results of. 123 methods overloading of. 190 signature conformance for. 222 building blocks of. 174 unqualified. 203. 205 offside limit. 145 name resolution in. 141 Measure attribute. 226 math. 225 option type. 224 checked arithmetic.Core. 140 erasing of. 67 operators address-of. 108 additional. 134 objects initialization of. 12 pattern-matching expression.FSharp. 228 Microsoft. 210 mscorlib. 36. 119. 106. 174 lookup expressions. 122 optional arguments to. 24. 167 opened for F# code. 68 NoComparison attribute. 82 symbolic. 221 native pointer operations. 204 offside rule. 221 mutable. 231 module declaration. 28 object transformation. 117 intrinsic. 227 parallel execution. 132 null. 225 overloaded conversion functions.Equals. 232 names of. 166 248 adding items to.FSharp. 141 member constraint invocation expressions. 125 overriding. 225 generic equality and comparison. 31 input and output handles. 143 name resolution in. 224 ML compatibility and. 68 function pipelining and composition. 44 null expression. 14. 31 typeof and typedefof. 204 exceptions to. 157 namespace declaration groups. 180 parenthesized expressions. 148 active pattern definitions in. 111 primary. 89 operator expressions. 167 signature of. 226 precedence of. 90 active. 66 object constructors.Core.Core.option. 221 Microsoft. 102 defining. 228 mlcompatibility option. 125 processing of definitions. 69 mailbox processor. 140 measure parameters. 141 MeasureAnnotatedAbbreviation attribute. 83 method applications. 172 name resolution. 108 object expressions. 147 defining. 42 basic types and annotations for.FSharp. 223 bitwise. 230 Microsoft. 72 pattern matching. 157 modules abbreviations for. 52 numeric. 121 named arguments to. 72 name environment.Collections.Core. 148 let bindings in. 166 namespace declaration. 223 Microsoft. 145 undentation of. 35. 223 infix.FSharp. 176 item-qualified. 68 basic arithmetic. 64 NullReferenceException. 230 nativeptr type. 57 Microsoft.NativeIntrop. 189 mutable values. 133 NoEquality attribute. 121 curried.literals integer. 227 default definition of. 24 string. 22 lookup expression-qualified. 70 member definitions. 143 grammar of. 139 type definitions with. 24 object construction expression. 85 numeric literals. 140 generalization of. 183 method members. 108 physical identity of. 119 extension. 138 constraints on. 143 namespaces. 206 offside lines. 152 members. 229 measure annotated base types. 83 ParamArray conversion. 32 prefix. 228 OptionalArgument attribute. 155 memory model. 86 Object. 85 method calls conditional compilation of. 145 do bindings in. 188 member signatures.Operators.list. 137 defining. 140 relations on. 226 pair. 74 patterns. 73 pattern-matching function. 109 mutable bindings. 89 references to. 124 overflow checking. 170 naming restrictions for.dll. 56. 117 name resolution for.

35 meanings of. 35 System. 76. 95 pointer. 158 Sealed attribute. 132 StructuralComparison attribute. 91 wildcard. 31 syntactic types. 152 type definitions. 42 structural equality. 152 value. 42 sequence expression. 231 of function applications.Tuple. 96 union case. 153 module. 151 anonymous. 230 static coercion expressions. 20 printf. 34 named. 72. 210 of type applications. 97 list. 119 static types. 55 evaluation of. 79. 95 conjunctive. 81 reflection. 145 of namespace declaration groups. 62 rec. 78 recursive bindings. 109 record construction expression. 106 members in. 170 named. 211 type definition group. 119. 34. 116 reraise expressions. 146. 36 type fresh. 114 structs. 52 System. 51 precedence differences from OCaml. 160 static members. 23 strongly typed quoted expressions. 95 literal. 165 System.Type objects. 74 sequential conditional expressions. 51 range expressions. 88 249 shortcut and expression. 105 property members. 96 simple constant. 152 signature files. 78. 152 slice expressions. 41. 70 source code files. 97 as. 229 printf function. 211 preprocessing directives. 88 resolution function application. 152 member. 104 type annotated patterns. 53 record expressions copy-and-update. 165 ReflectedDefinition attribute. 133 StructuralEquality attribute. 106 record types. 73 signature elements. 106 SealedAttribute attribute. 95 disjunctive. 76 evaluation of. 153 declarations of. 57 System. 41 abstract members in. 92 name resolution for. 127 checking of. 102 delegate. 178 method application. 101 type definition signatures. 95 cons. 158 compilation order of. 36 statically resolved variable. 96 type annotations over-constrained. 203 try-finally expressions.Object. 73 shortcut or expression. 95 dynamic type-test. 147 RequiresQualifiedAccess attribute. 87 static initializer execution of. 149 quotations. 120. 178 script files. 92 variable-binding. 35 strings. 144 type definition. 132 symbolic operators. 115 struct/end tokens. 229 ThreadStatic attribute. 75. 88 try-with expressions. 22 format. 229 quoted expressions. 81 struct types default constructor in. 73 sequential execution expressions. 91 type-annotated. 96 guarded rules for. byref. 132 reflected forms. 97 record.array. 64 private accessibility. 64 stack allocation. 128 public accessibility. 172 RequiresExplicitTypeArguments attribute. 84 ReferenceEquality attribute.Reflection objects. 131 structural types. 106 scope of field labels. 64 newlines in. 62 sequence iteration expression. 26. 191 reference types zero value of. 158 signatures conformance of. 18 sprintf function. 86 record types automatically implemented interfaces in. 105 records. 188 type applications lexical analysis of. 91 null. 42 recursive binding expression. 36 type abbreviations. 146 tokens hidden. 165 text formatting. 188. 229 RequireQualifiedAccess attribute. 116 . 149 private type abbreviations. 190 recursive safety analysis. 88 tuple type. 157 contents of.

49 interface types of. 165 type-directed conversions. 23 virtual methods. See array type base.enum. 75 units of measure. 84 values arity conformance for. 44 exn (exception). 41 name resolution for. 114 type extensions. 67. 42 struct. 40 val specification. 206. 202 with/end tokens. 44 comparison of. 100 reference. 115 exception. 83 weakly typed quoted expression. 188 value references. See measures unmanaged constraint. 43 class. 84 undentation. 46 enum. 154 type inference. 128 VolatileField attribute. 116 dynamic conversion of. 85 union types. 42 variable. 87 while-loop expression. 42 renaming. 146. 124 delegate. 20 significance in lightweight syntax. 116 generic. See anonymous variable type array. See tuple type union. 35 type inference environment. 75 unmanaged. 34 name resolution for. 107 unions. 106 unit. See interface types logical properties of. 81 while loops. 165 types anonymous variable. 85 value signatures. 43 record. 131 condensation of generalized. 113 interfaces in. 100 location of. 20 zero value. 42 sealed. 11. 42. 43 type-annotated expressions. 104 type parameter definitions. 152 value types zero value of. 77. 41 type variables. 34 tuple. 83 signature conformance for. 105 function. 153 verbatim strings. 187 initial. 107 members in. 195 constrained. 172 rigid. 106 automatically implemented interfaces for. 209 union cases. 108 coercion of. 222 partial static. 98 interface. 79 typedefof operator. 36 implicit static members of. 34 structural. 124 typeof operator. 84 250 . 112 value definitions. 130 kinds of. 147 signature conformance for. 105 reference. 132 syntactic. 117 type functions. 40 value. 37 conversion of. 75 whitespace. 171 nativeptr. 107 compiled. 116 flexible. 189 runtime. 115 equivalence of. 104 runtime. 101 XML documentation tokens. 34 static. 41 grammar of. 153 processing of definitions. 42 unit type. 35 type kind inference. 36 zero value of.

Sign up to vote on this title
UsefulNot useful