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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

|CaseNamen|_|) are not permitted.1.._> based on the number of case names. and must return a value of type option<_>.  (|CaseName|_|) arg1 . the limitation n ≤ 7 applies.. and can return any type. The function accepts n+1 arguments (the last being the value matched).  (|CaseName|) arg1 . and must return a value of type Choice<_.. In particular. In F# 2.. 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. and must return a value of type option<_>  (|CaseName1| . multi-case.. The function accepts one argument (the value being matched). The function accepts n+1 arguments (the last being the value matched)... and can return any type.. The function accepts one argument (the value being matched). 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 .7. argn inp — Single case with parameters..5 Active Patterns If long-ident from §7. argn inp — Partial with parameters. The function accepts one argument (the value being matched).. partial functions (|CaseName1| ..5) ensure that CaseNamei is associated with an active pattern function f in one of the following forms:  (|CaseName|) inp — Single case.0. n = %d" n | Negative n -> printfn "negative. Other active pattern functions are not permitted..1.1.|CaseNamen|) inp — Multi-case. The rules of name resolution in patterns (§14.  (|CaseName|_|) inp — Partial.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 name of f must be in one of the following forms: (|id1|.tyN> and _ is not present. The patterns are then converted to the syntactically identical corresponding expression forms and passed as arguments to the active pattern function f. tyout must be:    ty1 when n = 1 and an underscore is not present. The precise number of times the active pattern function is executed is implementation-dependent. the pattern argument pat is then matched against v.|idN|) —or— (|id1|_|) where: id is idk for one of the identifiers in this list. then the pattern applies f to the input being matched. When executed. the pattern matches if the active pattern function returns v.Core.FSharp.Choice<ty1. For example. When an active pattern function takes arguments.Option<ty1> when _ is present. where tyin is the type of input being matched.. or Some v..Core. To avoid ambiguities.. f is a value of function type tyin -> tyout.Assuming that the active pattern case name is associated with a function value f. 94 . the pat-params are interpreted as expressions that are passed as arguments to the active pattern function.. An active pattern function is executed only if a left-to-right.. 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. top-to-bottom reading of the entire pattern indicates that execution is required. ChoicekOfN v. Microsoft.FSharp. syntactically the pat-params are patterns and are limited to those forms shown in the grammar. Microsoft. respectively. If present. along with any given parameters..

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

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

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

record-field ..binding attributesopt staticopt do expr -.nullary union case -.. . '|' union-type-case union-type-case := attributesopt union-type-case-data union-type-case-data := ident ident of type * . The grammar of type definitions is shown below. * type ident : uncurried-sig -..side-effect binding 98 .n-ary union case record-type-defn := type-name = '{' record-fields '}' type-extension-elementsopt record-fields := record-field .. ...n-ary union case -. type-defn := abbrev-type-defn record-type-defn union-type-defn anon-type-defn class-type-defn struct-type-defn interface-type-defn enum-type-defn delegate-type-defn type-extension type-name := attributesopt accessopt ident typar-defnsopt abbrev-type-defn := type-name = type union-type-defn := type-name '=' union-type-cases type-extension-elementsopt union-type-cases := '|'opt union-type-case '|' .8 Type Definitions Type definitions define new named types.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 –.

