Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

F# 4.7 docs updates #15674

Merged
merged 8 commits into from Nov 12, 2019
@@ -1,7 +1,7 @@
---
title: Byrefs
description: Learn about byref and byref-like types in F#, which are used for low-level programming.
ms.date: 09/02/2018
ms.date: 11/04/2019
---
# Byrefs

@@ -194,9 +194,9 @@ You can also directly assign to a return `byref`. Consider the following (highly
type C() =
let mutable nums = [| 1; 3; 7; 15; 31; 63; 127; 255; 511; 1023 |]
override __.ToString() = String.Join(' ', nums)
override _.ToString() = String.Join(' ', nums)
member __.FindLargestSmallerThan(target: int) =
member _.FindLargestSmallerThan(target: int) =
let mutable ctr = nums.Length - 1
while ctr > 0 && nums.[ctr] >= target do ctr <- ctr - 1
@@ -1,7 +1,7 @@
---
title: Caller information
description: Describes how to use Caller Info Argument Attributes to obtain caller information from a method.
ms.date: 04/25/2017
ms.date: 11/04/2019
---
# Caller information

@@ -25,7 +25,7 @@ open System.Runtime.CompilerServices
open System.Runtime.InteropServices
type Tracer() =
member __.DoTrace(message: string,
member _.DoTrace(message: string,
[<CallerMemberName; Optional; DefaultParameterValue("")>] memberName: string,
[<CallerFilePath; Optional; DefaultParameterValue("")>] path: string,
[<CallerLineNumber; Optional; DefaultParameterValue(0)>] line: int) =
@@ -1,7 +1,7 @@
---
title: Computation Expressions
description: Learn how to create convenient syntax for writing computations in F# that can be sequenced and combined using control flow constructs and bindings.
ms.date: 03/15/2019
ms.date: 11/04/2019
---
# Computation Expressions

@@ -106,6 +106,34 @@ for sq in squares do
printfn "%d" sq
```

In most cases, it can be omitted by callers. The most common way to omit `yield` is with the `->` operator:

```fsharp
let squares =
seq {
for i in 1..10 -> i * i
}
for sq in squares do
printfn "%d" sq
```

For more complex expressions that might yield many different values, and perhaps conditionally, simply omitting the keyword can do:

```fsharp
let weekdays includeWeekend =
seq {
"Monday"
"Tuesday"
"Wednesday"
"Thursday"
"Friday"
if includeWeekend then
"Saturday"
"Sunday"
}
```

As with the [yield keyword in C#](../../csharp/language-reference/keywords/yield.md), each element in the computation expression is yielded back as it is iterated.

`yield` is defined by the `Yield(x)` member on the builder type, where `x` is the item to yield back.
@@ -138,6 +166,8 @@ When evaluated, the computation expression called by `yield!` will have its item

`yield!` is defined by the `YieldFrom(x)` member on the builder type, where `x` is a collection of values.

Unlike `yield`, `yield!` must be explicitly specified - its behavior is not implicit in computation expressions.
This conversation was marked as resolved by cartermp

This comment has been minimized.

Copy link
@mairaw

mairaw Nov 10, 2019

Contributor
Suggested change
Unlike `yield`, `yield!` must be explicitly specified - its behavior is not implicit in computation expressions.
Unlike `yield`, `yield!` must be explicitly specified. Its behavior isn't implicit in computation expressions.

### `return`

The `return` keyword wraps a value in the type corresponding to the computation expression. Aside from computation expressions using `yield`, it is used to "complete" a computation expression:
@@ -388,7 +418,7 @@ The following example shows the extension of the existing `Microsoft.FSharp.Linq
type Microsoft.FSharp.Linq.QueryBuilder with
[<CustomOperation("existsNot")>]
member __.ExistsNot (source: QuerySource<'T, 'Q>, predicate) =
member _.ExistsNot (source: QuerySource<'T, 'Q>, predicate) =
Enumerable.Any (source.Source, Func<_,_>(predicate)) |> not
```

@@ -1,7 +1,7 @@
---
title: Keyword Reference
description: Find links to information about all of the F# language keywords.
ms.date: 05/16/2016
ms.date: 11/04/2019
---
# Keyword Reference

@@ -81,7 +81,7 @@ The following table shows all F# keywords in alphabetical order, together with b
|`when`|[Constraints](./generics/constraints.md)|Used for Boolean conditions (*when guards*) on pattern matches and to introduce a constraint clause for a generic type parameter.|
|`while`|[Loops: `while...do` Expression](loops-while-do-expression.md)|Introduces a looping construct.|
|`with`|[Match Expressions](match-expressions.md)<br /><br />[Object Expressions](object-expressions.md)<br /><br />[Copy and Update Record Expressions](copy-and-update-record-expressions.md)<br /><br />[Type Extensions](type-extensions.md)<br /><br />[Exceptions: The `try...with` Expression](./exception-handling/the-try-with-expression.md)|Used together with the `match` keyword in pattern matching expressions. Also used in object expressions, record copying expressions, and type extensions to introduce member definitions, and to introduce exception handlers.|
|`yield`|[Sequences](sequences.md)|Used in a sequence expression to produce a value for a sequence.|
|`yield`|[Lists](lists.md), [Arrays](arrays.md), [Sequences](sequences.md)|Used in a list, array, or sequence expression to produce a value for a sequence. Typically can be omitted, as it is implicit in most situations.|
|`yield!`|[Computation Expressions](computation-expressions.md)<br /><br />[Asynchronous Workflows](asynchronous-workflows.md)|Used in a computation expression to append the result of a given computation expression to a collection of results for the containing computation expression.|

The following tokens are reserved in F# because they are keywords in the OCaml language:
@@ -1,7 +1,7 @@
---
title: Indexed Properties
description: Learn about indexed properties in F#, which allow for array-like access to ordered data.
ms.date: 10/17/2018
ms.date: 11/04/2019
---

# Indexed Properties
@@ -65,7 +65,7 @@ open System.Collections.Generic
/// Basic implementation of a sparse matrix based on a dictionary
type SparseMatrix() =
let table = new Dictionary<(int * int), float>()
member __.Item
member _.Item
// Because the key is comprised of two values, 'get' has two index values
with get(key1, key2) = table.[(key1, key2)]
@@ -1,7 +1,7 @@
---
title: Methods
description: Learn how an F# method is a function associated with a type that are used to expose and implement the functionality and behavior of objects and types.
ms.date: 05/16/2016
ms.date: 11/04/2019
---
# Methods

@@ -100,7 +100,7 @@ Starting with F# 4.1, you can also have optional arguments with a default parame
```fsharp
// A class with a method M, which takes in an optional integer argument.
type C() =
__.M([<Optional; DefaultParameterValue(12)>] i) = i + 1
_.M([<Optional; DefaultParameterValue(12)>] i) = i + 1
```

Note that the value passed in for `DefaultParameterValue` must match the input type. In the above sample, it is an `int`. Attempting to pass a non-integer value into `DefaultParameterValue` would result in a compile error.
@@ -1,50 +1,75 @@
---
title: Sequences
description: Learn how to use F# sequences, when you have a large, ordered collection of data but don't necessarily expect to use all of the elements.
ms.date: 02/19/2019
ms.date: 11/04/2019
---
# Sequences

> [!NOTE]
> The API reference links in this article will take you to MSDN. The docs.microsoft.com API reference is not complete.
A *sequence* is a logical series of elements all of one type. Sequences are particularly useful when you have a large, ordered collection of data but do not necessarily expect to use all of the elements. Individual sequence elements are computed only as required, so a sequence can provide better performance than a list in situations in which not all the elements are used. Sequences are represented by the `seq<'T>` type, which is an alias for `System.Collections.Generic.IEnumerable`. Therefore, any .NET Framework type that implements `System.IEnumerable` can be used as a sequence. The [Seq module](https://msdn.microsoft.com/library/54e8f059-ca52-4632-9ae9-49685ee9b684) provides support for manipulations involving sequences.
A *sequence* is a logical series of elements all of one type. Sequences are particularly useful when you have a large, ordered collection of data but do not necessarily expect to use all of the elements. Individual sequence elements are computed only as required, so a sequence can provide better performance than a list in situations in which not all the elements are used. Sequences are represented by the `seq<'T>` type, which is an alias for `System.Collections.Generic.IEnumerable`. Therefore, any .NET type that implements `System.IEnumerable<T>` interface can be used as a sequence. The [Seq module](https://msdn.microsoft.com/library/54e8f059-ca52-4632-9ae9-49685ee9b684) provides support for manipulations involving sequences.

## Sequence Expressions

A *sequence expression* is an expression that evaluates to a sequence. Sequence expressions can take a number of forms. The simplest form specifies a range. For example, `seq { 1 .. 5 }` creates a sequence that contains five elements, including the endpoints 1 and 5. You can also specify an increment (or decrement) between two double periods. For example, the following code creates the sequence of multiples of 10.

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

Sequence expressions are made up of F# expressions that produce values of the sequence. They can use the `yield` keyword to produce values that become part of the sequence.

Following is an example.
Sequence expressions are made up of F# expressions that produce values of the sequence. You can also generate values programmatically:

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

You can use the `->` operator instead of `yield`, in which case you can omit the `do` keyword, as shown in the following example.
The previous sample uses the `->` operator, which allows you to specify an expression whose value will become a part of the sequence. You can only use `->` if every part of the code that follows it returns a value.

Alternatively, you can specify the `do` keyword, with an optional `yield` that follows:

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

The following code generates a list of coordinate pairs along with an index into an array that represents the grid.
The following code generates a list of coordinate pairs along with an index into an array that represents the grid. Note that the first `for` expression requires a `do` to be specified.

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

An `if` expression used in a sequence is a filter. For example, to generate a sequence of only prime numbers, assuming that you have a function `isprime` of type `int -> bool`, construct the sequence as follows.

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

When you use `yield` or `->` in an iteration, each iteration is expected to generate a single element of the sequence. If each iteration produces a sequence of elements, use `yield!`. In that case, the elements generated on each iteration are concatenated to produce the final sequence.
As mentioned previously, `do` is required here because there is no `else` branch that goes with the `if`. If you try to use `->`, you will get an error saying that not all branches return a value.
This conversation was marked as resolved by cartermp

This comment has been minimized.

Copy link
@mairaw

mairaw Nov 10, 2019

Contributor
Suggested change
As mentioned previously, `do` is required here because there is no `else` branch that goes with the `if`. If you try to use `->`, you will get an error saying that not all branches return a value.
As mentioned previously, `do` is required here because there is no `else` branch that goes with the `if`. If you try to use `->`, you'll get an error saying that not all branches return a value.

## The `yield!` keyword

Sometimes, you may wish to include a sequence of elements into another sequence. To include a sequence within another sequence, you'll need to use the `yield!` keyword.
This conversation was marked as resolved by cartermp

This comment has been minimized.

Copy link
@mairaw

mairaw Nov 10, 2019

Contributor
Suggested change
Sometimes, you may wish to include a sequence of elements into another sequence. To include a sequence within another sequence, you'll need to use the `yield!` keyword.
Sometimes, you may wish to include a sequence of elements into another sequence. To include a sequence within another sequence, you'll need to use the `yield!` keyword:

```fsharp
// Repeats '1 2 3 4 5' ten times
seq {
for _ in 1..10 do
yield! seq { 1; 2; 3; 4; 5}
}
```

Another way of thinking of `yield!` is that it flattens an inner sequence and then includes that in the containing sequence.

When `yield!` is used in an expression, all other single values must use the `yield` keyword.
This conversation was marked as resolved by cartermp

This comment has been minimized.

Copy link
@mairaw

mairaw Nov 10, 2019

Contributor
Suggested change
When `yield!` is used in an expression, all other single values must use the `yield` keyword.
When `yield!` is used in an expression, all other single values must use the `yield` keyword:

```fsharp
// Combine repeated values with their values
seq {
for x in 1..10 do
yield x
yield! seq { for i in 1..x -> i}
}
```

You can combine multiple expressions together in a sequence expression. The elements generated by each expression are concatenated together. For an example, see the "Examples" section of this topic.
Specifying only `x` is the previous example will result in the sequence generating no values.
This conversation was marked as resolved by cartermp

This comment has been minimized.

Copy link
@mairaw

mairaw Nov 10, 2019

Contributor
Suggested change
Specifying only `x` is the previous example will result in the sequence generating no values.
Specifying only `x` in the previous example will result in the sequence generating no values.

## Examples

The first example uses a sequence expression that contains an iteration, a filter, and a yield to generate an array. This code prints a sequence of prime numbers between 1 and 100 to the console.

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

The following code uses `yield` to create a multiplication table that consists of tuples of three elements, each consisting of two factors and the product.
The following code creates a multiplication table that consists of tuples of three elements, each consisting of two factors and the product.
This conversation was marked as resolved by cartermp

This comment has been minimized.

Copy link
@mairaw

mairaw Nov 10, 2019

Contributor
Suggested change
The following code creates a multiplication table that consists of tuples of three elements, each consisting of two factors and the product.
The following example creates a multiplication table that consists of tuples of three elements, each consisting of two factors and the product:

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

@@ -56,7 +81,7 @@ The following example demonstrates the use of `yield!` to combine individual seq

Sequences support many of the same functions as [lists](lists.md). Sequences also support operations such as grouping and counting by using key-generating functions. Sequences also support more diverse functions for extracting subsequences.

Many data types, such as lists, arrays, sets, and maps are implicitly sequences because they are enumerable collections. A function that takes a sequence as an argument works with any of the common F# data types, in addition to any .NET Framework data type that implements `System.Collections.Generic.IEnumerable<'T>`. Contrast this to a function that takes a list as an argument, which can only take lists. The type `seq<'T>` is a type abbreviation for `IEnumerable<'T>`. This means that any type that implements the generic `System.Collections.Generic.IEnumerable<'T>`, which includes arrays, lists, sets, and maps in F#, and also most .NET Framework collection types, is compatible with the `seq` type and can be used wherever a sequence is expected.
Many data types, such as lists, arrays, sets, and maps are implicitly sequences because they are enumerable collections. A function that takes a sequence as an argument works with any of the common F# data types, in addition to any .NET data type that implements `System.Collections.Generic.IEnumerable<'T>`. Contrast this to a function that takes a list as an argument, which can only take lists. The type `seq<'T>` is a type abbreviation for `IEnumerable<'T>`. This means that any type that implements the generic `System.Collections.Generic.IEnumerable<'T>`, which includes arrays, lists, sets, and maps in F#, and also most .NET collection types, is compatible with the `seq` type and can be used wherever a sequence is expected.
This conversation was marked as resolved by cartermp

This comment has been minimized.

Copy link
@mairaw

mairaw Nov 10, 2019

Contributor

should the implements here be xref links to the APIs?


## Module Functions

@@ -1,7 +1,7 @@
---
title: Type Extensions
description: Learn how F# type extensions allow you add new members to a previously defined object type.
ms.date: 02/08/2019
ms.date: 11/04/2019
---
# Type extensions

@@ -77,15 +77,12 @@ Optional type extensions are useful for extending a type that you have not defin
```fsharp
module Extensions
open System.Collections.Generic
type IEnumerable<'T> with
/// Repeat each element of the sequence n times
member xs.RepeatElements(n: int) =
seq {
for x in xs do
for i in 1 .. n do
yield x
for _ in 1 .. n -> x
}
```

@@ -1,7 +1,7 @@
---
title: F# coding conventions
description: Learn general guidelines and idioms when writing F# code.
ms.date: 10/22/2019
ms.date: 11/04/2019
---
# F# coding conventions

@@ -166,8 +166,8 @@ Instead, just use a simple class to hold dependencies:

```fsharp
type MyParametricApi(dep1, dep2, dep3) =
member __.Function1 arg1 = doStuffWith dep1 dep2 dep3 arg1
member __.Function2 arg2 = doStuffWith dep1 dep2 dep3 arg2
member _.Function1 arg1 = doStuffWith dep1 dep2 dep3 arg1
member _.Function2 arg2 = doStuffWith dep1 dep2 dep3 arg2
```

This enables the following:
@@ -367,7 +367,7 @@ module Transactions =
...
type Transactor(ctx, currentBalance) =
member __.ExecuteTransaction(txnType) =
member _.ExecuteTransaction(txnType) =
Transactions.doTransaction ctx txtType currentBalance
...
```
@@ -395,8 +395,8 @@ open TransactionsTestingUtil.TransactionsTestable
let testableContext =
{ new ITransactionContext with
member __.TheFirstMember() = ...
member __.TheSecondMember() = ... }
member _.TheFirstMember() = ...
member _.TheSecondMember() = ... }
let transactionRoutine = getTestableTransactionRoutine testableContext
@@ -489,15 +489,15 @@ open System.Collections.Generic
type Closure1Table() =
let t = Dictionary<Item0, HashSet<TerminalIndex>>()
member __.Add(key, value) =
member _.Add(key, value) =
if not (t.ContainsKey(key)) then
t.Add(key, value)
else
t.[key] <- value
member __.Count = t.Count
member _.Count = t.Count
member __.Contains(key, value) =
member _.Contains(key, value) =
match t.TryGetValue(key) with
| (true, v) -> v.Equals(value)
| (false, _) -> false
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.