Skip to content

Commit

Permalink
F# 9 doc updates (#43777)
Browse files Browse the repository at this point in the history
* F# 9 doc updates

* lint

* up

* Update discriminated-unions.md

* attributes

* Update byrefs.md

* Update byrefs.md
  • Loading branch information
psfinaki authored Dec 6, 2024
1 parent 171d64c commit c853431
Show file tree
Hide file tree
Showing 8 changed files with 160 additions and 14 deletions.
33 changes: 31 additions & 2 deletions docs/fsharp/language-reference/active-patterns.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ let (|identifier|) [arguments] valueToMatch = expression
let (|identifier1|identifier2|...|) valueToMatch = expression
// Partial active pattern definition.
// Uses a FSharp.Core.option<_> to represent if the type is satisfied at the call site.
// Can use FSharp.Core.option<_>, FSharp.Core.voption<_> or bool to represent if the type is satisfied at the call site.
let (|identifier|_|) [arguments] valueToMatch = expression
```

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

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

## Return Type for Partial Active Patterns

Partial active patterns return `Some ()` to indicate a match and `None` otherwise.

Consider this match:

```fsharp
match key with
| CaseInsensitive "foo" -> ...
| CaseInsensitive "bar" -> ...
```

The partial active pattern for it would be:

```fsharp
let (|CaseInsensitive|_|) (pattern: string) (value: string) =
if String.Equals(value, pattern, StringComparison.OrdinalIgnoreCase) then
Some ()
else
None
```

Starting with F# 9, such patterns can also return `bool`:

```fsharp
let (|CaseInsensitive|_|) (pattern: string) (value: string) =
String.Equals(value, pattern, StringComparison.OrdinalIgnoreCase)
```

## Struct Representations for Partial Active Patterns

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:
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:

```fsharp
open System
Expand Down
76 changes: 76 additions & 0 deletions docs/fsharp/language-reference/attributes.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,82 @@ Although you do not usually need to specify the attribute target explicitly, val
[<``module``: MyCustomAttributeThatWorksOnModules>]
```

</td>
</tr>
<tr>
<td>method</td>
<td>

```fsharp
[<MyCustomAttributeThatWorksOnMethods>]
let someFunction() = 42
```

</td>
</tr>
<tr>
<td>class</td>
<td>

```fsharp
[<MyCustomAttributeThatWorksOnClasses>]
type MyClass(myValue: int) =
member _.MyValue = myValue
```

</td>
</tr>
<tr>
<td>struct</td>
<td>

```fsharp
[<MyCustomAttributeThatWorksOnStructs>]
[<Struct>]
type MyStruct(myValue: int) =
member _.MyValue = myValue
```

</td>
</tr>
<tr>
<td>interface</td>
<td>

```fsharp
[<MyCustomAttributeThatWorksOnInterfaces>]
type MyInterface =
abstract member Prop: string
```

</td>
</tr>
<tr>
<td>enum</td>
<td>

```fsharp
[<MyCustomAttributeThatWorksOnEnums>]
type Color =
| Red = 0
| Green = 1
| Blue = 2
```

</td>
</tr>
<tr>
<td>constructor</td>
<td>

```fsharp
type MyClass(myValue: int) =
member _.MyValue = myValue
[<MyCustomAttributeThatWorksOnCtors>]
new () = MyClass 42
```

</td>
</tr>
<tr>
Expand Down
2 changes: 2 additions & 0 deletions docs/fsharp/language-reference/byrefs.md
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,8 @@ A "`byref`-like" struct in F# is a stack-bound value type. It is never allocated
* They cannot be static or instance members of a class or normal struct.
* They cannot be captured by any closure construct (`async` methods or lambda expressions).
* They cannot be used as a generic parameter.
* 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)`).
* It is impossible to author generic code supporting byref-like types in F#.

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.

