Skip to content

Commit c853431

Browse files
authored
F# 9 doc updates (#43777)
* F# 9 doc updates * lint * up * Update discriminated-unions.md * attributes * Update byrefs.md * Update byrefs.md
1 parent 171d64c commit c853431

File tree

8 files changed

+160
-14
lines changed

8 files changed

+160
-14
lines changed

docs/fsharp/language-reference/active-patterns.md

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ let (|identifier|) [arguments] valueToMatch = expression
1818
let (|identifier1|identifier2|...|) valueToMatch = expression
1919
2020
// Partial active pattern definition.
21-
// Uses a FSharp.Core.option<_> to represent if the type is satisfied at the call site.
21+
// Can use FSharp.Core.option<_>, FSharp.Core.voption<_> or bool to represent if the type is satisfied at the call site.
2222
let (|identifier|_|) [arguments] valueToMatch = expression
2323
```
2424

@@ -132,9 +132,38 @@ Note however that only single-case active patterns can be parameterized.
132132

133133
[!code-fsharp[Main](~/samples/snippets/fsharp/lang-ref-2/snippet5008.fs)]
134134

135+
## Return Type for Partial Active Patterns
136+
137+
Partial active patterns return `Some ()` to indicate a match and `None` otherwise.
138+
139+
Consider this match:
140+
141+
```fsharp
142+
match key with
143+
| CaseInsensitive "foo" -> ...
144+
| CaseInsensitive "bar" -> ...
145+
```
146+
147+
The partial active pattern for it would be:
148+
149+
```fsharp
150+
let (|CaseInsensitive|_|) (pattern: string) (value: string) =
151+
if String.Equals(value, pattern, StringComparison.OrdinalIgnoreCase) then
152+
Some ()
153+
else
154+
None
155+
```
156+
157+
Starting with F# 9, such patterns can also return `bool`:
158+
159+
```fsharp
160+
let (|CaseInsensitive|_|) (pattern: string) (value: string) =
161+
String.Equals(value, pattern, StringComparison.OrdinalIgnoreCase)
162+
```
163+
135164
## Struct Representations for Partial Active Patterns
136165

137-
By default, partial active patterns return an `option` value, which will involve an allocation for the `Some` value on a successful match. Alternatively, you can use a [value option](value-options.md) as a return value through the use of the `Struct` attribute:
166+
By default, if a partial active pattern returns an `option`, this will involve an allocation for the `Some` value on a successful match. To avoid it, you can use a [value option](value-options.md) as a return value through the use of the `Struct` attribute:
138167

139168
```fsharp
140169
open System