explicit construction member-defn := attributesopt staticopt member accessopt member-binding attributesopt abstract memberopt accessopt member-sig attributesopt override accessopt member-binding attributesopt default accessopt member-binding attributesopt staticopt val mutableopt accessopt ident : type additional-constr-defn -.additional constructor ------ concrete member abstract member override member override member value member 99 . .enum constant definition -..delegated construction -..exception abbreviation delegate-type-defn := type-name '=' delegate-sig delegate-sig := delegate of uncurried-sig -. '|' enum-type-case enum-type-case := ident '=' const -.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 '|' . type-defn-element primary-constr-args := attributesopt accessopt (pat..' additional-constr-expr -.sequence construction (after) additional-constr-expr then expr -..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 . pat) additional-constr-defn := attributesopt accessopt new pat as-binding = additional-constr-expr additional-constr-expr := stmt '. .exception definition -.sequence construction (before) if expr then additional-constr-expr else additional-constr-expr let val-decls in additional-constr-expr -...binding construction additional-constr-init-expr additional-constr-init-expr := '{' class-inherits-decl field-binds '}' new type expr -.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Like namespace declaration groups.namespace MyCompany. let recopt binding1 and . the individual declarations are checked in order and an overall module signature Msig is inferred for the module.MyLibrary brings Values1 into scope module Values2 = let x = Values1..2) Values and functions defined by ―let‖ bindings are referred to simply as ―values. module Part1 = let x = Part2.Clear() = () No two types or modules may have identical names in the same namespace. Adding the attribute [<CompilationRepresentation(CompilationRepresentationFlags. so that later namespace declaration groups are not in scope when earlier ones are processed.x 10.‖ ―Let‖ bindings in modules may declare explicit type variables and type constraints: 145 . types.1) + fib (n . module definitions are processed sequentially rather than simultaneously.ModuleSuffix)>] adds the suffix Module to the name of a module for the purposes of this check.2.. 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 .StorageCache() module Part2 = type StorageCache() = member cache.MyLibrary module Values1 = let x = 1 namespace MyCompany. An entry for M is then added to the ModulesAndNamespaces table in the original environment env0. // error (Part2 not yet declared) 10. and function values. Grouping code in modules helps keep related code together and helps avoid name conflicts in your program.1 “let” Bindings in Modules ―Let‖ bindings in modules introduce named values and functions.MyLibrary // Implicit open of MyCompany.2 Module Definitions A module definition is a named collection of declarations such as values. 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) let dispose<'T when 'T :> System.DayOfWeek. Values may have attributes.2 Literal Definitions in Modules ―Let‖ bindings in modules may be given the Literal attribute. The default accessibility annotation of a ―let‖ binding in a module is public. with the following adjustments:   Each defined value may have an accessibility annotation (§10.Obsolete("Don't use this")>] let (a. ―Let‖ bindings may specify attributes for values.2. For example: [<Literal>] let StartOfWeek = System.5).count + 1. Externally accessible values have a guaranteed compiled CLI representation of these bindings in compiled CLI binaries. including the ThreadStatic or ContextStatic attributes. 2) Values may be declared mutable: let mutable count = 1 let FreshName() = (count <.3).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.let pair<'T>(x : 'T) = (x. The right-hand side expression must be a literal constant expression made up of either: 146 .    Each defined value can be used to satisfy the requirements of any signature for the module (§11.10). [<System.6). Each defined value is subject to arity analysis (§14.Dispose() let convert<'T. It may not be given the ThreadStatic or ContextStatic attributes. [<System.Obsolete("Don't use this")>] let pear v = (v. b) = (1. 10. count) ―Let‖ bindings in modules are processed in the same way as let and let rec bindings in expressions (§14. v) If more than one value is defined by a ―let‖ binding through pattern matching then the attributes apply to each value.2). Each defined value is externally accessible if it has an accessibility annotation of public and is not hidden by an explicit signature. For example: [<Literal>] let PI = 3.IDisposable>(x : 'T) = x.141592654 Literal values may be used in custom attributes and pattern matching. 'U>(x) = unbox<'U>(box<'T>(x)) A non-function value with explicit type variables is called a type function (§10.2.

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

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

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

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

submodule signature -.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 .. and ....local alias for a module -. 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 -. and specifies the functionality that is implemented by its corresponding implementation file..locally import contents of a module module-signature-elements := module-signature-element . 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 . It also serves to hide functionality contained within its corresponding implementation file..

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

function binding -. float. 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.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.. resolutions that do not give such a warning are preferred over ones that do give such a warning. 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. patn :opt return-typeopt = rhs-expr or a value definition.1 Ambiguities in Bindings An ambiguity exists between the two different kinds of ―let‖ bindings. let rec.6 Checking and Elaborating Bindings This section describes how let.5..6. System. int. This is deliberate: in the CLI. 14. and member bindings are checked.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.Note: The decimal type is included only for the Sign static member. In addition. (+).value binding This ambiguity is always resolved as a function binding. and (-). ―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. as the grammar shows: | ident pat = expr | pat = expr -. patn = expr 14. generalized and elaborated. Each binding is either a function definition: inlineopt ident1 pat1 . This mechanism is used to implement the extensible conversion and math functions of the F# library including sin. For example: type foo = Id of int let Id x = x 188 . cos.. 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 . In particular:ident pat = expr This can be interpreted as either a function or value binding.. For example. 14.

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

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

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

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

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

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

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

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

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

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

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

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

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. System.IndexOf requiring C : equality System. for any overload that does not take an IEqualityComparer<_> 201 .Array. for any overload that does not take an IComparer<T> System. for any overload that does not take an IEqualityComparer<T> new SortedList<A.Equals(yobj) requires type ty : equality for the static type of x x.value) requiring C : comparison.14.T) requiring C : equality System. You should consider writing wrappers around these functions to improve the type safety of using the operations.Array.GetHashCode() requires type ty : equality for the static type of x new Dictionary<A.Array.B>() requiring C : comparison.LastIndexOf(array.Sort<'T>(array) requiring C : comparison.Array. for any overload that does not take an IEqualityComparer<T> new SortedDictionary<A.B>() requires A : equality.BinarySearch<T>(array. because they are common in F# programming and cause extremely difficult-to-find bugs. For each use of the following constructs.B>() requiring A : comparison. for any overload that does not take an IEqualityComparer<T> No constraints are added for the following operations.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Sign up to vote on this title
UsefulNot useful