Expand Down
2 changes: 1 addition & 1 deletion docs/fsharp/language-reference/compiler-directives.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ The following table lists the preprocessor directives that are available in F#.
|`#else`|Supports conditional compilation. Marks a section of code to include if the symbol used with the previous `#if` is not defined.|
|`#endif`|Supports conditional compilation. Marks the end of a conditional section of code.|
|`#`[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.|
|`#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"`|
|`#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`|

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

Expand Down
12 changes: 8 additions & 4 deletions docs/fsharp/language-reference/computation-expressions.md
Original file line number Diff line number Diff line change
Expand Up @@ -440,17 +440,21 @@ You can define a custom operation on a computation expression and use a custom o

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.

The following example shows the extension of the existing `FSharp.Linq.QueryBuilder` class.
The following example shows the extensions of the existing `FSharp.Linq.QueryBuilder` class.

```fsharp
open System
open FSharp.Linq
type QueryBuilder with
[<CustomOperation("existsNot")>]
member _.ExistsNot (source: QuerySource<'T, 'Q>, predicate) =
System.Linq.Enumerable.Any (source.Source, Func<_,_>(predicate)) |> not
[<CustomOperation>]
member _.any (source: QuerySource<'T, 'Q>, predicate) =
System.Linq.Enumerable.Any (source.Source, Func<_,_>(predicate))
[<CustomOperation("singleSafe")>] // you can specify your own operation name in the constructor
member _.singleOrDefault (source: QuerySource<'T, 'Q>, predicate) =
System.Linq.Enumerable.SingleOrDefault (source.Source, Func<_,_>(predicate))
```

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).
Expand Down
28 changes: 23 additions & 5 deletions docs/fsharp/language-reference/discriminated-unions.md
Original file line number Diff line number Diff line change
Expand Up @@ -113,16 +113,17 @@ type SingleCase = Case of string
[<Struct>]
type Multicase =
| Case1 of Case1 : string
| Case2 of Case2 : int
| Case3 of Case3 : double
| Case1 of string
| Case2 of int
| Case3 of double
```

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

1. They are copied as value types and have value type semantics.
2. You cannot use a recursive type definition with a multicase struct Discriminated Union.
3. You must provide unique case names for a multicase struct Discriminated Union.
2. You cannot use a recursive type definition with a multicase struct discriminated union.

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.

## Using Discriminated Unions Instead of Object Hierarchies

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

## `.Is*` properties on cases

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.

This is how it can be used:

```fsharp
type Contact =
| Email of address: string
| Phone of countryCode: int * number: string
type Person = { name: string; contact: Contact }
let canSendEmailTo person =
person.contact.IsEmail // .IsEmail is auto-generated
```

## Common attributes

The following attributes are commonly seen in discriminated unions:
Expand Down
15 changes: 15 additions & 0 deletions docs/fsharp/language-reference/fsharp-collection-types.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,21 @@ This section compares the functions that are available on F# collection types. T
|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`.|
|permute|O(N)|O(N)|-|-|-|Returns an array with all elements permuted according to the specified permutation.|
|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.|
|randomChoice|O(1)|O(1)|O(1)|-|-|Returns a random element from the given collection.|
|randomChoiceBy|O(1)|O(1)|O(1)|-|-|Returns a random element from the given collection with the specified `randomizer` function.|
|randomChoiceWith|O(1)|O(1)|O(1)|-|-|Returns a random element from the given collection with the specified `Random` instance.|
|randomChoices|O(count)|O(count)|O(count)|-|-|Returns a collection of random elements from the given collection, each element can be selected multiple times.|
|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.|
|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.|
|randomSample|O(count)|O(count)|O(count)|-|-|Returns a random sample of elements from the given collection, each element can be selected only once.|
|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.|
|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.|
|randomShuffle|O(N)|O(N)|O(N)|-|-|Return a new collection shuffled in a random order.|
|randomShuffleBy|O(N)|O(N)|O(N)|-|-|Return a new collection shuffled in a random order with the specified `randomizer` function.|
|randomShuffleWith|O(N)|O(N)|O(N)|-|-|Return a new collection shuffled in a random order with the specified `Random` instance.|
|randomShuffleInPlace|O(N)|-|-|-|-|Sorts input array in a random order by mutating the array in-place.|
|randomShuffleInPlaceBy|O(N)|-|-|-|-|Sorts input array in a random order using the specified `randomizer` function by mutating the array in-place.|
|randomShuffleInPlaceWith|O(N)|-|-|-|-|Sorts input array in a random order with the specified `Random` instance by mutating the array in-place.|
|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.|
|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.|
|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)).|
Expand Down
6 changes: 4 additions & 2 deletions docs/fsharp/tools/fsharp-interactive/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -243,15 +243,17 @@ The `#r` and `#load` directives seen previously are only available in F# Interac
|`#help`|Displays information about available directives or documentation for specific functions.|
|`#I`|Specifies an assembly search path in quotation marks.|
|`#quit`|Terminates an F# Interactive session.|
|`#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.|
|`#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.|

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

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.

For other cases, quotation marks are optional, starting with F# 9.

### Extended #help directive

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

```fsharp
#help List.map;;
Expand Down

0 comments on commit c853431

Please sign in to comment.