docs/fsharp/language-reference/attributes.md

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,82 @@ Although you do not usually need to specify the attribute target explicitly, val
8181
[<``module``: MyCustomAttributeThatWorksOnModules>]
8282
```
8383

84+
</td>
85+
</tr>
86+
<tr>
87+
<td>method</td>
88+
<td>
89+
90+
```fsharp
91+
[<MyCustomAttributeThatWorksOnMethods>]
92+
let someFunction() = 42
93+
```
94+
95+
</td>
96+
</tr>
97+
<tr>
98+
<td>class</td>
99+
<td>
100+
101+
```fsharp
102+
[<MyCustomAttributeThatWorksOnClasses>]
103+
type MyClass(myValue: int) =
104+
member _.MyValue = myValue
105+
```
106+
107+
</td>
108+
</tr>
109+
<tr>
110+
<td>struct</td>
111+
<td>
112+
113+
```fsharp
114+
[<MyCustomAttributeThatWorksOnStructs>]
115+
[<Struct>]
116+
type MyStruct(myValue: int) =
117+
member _.MyValue = myValue
118+
```
119+
120+
</td>
121+
</tr>
122+
<tr>
123+
<td>interface</td>
124+
<td>
125+
126+
```fsharp
127+
[<MyCustomAttributeThatWorksOnInterfaces>]
128+
type MyInterface =
129+
abstract member Prop: string
130+
```
131+
132+
</td>
133+
</tr>
134+
<tr>
135+
<td>enum</td>
136+
<td>
137+
138+
```fsharp
139+
[<MyCustomAttributeThatWorksOnEnums>]
140+
type Color =
141+
| Red = 0
142+
| Green = 1
143+
| Blue = 2
144+
```
145+
146+
</td>
147+
</tr>
148+
<tr>
149+
<td>constructor</td>
150+
<td>
151+
152+
```fsharp
153+
type MyClass(myValue: int) =
154+
member _.MyValue = myValue
155+
156+
[<MyCustomAttributeThatWorksOnCtors>]
157+
new () = MyClass 42
158+
```
159+
84160
</td>
85161
</tr>
86162
<tr>

docs/fsharp/language-reference/byrefs.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,8 @@ A "`byref`-like" struct in F# is a stack-bound value type. It is never allocated
179179
* They cannot be static or instance members of a class or normal struct.
180180
* They cannot be captured by any closure construct (`async` methods or lambda expressions).
181181
* They cannot be used as a generic parameter.
182+
* Starting with F# 9, this restriction is relaxed if the generic parameter is defined in C# using the allows ref struct anti-constraint. F# can instantiate such generics in types and methods with byref-like types. As a few examples, this affects BCL delegate types (`Action<>`, `Func<>`), interfaces (`IEnumerable<>`, `IComparable<>`) and generic arguments with a user-provided accumulator function (`String.string Create<TState>(int length, TState state, SpanAction<char, TState> action)`).
183+
* It is impossible to author generic code supporting byref-like types in F#.
182184

183185
This last point is crucial for F# pipeline-style programming, as `|>` is a generic function that parameterizes its input types. This restriction may be relaxed for `|>` in the future, as it is inline and does not make any calls to non-inlined generic functions in its body.
184186

docs/fsharp/language-reference/compiler-directives.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ The following table lists the preprocessor directives that are available in F#.
2323
|`#else`|Supports conditional compilation. Marks a section of code to include if the symbol used with the previous `#if` is not defined.|
2424
|`#endif`|Supports conditional compilation. Marks the end of a conditional section of code.|
2525
|`#`[line] *int*,<br/>`#`[line] *int* *string*,<br/>`#`[line] *int* *verbatim-string*|Indicates the original source code line and file name, for debugging. This feature is provided for tools that generate F# source code.|
26-
|`#nowarn` *warningcode*|Disables a compiler warning or warnings. To disable a warning, find its number from the compiler output and include it in quotation marks. Omit the "FS" prefix. To disable multiple warning numbers on the same line, include each number in quotation marks, and separate each string by a space. <br/> For example: `#nowarn "9" "40"`|
26+
|`#nowarn` *warningcode*|Disables a compiler warning or warnings. To disable multiple warning numbers on the same line, separate each string by a space. <br/> For example: `#nowarn 9 42`|
2727

2828
The effect of disabling a warning applies to the entire file, including portions of the file that precede the directive.|
2929

docs/fsharp/language-reference/computation-expressions.md

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -440,17 +440,21 @@ You can define a custom operation on a computation expression and use a custom o
440440

441441
If you already have a builder class, its custom operations can be extended from outside of this builder class. Extensions must be declared in modules. Namespaces cannot contain extension members except in the same file and the same namespace declaration group where the type is defined.
442442

443-
The following example shows the extension of the existing `FSharp.Linq.QueryBuilder` class.
443+
The following example shows the extensions of the existing `FSharp.Linq.QueryBuilder` class.
444444

