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

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

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

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

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

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

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

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

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

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

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

we place a portion of our original script in a module.squares 5) printfn "Squares up to 10 = %A" (ApplicationLogic.Encode(s) = s member x.map square printfn "Squares up to 5 = %A" (ApplicationLogic. module ApplicationLogic = let numbers n = [1 . Other devices aimed at supporting software engineering include signatures. All examples in this specification use lightweight syntax. \Lu for any uppercase letter. n] let square x = x * x let squares n = numbers n |> List. For example: regexp+ regexp* regexp? [ char . 1. which serve as a way of organizing the name hierarchies for larger APIs.Console.Both object expressions and type definitions can implement interface types. and namespaces.squares 10) System. apostrophes and quotation marks enclose symbols that are used in the specification of the grammar itself.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. List. In the following example. For example.char ] [ ^ char . Regular expressions are given in the usual notation. which can be used to give explicit types to components. Where appropriate.2 Notational Conventions in This Specification This specification describes the F# language through a mixture of informal and semiformal techniques. For example. Therefore. here is an object expression that implements the interface type: let nullEncoder = { new IEncoding with member x. unless otherwise specified.ReadKey(true) Modules are also used in the F# library design to associate extra functionality with types. such as '<' and '|'. 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. the regular expression abstract matches precisely the characters abstract. For example. the following regular expression matches (+) or (-): '(' (+|-) ')' 16 ..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.map is a function in a module.

. indicates repetition of the preceding non-terminal construct and the separator token.' 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. For example. 17 . token token-name = regexp In the grammar rules. the notation element-nameopt indicates an optional element.. expr '. The notation ...' . '.

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

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

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

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

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 . 3.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. With the exception of the symbolic keywords (§3. In a UTF-8-encoded file. you can directly embed the following in a string in the same way as in C#: • • • Unicode characters Identifiers.6). as described in the previous section Trigraph specifications of Unicode characters. Literals may also be specified using C#-like verbatim forms that interpret \ as a literal character rather than an escape sequence. we refer to the token generated for a keyword simply by using the text of the keyword itself.String) and unsigned byte arrays (type byte[] = bytearray). the following token forms are reserved: token reserved-ident-formats = | ident-text ( '!' | '#') In the remainder of this specification.5 Strings and Characters String literals may be specified for two types: Unicode strings (type string = System.

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

example. 34un example.6). 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.8). 34u example. 34L example. 34y example.4./<=>@^|~ 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. example.token reserved-symbolic-sequence = ~ ` 3. 34ul example. 34n example.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. 34uy example. 3. &&& and ||| are valid symbolic operators.7 Symbolic Operators User-defined and library-defined symbolic operators are sequences of characters as shown below.. 34UL example.. 34uL 24 . The associativity and precedence of symbolic operators when used in expression forms is given in §4. Only the operators ? and ?<.may start with ?. 34us example. The quote-op-left and quote-op-right operators are used in quoted expressions (§6. except where the sequence of characters is a symbolic keyword (§3. 34s example. 34 0x22 0o42 0b10010 example. example. 34l example. regexp first-op-char = !%&*+-.

However the ―-‖ token is marked as an ADJACENT_PREFIX_MINUS token.0 For example. digit* digit+ (. (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 token steam is post-filtered by the following additional rules: (a) If the token stream contains .1 Post-filtering of Adjacent Prefix Tokens Negative integers are specified using the – token.0F or 3.8. Otherwise.0f For example. it is not applied for the token sequence ident . -3 becomes a single token ―-3‖. This rule is not applied for the sequence: i. For example.token ieee32 = | float [Ff] | xint 'lf' token ieee64 = | float | xint 'LF' token bignum For example. 0x00000000lf For example. the tokens remain. ii. -3. 25 .token where these tokens are adjacent then If token is a constant signed literal the pair of tokens is merged/. for example. 34742626263193832612536171N token decimal = (float|int) [Mm] token float = digit+ .ident when all three tokens are adjacent. 0x0000000000000000LF = int ('Q' | 'R' | 'Z' | 'I' | 'N' | 'G') For example. 3.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. token1 . digit* )? (e|E) (+|-)? digit+ 3. 3.

2 -> x + x ].‖.. 26 .”.” Tokens of the form token intdotdot = int. Without this rule.8. In the absence of line number directive.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. the name stdin is used... If no line directive has been given. 3. This construction is used in expressions of the form [for x in 1. such as 34. for example..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..Path.IO.2 Post-filtering of Integers Followed by Adjacent “.” to immediately follow an integer. the longest-match rule would consider this sequence to be a floating-point number followed by a “. 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.. For F# Interactive. C:\source.GetFullPath. the name is determined by that given to the command-line compiler in combination with System. The name of the current file is determined by the most recent line directive in the file. See §15 for a full specification and for the augmented grammar rules that take these into account. When using F# Interactive from tools such as Visual Studio. 3. recorded in debugging symbols. a line directive is implicitly added before each interactive execution of script fragment.10 Hidden Tokens Some hidden tokens are inserted by lexical filtering (§15) or are used to replace existing tokens. ―.3.8. 3. the first line of a file is numbered 1. Note: This rule allows “. are post-filtered to two tokens: one int and one symbolic-keyword.9 Line Directives The following directives adjust the source code filenames and line numbers that are reported in error messages.

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

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

[] 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 . op_RangeStep 29 . The compiled names are shown below.Symbolic operators and some symbolic keywords are given a compiled name that is visible in the compiled form of F# programs... op_Range . ..

8. the symbolic identifier <* has the compiled name op_LessMultiply: > < + * = ~ % .' ident long-ident-or-op := | long-ident '. '.String) String of type "string" (System. 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...' ident-or-op | ident-or-op 4. 16..2 Long Identifiers Long identifiers long-ident are sequences of identifiers separated by ‘.Nn where N1 to Nn are the names for the characters as shown in the table below. long-ident := ident '.' .String) 30 .Compiled names for other symbolic operators are op_N1. const := | sbyte | int16 | int32 | int64 | byte | uint16 | uint32 | int | uint64 | ieee32 | ieee64 | bignum | char | string | verbatim-string -.3 Constants The following table shows the constants that may be used in patterns and expressions.. : ( . 16. For example. Long identifiers long-ident-or-op are long identifiers that may terminate with an operator name. The individual lexical formats for the different constants are defined in §3. & | @ # ^ ! ? / . 32 and 64-bit signed integers --------- 32-bit signed integer 8. ) [ ] 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.’ and optional whitespace.

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

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

see §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.Note: This rule ensures that operators such as . 33 .2 and §15. In the preceding table.

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

35 . and constraint static-typars := ^ident (^ident or .5).1) and a type inference environment (§14.CLI default constructor constraint struct -. and a floating type variable environment (§14.5). and entire files. That is.unmanaged constraint delegate<type. 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. a set of current inference constraints is maintained.1 Checking Syntactic Types Syntactic types are checked and converted to static types as they are encountered.typar typar typar typar typar typar : : : : : : (new : unit -> 'T) -. .enum decomposition constraint unmanaged -. each static type is processed under input constraints Χ. typar-defn typar-constraintsopt > typar-constraints := when constraint and . expressions. The conversion from syntactic types to static types happens in the context of a name resolution environment (§14. 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. type> -. For the remainder of this specification we use the same syntax to represent syntactic types and static types. Specifically: array<int> not array < int > 5.. Type inference variables are either solved or generalized by type inference (§14.delegate decomposition constraint typar-defn := attributesopt typar typar-defns := < typar-defn. During conversion and throughout the checking of types.CLI non-Nullable struct not struct -.. Type inference variables and constraints are progressively simplified and eliminated based on these equations through constraint solving (§14. declarations. and results in output constraints Χ’..5)...5). possibly involving one or more explicit or implicit generic parameters.. as determined bylexical filtering (§15). Every expression in an F# program is given a unique inferred static type. 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..1).CLI reference type enum<type> -. The phrase ―fresh type‖ means a static type formed from a fresh type inference variable (§14.

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

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

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

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

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

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

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

43 . For example. 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. substitute the formal generic parameters of C for type-inst.5. generalization is applied (see §14.Object. Occasionally it is useful to give a more fully annotated representation of the inferred and generalized type information.MulticastDelegate System.3 Type Variables and Binding Static types may be type variables. For example: let id<'a> x'a = x'a 5. for some constructs (notably let and member bindings).4. During type inference.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. in that they contain type inference variables that have not been solved or generalized.Enum System. 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.Object System.Exception System.8).Object The specification of these types can be found in the CLI specifications and corresponding implementation documentation. then the resulting constraint set is normally the union of the constraints arising.Object The declared base type of the type definition if the type has one. However. If an expression is made up of multiple subexpressions. For example. else System.       Interface types Struct types Enum types Delegate types All array types Variable types System.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. Type variables without a binding site are inference variables. Type variables may also refer to explicit type parameter definitions.6. in which case the type variable is said to be rigid and have a binding site.ValueType System.Array System. given type C<'T> = 'T * 'T the binding site of 'T is the type definition of C.4. where formal generic parameters are substituted for the actual type instantiation type-inst.Object System. For generic types C<type-inst>.Object System. 5.4. static types may be partial.

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

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

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

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

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

49 .expr expr. with reference to procedures such as Name Resolution (§14. expr . expr slice-range := expr.expr '*' -.  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.5). the state of the inference procedure is left unchanged and the test fails.  The phrase ―the expression expr has type ty‖ means the initial type of the expression is asserted to be equal to ty.  The phrase ―type ty is known to .. In this case either an error is reported or.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 expr . 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. All expressions are assigned a static type through type checking and inference.1 Some Checking and Inference Terminology The rules applied when checking individual expression forms are described in the following subsections. .1) and Constraint Solving (§14.. Additionally:  Adding constraints to the type inference constraint set may fail if an inconsistent constraint set is detected (§14.5).yield result -.....range sequence -. if we are only attempting to assert the condition.‖ indicates that the initial type satisfies the given property given the current inference constraints. The initial type dictates some of the information available to resolve method overloading and other language constructs.. During type checking..

and ident = expr in expr  Applications of methods and functions (with static overloading resolved). 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 . With the exception of the extra resolution information noted above. expr Try-with: try expr with expr Try-finally: try expr finally expr The constructs required for the elaboration of pattern matching (§7).. for example. the elaborated form of System. array creation. elaborated forms are syntactically a subset of syntactic expressions. and in some cases (such as constants) the elaborated form is the same as the source form. reduced language that effectively contains a fully resolved and annotated form of the expression.Console.2 Elaboration and Elaborated Expressions Checking an expression generates an elaborated expression in a simpler. union cases. The elaborated expression carries more explicit information than the source form. for example.6.WriteLine("Hello") carries the information about exactly which overloaded method definition the call has resolved to. 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. 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. let x = 1 in x + x. 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..

9) and also form the basis for the expression trees returned by quoted expression (see §6.Char) (String) (System.01 1.The following constructs are used in the elaborated forms of expressions that make direct local and array assignments and generate ―byref‖ pointer values. The operations are loosely named after their corresponding primitive constructs in the CLI. For example: 3y 32uy 17s 18us 86 99u 99999999L 10328273UL 1.8). 6.Boolean) Simple constant expressions have the corresponding simple type and elaborate to the corresponding simple constant value. System.[expr]) Elaborated expressions are used as the basis of evaluation (see §6. when describing the process of elaborating compound expressions.IntPtr) (System.0f 1. string.01f 1.01e10 1.     Assigning to a byref-pointer: expr <-stobj expr Generating a byref-pointer by taking the address of a mutable value: &path.field) Generating a byref-pointer by taking the address of an array element: &(expr.BigInteger or user-specified) (System. Boolean and unit constants.Unit) (System. Generating a byref-pointer by taking the address of a record field: &(expr.Boolean) (System.String) (Verbatim Unicode.3.String) (Microsoft.1 Simple Constant Expressions Simple constant expressions are numeric.Core.3 Data Expressions 6.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. By convention. we omit the process of recursively elaborating sub-expressions.UIntPtr) (System. 1. 51 .FSharp.Numerics.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1) is applied to expression expr1 using a fresh expected result type ty. The overall elaborated expression is an assignment to a value reference path <-stobj expr2. producing an elaborated expression expr2.3). 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.9. producing an elaborated expression expr2.9 Assignment Expressions An expression of the form expr1 <.  A reference to a mutable field expr1a.member x.[expr1b] where expr1a has type ty[]. o In this case expr2 is then checked using expected result type ty. DefinitelyMutates) <-stobj expr2 (see §6.3).2. A modified version of Unqualified Lookup (§14. 71 . 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. The overall elaborated expression is an assignment to a field AddressOf(expr1a.4. thus producing an elaborate expression expr1. producing an elaborated expression expr2. o In this case expr2 is then checked using expected result type ty.[expr1b] . The overall elaborated expression is an assignment to a value reference &path <-stobj expr2.9.  A mutable value path of type ty. o In this case expr2 is then checked using expected result type ty.field with actual result type ty. The overall elaborated expression is an assignment to a field AddressOf(expr1a.  A array lookup expr1a.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. producing an elaborated expression expr2. DefinitelyMutates) <-stobj expr2 (see §6.  A reference to a value path of type byref<ty>.expr2 is an assignment expression.field. o In this case expr2 is then checked using expected result type ty.

6.3 and these are: s2.1.5 Control Flow Expressions 6. 3 Note: The . and an additional syntax rule for lightweight syntax applies (§15. 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).5. expr2 is a sequential execution expression. The expression expr2 is then checked with the same initial type as the overall expression. ty is asserted to be equal to unit.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. In this case.2 Sequential Execution Expressions An expression of the form expr1.x <.1 Parenthesized and Block Expressions An expression of the form (expr) is a parenthesized expression and begin expr end is a block expression. where “immediate” contents means the contents of a mutable value type. a warning rather than an error is reported.x <.1).3 s4. The expression expr1 is checked with an arbitrary initial type ty. expr2.sa. After checking expr1. For example: printfn "Hello".x <.x <. printfn "World".SA(2) 6. a $sep token is automatically inserted. In practice.5.sa. The expression expr is checked with the same initial type as the overall expression.3 s4.3 s3. this means that the token can be omitted for sequential execution expressions that implement functions or immediately follow tokens such as begin and (. If the assertion fails. 72 .sa <. The elaborated form of the expression is simply the elaborated form of expr. 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. Sequential execution expressions are a primitive elaborated form expr1. For example.

j -> printfn "j = %d" j | i. For example. If the operator is not immediately applied to two arguments.IntrinsicOperators.IntrinsicOperators.6.Core. 6.5 Pattern-Matching Expressions and Functions An expression of the form match expr with rules is a pattern-matching expression. For example: match (3.Core. 2) with | 1.FSharp.LanguagePrimitives. 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.(||) defined in the F# core library when applied to two arguments. 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. 2 -> printfn "i = %d" i | _ -> printfn "no match" 73 .LanguagePrimitives.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.4 Shortcut Operator Expressions Under default definitions.FSharp. 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.5. 6. then it is interpreted as a strict function that evaluates both its arguments before use.(&&) Microsoft. Pattern matching is used to evaluate the given expression and select a rule (§7). 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.5.

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

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

This means that assertions will not be triggered unless the DEBUG conditional compilation symbol is defined.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.Debug. Try-finally expressions are a primitive elaborated form.5.Assert(expr) Note: System.5. Expression expr2 is checked with arbitrary initial type.FSharp. Try-with expressions are a primitive elaborated form.11 Try-finally Expressions try expr1 finally expr2 is a try-finally expression. try failwith "fail" with e -> printfn "Failing".reraise defined in the F# core library.6 Binding Expressions 6.Diagnostics. 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.Exception.Operators.Assert is a conditional method call.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. The pattern matching clauses are then checked with the same initial type and with input type System. 6.5.Core. The expression assert expr is syntactic sugar for System.12 Assertion Expressions An expression of the form assert expr is an assertion expression. and a warning is given if this type cannot then be asserted to be equal to unit. 6.6. 6.Debug. 76 . 6.Diagnostics.Expression expr is checked with the same initial type as the overall expression. reraise() Note: The rules in this section apply to any use of the function Microsoft.

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

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

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

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

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

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

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

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

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

.... array-pat. Rules are attempted in order from top-to-bottom and left-to-right.... :? atomic-type. The syntactic forms of patterns are shown in the subsequent table... '|' rule -. (pat).. . .7 Patterns Patterns are used to perform simultaneous case analysis and decomposition on values in conjunction with the match. ...... pat-param ) | long-ident pat-param | pat-param : type | <@ expr @> | <@@ expr @@> | null pats := pat . . fun and let expression and declaration constructs... . pat |] record-pat := { field-pat .restricted to const. record-pat.pattern. try... .. 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 . . . list-pat.with. pat ] array-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.pat (pat) list-pat array-pat record-pat :? atomic-type :? atomic-type as ident null attributes pat list-pat := [ ] [ pat . .. pat-param ] | ( pat-param. field-pat rules := '|'opt rule '|' . null. .. field-pat } atomic-pat := pat -. long-ident. . _ field-pat := long-ident = pat pat-param := | const | long-ident | [ pat-param . function.. pat field-pats := field-pat . .

7.Operators. Note: The use of Microsoft. This reduces pattern matching to decision trees. the match fails.(=) taking the relevant match input and constant as arguments. Simple constant patterns have the corresponding simple type and elaborate to a call to the F# generic equality function Microsoft.1 may be used as a constant pattern with the exception of integer literals that have the suffixes Q. and CLI ordinal string equality is used for matching strings. During checking.1 Pattern Forms 7.1. the variable is assigned the same value and type as the value being matched. 7. I.1. N.Core.Patterns are elaborated to expressions through a process called pattern match compilation. Z. otherwise. 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.Operators.3.1 Simple Constant Patterns The pattern const is a constant pattern which matches values equal to the given constant. R. G.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. 91 .Core. The match succeeds if this call returns true. For example: let rotate3 x = match x with | 0 -> 2 | 1 -> 0 | 2 -> 1 | _ -> failwith "rotate3" Any constant listed in §6.FSharp.(=) means that CLI floating-point equality is used for matching floating-point values.FSharp.

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

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. The function accepts one argument (the value being matched).. and must return a value of type Choice<_..  (|CaseName|_|) arg1 . multi-case. 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 ... Other active pattern functions are not permitted. and must return a value of type option<_>.. n = %d" n | Negative n -> printfn "negative.1. The function accepts n+1 arguments (the last being the value matched).1..5) ensure that CaseNamei is associated with an active pattern function f in one of the following forms:  (|CaseName|) inp — Single case. and must return a value of type option<_>  (|CaseName1| . |CaseNamen|_|) are not permitted. 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|) inp — Multi-case. and can return any type. the limitation n ≤ 7 applies... The function accepts one argument (the value being matched). argn inp — Single case with parameters.5 Active Patterns If long-ident from §7. argn inp — Partial with parameters. In particular..7. partial functions (|CaseName1| ..1. and can return any type.  (|CaseName|_|) inp — Partial...  (|CaseName|) arg1 . In F# 2.0. The rules of name resolution in patterns (§14. The function accepts n+1 arguments (the last being the value matched)._> based on the number of case names.

the pat-params are interpreted as expressions that are passed as arguments to the active pattern function.Choice<ty1.Option<ty1> when _ is present... top-to-bottom reading of the entire pattern indicates that execution is required. Microsoft.|idN|) —or— (|id1|_|) where: id is idk for one of the identifiers in this list.. or Some v. If present. An active pattern function is executed only if a left-to-right. ChoicekOfN v. where tyin is the type of input being matched. When executed. along with any given parameters. The patterns are then converted to the syntactically identical corresponding expression forms and passed as arguments to the active pattern function f. the pattern argument pat is then matched against v. respectively.Core. Microsoft. 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..Core. the pattern matches if the active pattern function returns v... 94 . syntactically the pat-params are patterns and are limited to those forms shown in the grammar. then the pattern applies f to the input being matched. tyout must be:    ty1 when n = 1 and an underscore is not present.Assuming that the active pattern case name is associated with a function value f. For example. f is a value of function type tyin -> tyout.tyN> and _ is not present. To avoid ambiguities.FSharp. The name of f must be in one of the following forms: (|id1|.FSharp. The precise number of times the active pattern function is executed is implementation-dependent. When an active pattern function takes arguments.

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

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

data2) | _ -> failwith "unknown packet" 7.. data2) | [| "HeaderB".16 Guarded Pattern Rules Rules of the form pat when expr are guarded pattern rules. 2) with | (3.14 Array Patterns The pattern [|pat . data2 |] -> (data1. data1 |] -> (data1. Not all record fields for the type need to be specified in the pattern.1. . .let totalSize data = match data with | { Header = "TCP". 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. the following evaluates to 2 with no output. some F# types do use null as a representation.1. However. 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.8.4. Size = size. pat|] is an array pattern that matches arrays of the given length. For example. data2.Length * 12 | { Header = "UDP".Environment. Names = names } -> size + names. For example: let path = match System. data1.15 Null Patterns The pattern null is a null pattern that matches values represented by the CLI value null.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. 7. y) -> y 97 .1. unique F# record type. see §5. true) -> 0 | (_. 7. match (1. For example: let checkPackets data = match data with | [| "HeaderA".. x) when (printfn "not printed".

. ... 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 '|' .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 –. The grammar of type definitions is shown below.. '|' 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 ..side-effect binding 98 .8 Type Definitions Type definitions define new named types. * type ident : uncurried-sig -.binding attributesopt staticopt do expr -..nullary union case -.. record-field .n-ary union 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 -. pat) additional-constr-defn := attributesopt accessopt new pat as-binding = additional-constr-expr additional-constr-expr := stmt '.exception definition -.binding construction additional-constr-init-expr additional-constr-init-expr := '{' class-inherits-decl field-binds '}' new type expr -.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 '|' ..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 . ..sequence construction (before) if expr then additional-constr-expr else additional-constr-expr let val-decls in additional-constr-expr -. '|' enum-type-case enum-type-case := ident '=' const -.delegated construction -.' additional-constr-expr -. .enum constant definition -.additional constructor ------ concrete member abstract member override member override member value member 99 ...exception abbreviation delegate-type-defn := type-name '=' delegate-sig delegate-sig := delegate of uncurried-sig -.sequence construction (after) additional-constr-expr then expr -. type-defn-element primary-constr-args := attributesopt accessopt (pat...

member-binding := ident.7) Struct type definitions (§8..4) With the exception of type abbreviations and type extension definitions.3) Record type definitions (§8. 100 .opt binding -.12) Measure type definitions (§9.get curried-sig := args-spec -> . -> args-spec -> type uncurried-sig := args-spec -> type args-spec := arg-spec * .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..4) Union type definitions (§8.. type definitions define fresh.5) Class type definitions (§8.set set..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. * arg-spec arg-spec := attributesopt arg-name-specopt type arg-name-spec := ?opt ident : interface-spec := interface type For example: type int = System.8) Enum type definitions (§8.11) Type extension definitions (§8. distinct from other types.10) Exception type definitions (§8.method or property definition ident.opt ident with bindings -. named types.9) Delegate type definitions (§8.6) Interface type definitions (§8.

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

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

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

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

appear to refer to private abbreviations. Flexible type constraints may not be used in type definitions except in member signatures. For example. Note: Inferred types of public entities may. For example.y 105 . 8.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. 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. Likewise. For example. 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 this purpose. the following type is disallowed: type BadType = #Exception -> int // disallowed Type abbreviations may be declared internal or private. because they expand to a type variable that has not been named in the type arguments of the type abbreviation. 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. 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.x + this. For example: type R1 = { x : int. type Drop<'T. the following is not a valid type abbreviation.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. flexible type constraints may not be used on the right of a type abbreviation. in visual presentations of types.For example. y : int } member this.Sum = this.'U> = 'T * 'T // invalid: dropped type variableNote: This restriction simplifies the process of guaranteeing a stable and consistent compilation to generic CLI code. however these inferred types are considered equivalent to their expanded form.

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

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

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

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

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

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

and often only occur in generated code.8). side effects can be performed after the initialization of the fields of the object by using the additional-constr-expr then stmt form. 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. For example: type X = val a : (unit -> string) val mutable b : string new() as x = { a = (fun () -> x. 112 . the type of the field must admit default initialization (§5.y:int) = // This additional constructor has a side effect after initialization. new(x) = PairOfIntegers(x. 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.5 Additional Fields in Classes Additional field declarations indicate a value stored in an object. For example: type PairOfIntegers(x:int.b).4. For classes without a primary constructor. Note that precisely one additional-constr-init-expr occurs for each branch of a construction expression. If this parameter is true.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 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. They are generally used only for classes without a primary constructor.6. 8. This parameter has a default value of true. x) then printfn "Initialized with only one integer" The name of the object parameter can be bound within additional constructors. or for mutable fields with default initialization. y) = {x = x. For example: type PairOfIntegers = val x : int val y : int new(x. b = "b" } A warning is given if x occurs syntactically in or before the additional-constr-init-expr of the construction expression.

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

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

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

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

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

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

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

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

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

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

8.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.Instance)>] member x.14.IsNone = match x with None -> true | _ -> false member x. 8.10 Members Represented as Static Members Most members are represented as their corresponding CLI method or property.Instance) on the member.UseNullAsTrueValue)>] type option<'T> = | None | Some of 'T member x.Publish 8.[<CLIEvent>] member self. For example. 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 . For example: type IX = abstract M : int -> int A class definition may contain abstract member definitions.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. This happens when either of the following is true:  The type definition uses null as a representation by placing the CompilationRepresentation(CompilationRepresentationFlags.ChannelChanged = channelChanged.IsSome = match x with Some _ -> true | _ -> false [<CompilationRepresentation(CompilationRepresentationFlags. The Item property is represented as an instance property.Item = match x with | Some x -> x | None -> failwith "Option. However.13.  The member is an extension member.Item" The IsNone and IsSome properties are represented as CLI static methods. consider the following type: [<CompilationRepresentation(CompilationRepresentationFlags. 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.Reflection.UseNullAsTrueValue) attribute on the type declaring the member.

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

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

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

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

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

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

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

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

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

anonymous measure measure-literal-simp const := . 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 -.parenthesized measure. measure-literal-atom := long-ident -. Units of measure. 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>.power of measure.variable measure.implicit product.9 Units Of Measure F# supports static checking of units of measure.reciprocal.product. they differ from types in that they play no role at runtime (in fact.parenthesized measure. such as 'U / 'V 137 .g. can contain variables (as in float<'U>). such as 'U -.named measure e. they are erased). such as m^3 measure-literal-seq := measure-literal-power measure-literal-power measure-literal-seq measure-literal-simp := measure-literal-seq -. kg ( measure-literal-simp ) -.power of measure. such as /s 1 -.3) is extended to support numeric constants with units of measure and the syntax of types is extended with measure type annotations. such as 'U * 'V -. such as m * s^3 measure-literal-simp / measure-literal-simp -. and are supported by special syntax. However.named measure. or measuresfor short. add<m>).. The syntax of constants (§4. such as m s^-2 measure-literal-simp * measure-literal-simp -. such as m^3 -. such as (N m) measure-literal-power := measure-literal-atom measure-literal-atom ^ int32 -.simple measure. such as (N m) -.quotient. such as 'U 'V^3 -.dimensionless measure-literal := _ -.implicit product.product. and are checked for consistency by the type-checker. such as m/s^2 / measure-literal-simp -. they obey special rules of equivalence (so N m can be interchanged with m N). such as kg -. vector<m/s>..quotient.

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

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

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

They explicitly implement System.IComparable.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. the type-checker distinguishes between type parameters and measure parameters by assigning one of two sorts (Type or Measure) to each parameter. System. for example.IEquatable<float<'u>> (so that you can invoke. System. Reflection is with respect to erased types. instead they are erased.Radius:float<'U> } type Disc<[<Measure>] 'U> = { Center:Vector<'U>.IFormattable.ValueType. measure parameters are not exposed in the metadata that is interpreted by the runtime. 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. System. 9. instantiated at the given type—for example. CompareTo after an explicit upcast).6 Measure Parameter Erasure In contrast to type parameters on generic types.IConvertible. Norm:Vector<1> } type SceneObject<[<Measure>] 'U> = | Sphere of Sphere<'U> | Disc of Disc<'U> Internally. and corresponding generic interfaces. 141 . Overload resolution is with respect to erased types. 9.IComparable<float<'u>> and System. Erasure has several consequences:    Casting is with respect to erased types. rejecting ill-formed types such as float<int> and IEnumerable<m/s>.  Their compiled form is (through erasure) the corresponding primitive type. 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>. This is used when checking the actual arguments to types and other parameterized definitions.

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

. Declaration elements are processed with respect to an environment..1 Namespace Declaration Groups With respect to naming. module-elem access := private internal public 10. These also have corresponding forms in signatures. New components may contribute entities to existing namespaces. modules and types in an F# program are organized into namespaces. Each such contribution to a namespace is called a namespace declaration group.elements within a namespace -.. a file may contain multiple namespace declaration groups. and module definitions.side-effect binding compiler-directive-decl := # ident string . which finally contain expressions.. namespace-decl-group := namespace long-ident module-elems namespace global module-elems -. each of which defines types and modules.1. F# source code units are made up of declarations. 143 . and the types and modules may contain members and―let‖ bindings. The definition of the various elements of an environment is found in §14.10 Namespaces and Modules F# is primarily an expression-based language. string module-elems := module-elem .binding -.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 –. However. For example. some of which can contain further declarations. Declarations are grouped using namespace declaration groups. type definitions.

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

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

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

For example: let empty<'T> : (list<'T> * Set<'T>) = ([]. and user-defined numeric literals. and computation expressions because ―let‖ bindings at these points may not include explicit generic parameters.6. unsigned native integer literals. For example: let mutable count = 1 let r<'T> = (count <.o a simple constant expression.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. for example. Type functions should. ref ([] : 'T list). Type functions are rarely used in F# programming. For example.Type val sizeof<'T> : int module Set = val empty<'T> : Set<'T> module Map = val empty<'Key. no explicit function parameters) is called a type function. type functions may still perform computations. Pure functions whose result is independent of inferred type arguments.'Value> Type functions are typically used for:   Pure functions that compute type-specific information based on the supplied type arguments. and are generally attributed with one of the RequiresExplicitTypeArguments and GeneralizableValue attributes. 10.count + 1). Type functions are treated specially with respect to generalization (§14. However.empty) A value with explicit generic parameters but arity [] (that is. though are very convenient when necessary. empty sets and maps. native integer literals. That is. expressions. be used only for computations that do not have observable side effects. with the exception of (). Some example type functions from the F# library are: val typeof<'T> : System. BigInteger literals. Type functions may not be defined inside types. 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.8) and signature conformance (§11.3 Type Function Definitions in Modules ―Let‖ bindings of values within modules may be given explicit generic parameters. 147 .2. Set.2). 10. as a rule. // 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.'Value> : Map<'Key.2.. or o a reference to another literal. byte array literals.

9.FSharp. System. 148 .FSharp.Collections. For example: module Ops = Microsoft. ty is asserted to be equal to unit.let (|A|B|C|) x = if x < 0 then A elif x = 0 then B else C introduces pattern tags A. 10. For example: open Microsoft..Application.2. ―Do‖ bindings may be given attributes. Fn] by Name Resolution in Module and Namespace Paths (§14.1. These make elements of other namespace declaration groups and modules accessible via unqualified names.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.Run(form) [<STAThread>] do main() 10. 10.2). B and C into the PatItems table in the name resolution environment.Windows.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..3 Import Declarations Namespace declaration groups and module definitions can include import declarations.Generic may resolve to one or more namespace declaration groups—one for each assembly that contributes a namespace declaration group in the current environment.Core. . For example: let main() = let form = new System.Forms.fsx and . This warning is suppressed for plain expressions without do in script files (that is.Windows.Form() System..1.4 Module Abbreviations Module abbreviations define a local name for a module long identifier.Forms.fsscript files). a warning rather than an error is reported. Each Fi is added to the environment successively using the technique specified in §14. An error is given if any Fi is a module has the RequireQualifiedAccess attribute. After checking expr. If this attempt fails. For example.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. .

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

X = 1 On explicit property get/set in classes: member v.Item with private get i = 1 and private set i v = () On type representations: type Cases = private | A | B 150 .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..

local alias for a module -..submodule signature -..... and . and specifies the functionality that is implemented by its corresponding implementation file.locally import contents of a module module-signature-elements := module-signature-element . 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 -.. It also serves to hide functionality contained within its corresponding implementation file.11 Namespace and Module Signatures A signature file contains one or more namespace or module signatures. 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 . 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 .

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

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

rather than a compile-time function value.[x] else let res = x * x myTable. [] 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. For example: let f = let myTable = new System. by default.ContainsKey x then myTable. The first signature can only be satisfied by a true function. For example.8).Collections. Thus. 154 .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. 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.2. that is. rather than to fields that are function values. generalizable (§14.The parentheses indicate a top-level function which might be a first-class computed expression that computes to a function value. the implementation let empty<'T> : list<'T> = printfn "hello". 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.Dictionary<int.[x] <. The rationale for this interpretation of types in value and member signatures is that CLI interoperability requires that F# functions compile to methods.6. the implementation must be a lambda value as in let F x = x + 1 Note: Because arity inference also permits right-hand-side lambdas. 11.1.Generic.2 Signature Conformance for Type Functions If a value is a type function.int>(4) fun x -> if myTable. then its corresponding value signature must have explicit type arguments.

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

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

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

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

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

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

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

The function is asserted to have type string[] -> int before checking.5.Likewise.exe) file may additionally contain an explicit entry point. 162 .0 "two" enum<System. and this function must be the last declaration in the last file processed on the command line.GetCommandLineArgs(). all of the following represent bindings with non-observable initialization.defaultof<int> Unchecked.2 Explicit Entry Point The last file specified in the compilation order for an executable (. the static initializer for the file in which the function is declared is immediately forced. minus the first entry in that array.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. If this assertion fails. 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. 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. It cannot be a member. an error is reported. The function becomes the entry point to the program. The function may be in a nested module.DayOfWeek. and the body of the function is then evaluated.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.  At runtime.Environment. When evaluated.Friday 1.

attribute >] attributes := attribute-set .Bar() = 1 163 . . attribute-set attribute-target := assembly module return field property param type constructor event 13... Custom attributes can be applied only to certain target language constructs according to the AttributeUsage attribute.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. 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.Obsolete("don't use me")>] private () = member x. This chapter describes these mechanisms for F#. .Reflection libraries. These are added to the corresponding elaborated and compiled forms of the constructs to which they apply.Obsolete("don't use me")>] () = member x. which is found on the attribute class itself. Custom attributes are not permitted on ―let‖ bindings in expressions or computation expressions. Attributes are given by the following grammar: attribute := attribute-target:opt object-construction attribute-set := [< attribute . They also allow entities to be attributed by static data. An error occurs if an attribute is attached to a language construct that does not allow that attribute. and these attributes may be accessed and read by tools and running programs...Bar() = 1 type Foo2 [<System.

The compiled assembly. then give a warning and ignore the attribute in the implementation. A custom attribute on a type type is compiled to a custom attribute on the corresponding CLI type definition. and not for ―let‖-bound function definitions.Forms.  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. o If ASig contains an attribute that has the same attribute type but is not an exact match.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. let main() = let form = new System. then ignore the attribute in the implementation. The compiled module. custom attributes attached to items in F# signature files (. and continue checking.Custom attributes are mapped to compiled CLI metadata as follows:   Custom attributes map to the element that is specified by their target. unless the target of the attribute is field.  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. 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. 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.  Check each attribute in AImpl against the available attributes in ASig. Custom attributes on generic parameters are not propagated. 164 . in declaration order. and likewise for the assembly.Forms. remove the attribute from ASig.Windows. 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.Windows.Application. the main method takes precedence. If it is valid for the attribute to be attached to either the main method or the assembly. if a target is given. For example.1 Custom Attributes and Signatures During signature checking. o If ASig contains an attribute that is an exact match after evaluating attribute arguments. whose System. in which case it becomes a custom attribute on the underlying backing field for the CLI property that is named _F.1.  By default.Type object is returned by typeof<type>.Run(form) [<STAThread>] do main() 13.Form() System. the STAThread attribute should be placed immediately before a top-level “do” binding.

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

if a module called System.14 Inference Procedures 14.Collections is declared or in a referenced assembly. If multiple assemblies are referenced.Tuple with n = 2 returns a single type. in the default type-checking environment. Each signature is either a namespace declaration group signature or a module signature.  ExprItems: a table that maps names to items.C. 166 .Collections may map to one namespace declaration group signature for each referenced assembly that contributes to the System.1 Name Environments Each point in the interpretation of an F# program is subject to an environment. For example. This returns at most one type.Collections namespace. This may return multiple types. For example.1 Name Resolution 14. the resolution of System. and to a module signature. ModulesAndNamespaces: a table that maps long-idents to a list of signatures. Two queries are supported on this table: o Find a type by name alone. This matters only if ambiguities arise in referencing the contents of assemblies—for example. 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. then the assemblies are added to the name resolution environment in the order in which the references are specified on the command line. For example. 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. in the default typechecking environment.Tuple returns multiple tuple types. the resolution of System. Find a type by name and generic arity n.1. The environment encompasses:   All referenced external DLLs (assemblies). 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. if two assemblies define the type MyNamespace. System.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

str) M(str. Details: Given a type inference context. because the target type is a variable type: M(obj. d :'b) = 1 let obj = new obj() let str = "" these pass type-checking: M<obj>(obj.This means that F# functions whose inferred type includes an unsealed type in argument position may be passed subtypes when called.Y = i let d = new Derived(7) let f (b : Base) = b. without the need for explicit upcasts. For example: type Base() = member b. 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 . given the following: let M<'b>(c :'b. For example. obj) M(str.. obj) 14.X = 1 type Derived(i : int) = inherit Base() member d. It is invoked every time a constraint is added to the set of current inference constraints at any point during checking. M<obj>(str.. M<obj>(str. M<obj>(obj.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. str) str) obj) obj) str) These do not. M(obj. but before any arguments are checked.5 Constraint Solving Overview: Constraint solving is the process of processing (―solving‖) non-primitive constraints down to primitive constraints on type variables. or type) : (member-sig) typar : (new : unit -> 'T) typar : struct typar : unmanaged 184 .

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

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

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

For example: type foo = Id of int let Id x = x 188 . (+). cos. For example. patn = expr 14. In particular:ident pat = expr This can be interpreted as either a function or value binding.5. Each binding is either a function definition: inlineopt ident1 pat1 . System. int. This is deliberate: in the CLI. This mechanism is used to implement the extensible conversion and math functions of the F# library including sin. resolutions that do not give such a warning are preferred over ones that do give such a warning. float. as the grammar shows: | ident pat = expr | pat = expr -. 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. In addition.function binding -. 14.. generalized and elaborated.Note: The decimal type is included only for the Sign static member.. 14. patn :opt return-typeopt = rhs-expr or a value definition. 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 . and member bindings are checked.value binding This ambiguity is always resolved as a function binding.6 Checking and Elaborating Bindings This section describes how let. 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. and (-). let rec.1 Ambiguities in Bindings An ambiguity exists between the two different kinds of ―let‖ bindings.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.6. ―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.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 resulting elaborated bindings are:   ident <typars1> = expr body-expr. This check results in zero or more identifiers ident1 ... use the following syntax‖ let v = if 3 = 4 then Id "yes" else Id "no" let (Id answer) = v 14.8) and yields generic parameters <typarsj>. tym. 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. identm..2 Mutable Bindings ―Let‖ bindings may be marked as mutable.  Otherwise.    The expression rhs-expr is checked against initial type ty. Value definitions may not be inline. where tmp is a fresh identifier and each expri arises from the compilation of the pattern pat (§7) against input tmp.     tmp <typars1… typarsn> = expr ident1 <typars1> = expr1 … identn <typarsn> = exprn 189 . In addition: o o  All identj must be distinct. the resulting elaborated bindings are the following. To ensure that this is resolved a pattern.In this case. each of type ty1 . and are similarly implicitly dereferenced. giving an elaborated form expr. For example: let mutable v = 0 while v < 10 do v <. 14.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).6.9).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. Each identi (of type tyi) is then generalized (§14.6.. If pat is a single value pattern.

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

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. or data construction expression whose field initialization expressions are each safe.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. As a field initializer for an immutable field of a record type that is defined in the current assembly. A record. Any object expression that implements an interface. list. 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. the record fields must be initialized in the same order as their declared type. where runtime checks are inserted to locally enforce initialization.Within recursive groups. For example. including interfaces whose member bodies include references to variables being defined recursively. In the case of record fields that contain recursive references to values being bound. A value that is not being recursively bound.6.7 Recursive Safety Analysis A set of recursive bindings may include non-function values. consider the following declaration: let rec countDown count x = if count > 0 then let a = countDown (count . A right-hand side expression is safe if it is:   Any function expression. as described later in this section. 191 . any use of an ungeneralized recursive binding results in immediate constraints on the recursively bound construct.8). tuple. then early generalization applies and recursive calls at different types are permitted (§14. For example: module M = let rec f<'T> (x:'T) : 'T = let a = f 1 let b = f "Hello" x 14. 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). including ones whose bodies include references to variables that are defined recursively. 0) -> r).6.     A lazy delayed expression. If a binding is given a full signature. n) This raises the possibility of invalid recursive cycles that are exercised by strict evaluation.

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

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

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. functions and members. where the record contains no mutable fields A union case expression. all of whose arguments are generalizable     194 . all of whose elements are generalizable A record expression. Informally. (2) Determine a set of variables U that may not be generalized because they are free in the environment or present in ungeneralizable bindings.turn. (3) Remove these from the set.  Any type inference variable that appears in a constraint that itself refers to an ungeneralizable type variable. as described later in this section.  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. that is: (1) Start with all variables that are candidates for generalization. checked bindings until a stable set of generalizable bindings remains. The variable is a type parameter copied from the enclosing type definition (for members and ―let‖ bindings in classes). The variable is explicitly declared as a generic parameter on an item.  Any type inference variable in an inferred type in the ExprItems or PatItems tables of env. (4) Add to U any inference variables with a constraint involving one of the variables from U. cannot be generalized. unless that binding is marked inline. Note: Generalizable type variables can be computed by a greatest-fixed-point computation. 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.  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. o Ungeneralizable type inference variables are:  Any type inference variable ^typar that is part of the inferred or declared type of a binding. (5) Repeat steps (2) through (4). or in any inferred type of any module in the ModulesAndNamespaces table in env. all of whose elements are generalizable. This is an iterative (greatest fixed point) computation where bindings are repeatedly removed from the set of ungeneralized.

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

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

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

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

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

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

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

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

[i] <. These are shown below.create numLetters 0 let data = "The quick brown fox" for i = 0 to data.code c .Char.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 .syntax error 15. 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.[i] + 1 end done. let ArraySample() = let numLetters = 26 let results = Array.warning FS0058: possible incorrect indentation: this token is offside of context at position (2:1) // The "|" markers in patterns must align.Chars(i) in let c = Char.[i] <. printfn "done!" // When the light syntax option is // enabled the scope of if/then/else is implicit from // indentation.printfn "done!" done.2 Inserted Tokens Some hidden tokens are inserted by lexical filtering.1 do let c = data. 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.[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.ToUpper(c) if c >= 'A' && c <= 'Z' then let i = Char.Length . 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.1.Length .1.ToUpper(c) in if c >= 'A' && c <= 'Z' then begin let i = Char. let x = 1 let y = 2 <-.results. let f () = match 1+1 with | 2 -> printf "ok" | _ -> failwith "no!" <-.results. // The first "|" should always be inserted.Char.1 do let c = data. 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.code 'A' results.Chars(i) let c = Char.unmatched 'let' let z = 3 <-.code c .create numLetters 0 in let data = "The quick brown fox" in for i = 0 to data.code 'A' in results.

else.4 Offside Lines Lightweight syntax is sometimes called the ―offside rule‖. 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 start of a let.. 204 . For example. 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 .1. } and end) automatically terminate offside contexts up to and including the context introduced by the corresponding ―opening‖ token. in particular at the following places:   The column of the first token after the then in an if/then/else construct.| 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. a ―context‖ is pushed. ―Closing‖ bracketing tokens (). offside lines occur at column positions..   The column of the first token of a (. -> and with (in a match/with or try/with) and with (in a type extension)..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).. an = token associated with let introduces an offside line at the column of the first non-whitespace token after the = token. module-signature-element $end module-signature +:= | module ident = $begin module-signature-body $end 15. { or begin token.1. 15.   When a column position becomes an offside line. In F# code. The column of the first token after a try. Other structured constructs can also introduce offside lines. and uses a stack of contexts.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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