445445
```fsharp
446446
open System
447447
open FSharp.Linq
448448
449449
type QueryBuilder with
450450
451-
[<CustomOperation("existsNot")>]
452-
member _.ExistsNot (source: QuerySource<'T, 'Q>, predicate) =
453-
System.Linq.Enumerable.Any (source.Source, Func<_,_>(predicate)) |> not
451+
[<CustomOperation>]
452+
member _.any (source: QuerySource<'T, 'Q>, predicate) =
453+
System.Linq.Enumerable.Any (source.Source, Func<_,_>(predicate))
454+
455+
[<CustomOperation("singleSafe")>] // you can specify your own operation name in the constructor
456+
member _.singleOrDefault (source: QuerySource<'T, 'Q>, predicate) =
457+
System.Linq.Enumerable.SingleOrDefault (source.Source, Func<_,_>(predicate))
454458
```
455459

456460
Custom operations can be overloaded. For more information, see [F# RFC FS-1056 - Allow overloads of custom keywords in computation expressions](https://github.com/fsharp/fslang-design/blob/main/FSharp-6.0/FS-1056-allow-custom-operation-overloads.md).

docs/fsharp/language-reference/discriminated-unions.md

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -113,16 +113,17 @@ type SingleCase = Case of string
113113
114114
[<Struct>]
115115
type Multicase =
116-
| Case1 of Case1 : string
117-
| Case2 of Case2 : int
118-
| Case3 of Case3 : double
116+
| Case1 of string
117+
| Case2 of int
118+
| Case3 of double
119119
```
120120

121121
Because these are value types and not reference types, there are extra considerations compared with reference discriminated unions:
122122

123123
1. They are copied as value types and have value type semantics.
124-
2. You cannot use a recursive type definition with a multicase struct Discriminated Union.
125-
3. You must provide unique case names for a multicase struct Discriminated Union.
124+
2. You cannot use a recursive type definition with a multicase struct discriminated union.
125+
126+
Before F# 9, there was a requirement for each case to specify a unique case name (within the union). Starting with F# 9, the limitation is lifted.
126127

127128
## Using Discriminated Unions Instead of Object Hierarchies
128129

@@ -190,6 +191,23 @@ type Shape =
190191
| Rectangle(l, w) -> printfn $"Rectangle with length %f{l} and width %f{w}"
191192
```
192193

194+
## `.Is*` properties on cases
195+
196+
Since F# 9, discriminated unions expose auto-generated `.Is*` properties for each case, allowing you to check if a value is of a particular case.
197+
198+
This is how it can be used:
199+
200+
```fsharp
201+
type Contact =
202+
| Email of address: string
203+
| Phone of countryCode: int * number: string
204+
205+
type Person = { name: string; contact: Contact }
206+
207+
let canSendEmailTo person =
208+
person.contact.IsEmail // .IsEmail is auto-generated
209+
```
210+
193211
## Common attributes
194212

195213
The following attributes are commonly seen in discriminated unions:

docs/fsharp/language-reference/fsharp-collection-types.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,21 @@ This section compares the functions that are available on F# collection types. T
9797
|partition|O(N)|O(N)|-|O(N)|O(N)|Splits the collection into two collections. The first collection contains the elements for which the given predicate returns `true`, and the second collection contains the elements for which the given predicate returns `false`.|
9898
|permute|O(N)|O(N)|-|-|-|Returns an array with all elements permuted according to the specified permutation.|
9999
|pick|O(N)|O(N)|O(N)|O(log(N))|-|Applies the given function to successive elements, returning the first result where the function returns Some. If the function never returns Some, `System.Collections.Generic.KeyNotFoundException` is raised.|
100+
|randomChoice|O(1)|O(1)|O(1)|-|-|Returns a random element from the given collection.|
101+
|randomChoiceBy|O(1)|O(1)|O(1)|-|-|Returns a random element from the given collection with the specified `randomizer` function.|
102+
|randomChoiceWith|O(1)|O(1)|O(1)|-|-|Returns a random element from the given collection with the specified `Random` instance.|
103+
|randomChoices|O(count)|O(count)|O(count)|-|-|Returns a collection of random elements from the given collection, each element can be selected multiple times.|
104+
|randomChoicesBy|O(count)|O(count)|O(count)|-|-|Returns a collection of random elements from the given collection with the specified `randomizer` function, each element can be selected multiple times.|
105+
|randomChoicesWith|O(count)|O(count)|O(count)|-|-|Returns a collection of random elements from the given collection with the specified `Random` instance, each element can be selected multiple times.|
106+
|randomSample|O(count)|O(count)|O(count)|-|-|Returns a random sample of elements from the given collection, each element can be selected only once.|
107+
|randomSampleBy|O(count)|O(count)|O(count)|-|-|Returns a random sample of elements from the given colleciton with the specified `randomizer` function, each element can be selected only once.|
108+
|randomSampleWith|O(count)|O(count)|O(count)|-|-|Returns a random sample of elements from the given collection with the specified `Random` instance, each element can be selected only once.|
109+
|randomShuffle|O(N)|O(N)|O(N)|-|-|Return a new collection shuffled in a random order.|
110+
|randomShuffleBy|O(N)|O(N)|O(N)|-|-|Return a new collection shuffled in a random order with the specified `randomizer` function.|
111+
|randomShuffleWith|O(N)|O(N)|O(N)|-|-|Return a new collection shuffled in a random order with the specified `Random` instance.|
112+
|randomShuffleInPlace|O(N)|-|-|-|-|Sorts input array in a random order by mutating the array in-place.|
113+
|randomShuffleInPlaceBy|O(N)|-|-|-|-|Sorts input array in a random order using the specified `randomizer` function by mutating the array in-place.|
114+
|randomShuffleInPlaceWith|O(N)|-|-|-|-|Sorts input array in a random order with the specified `Random` instance by mutating the array in-place.|
100115
|readonly|-|-|O(N)|-|-|Creates a sequence object that delegates to the given sequence object. This operation ensures that a type cast can't rediscover and mutate the original sequence. For example, if given an array, the returned sequence will return the elements of the array, but you can't cast the returned sequence object to an array.|
101116
|reduce|O(N)|O(N)|O(N)|-|-|Applies a function to each element of the collection, threading an accumulator argument through the computation. This function starts by applying the function to the first two elements, passes this result into the function along with the third element, and so on. The function returns the final result.|
102117
|reduceBack|O(N)|O(N)|-|-|-|Applies a function to each element of the collection, threading an accumulator argument through the computation. If the input function is f and the elements are i0...iN, this function computes f i0 (...(f iN-1 iN)).|

docs/fsharp/tools/fsharp-interactive/index.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -243,15 +243,17 @@ The `#r` and `#load` directives seen previously are only available in F# Interac
243243
|`#help`|Displays information about available directives or documentation for specific functions.|
244244
|`#I`|Specifies an assembly search path in quotation marks.|
245245
|`#quit`|Terminates an F# Interactive session.|
246-
|`#time "on"` or `#time "off"`|By itself, `#time` toggles whether to display performance information. When it is `"on"`, F# Interactive measures real time, CPU time, and garbage collection information for each section of code that is interpreted and executed.|
246+
|`#time on` or `#time off`|By itself, `#time` toggles whether to display performance information. When it is `on`, F# Interactive measures real time, CPU time, and garbage collection information for each section of code that is interpreted and executed.|
247247

248248
[^1]: More about [F# Interactive extensions](https://aka.ms/dotnetdepmanager).
249249

250250
When you specify files or paths in F# Interactive, a string literal is expected. Therefore, files and paths must be in quotation marks, and the usual escape characters apply. You can use the `@` character to cause F# Interactive to interpret a string that contains a path as a verbatim string. This causes F# Interactive to ignore any escape characters.
251251

252+
For other cases, quotation marks are optional, starting with F# 9.
253+
252254
### Extended #help directive
253255

254-
The `#help` directive now supports displaying documentation for specific functions. You can pass the name of the function directly (without quotes) to retrieve details.
256+
The `#help` directive now supports displaying documentation for specific functions. You can pass the name of the function directly to retrieve details.
255257

256258
```fsharp
257259
#help List.map;;

0 commit comments

Comments
 (0)