Bits and pieces of F# code picked up on the learning path.
This method allows stopping at breakpoints, unlike dotnet [watch] run which does not allow that.
- Click
Run and Debugbutton on the right panel or pressCtrl-Shift-D - Click
Start Debuggingor pressF5key - Click the
...create a launch.json file.link - Select
.Net Core - Click
Add Configuration...button - Select
{} .NET: Lauch .NET Core Console App - Fix the path to the executable (the path can be determined by looking into
...\bin\Debugfolder):- Replace
<target-framework>withnet5.0(or other actual folder name) - Replace
project-name.dll/exewith the name of the actual produced dll / exe file
- Replace
- Rerun
Start Debugging - Click
Create Task - Select
Create tasks.json file from template - Select
.NET Core - Optional: Add command line argumets (
argv) into thelanuch.jsonfile, lineargs
Type dotnet watch run [args] in the command line.
Named tuples are single discriminated union tuples:
type Point = x: int * y: int // Does not compile - no name for the tuple
type Point = Point of x: int * y: int // Works! let x = (1,2)
let x1,x2 = x // Normal tuple deconstruction at let-binding
let xFunc (x1,x2) = // Normal tuple deconstruction in function let-binding
x1 * x2
let point = Point (3,4)
let (Point(x,y)) = point // Deconstruction of the union and the inner tuple
let pointFunc (Point(x,y)) = ... // Deconstruction as function inputBut we are also able, in those union cases, to deconstruct only what we want by name (with a slightly different syntax, note the semicolon):
let point = Point (5,6)
let (Point(x = xaxis; y = yaxis)) = pointThis is helpful in cases where we have 'large' tuples and in a given place are only interested in one part of the tuple:
type Point3D = Point3D of x: int * y: int * z: int
let point = Point3D (3, 4, 5)
let getZ (Point3D (z = zValue)) = zValue
let getXZ (Point3D (x = xValue; z = zValue)) = xValue, zValue
let getXZ' (Point3D(x, _, z)) = x, z // This is equivalent extraction, but clunky for large tuples
getZ point // 5
getXZ point // 3, 5Not sure how we got here but never mind. From https://docs.microsoft.com:
Active patterns enable you to define named partitions that subdivide input data, so that you can use these names in a pattern matching expression just as you would for a discriminated union. You can use active patterns to decompose data in a customized manner for each partition.
Active patterns are actually functions and can be user like those too.
// Active pattern of one choice.
let (|identifier|) [arguments] valueToMatch = expression
// Active Pattern with multiple choices.
// Uses a FSharp.Core.Choice<_,...,_> based on the number of case names. In F#, the limitation n <= 7 applies.
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.
let (|identifier|_|) [arguments] valueToMatch = expressionThere can be up to seven partitions in an active pattern definition. The expression describes the form into which to decompose the data. You can use an active pattern definition to define the rules for determining which of the named partitions the values given as arguments belong to. The (| and |) symbols are referred to as banana clips and the function created by this type of let binding is called an active recognizer.
As an example, consider the following active pattern with an argument.
let (|Even|Odd|) input = if input % 2 = 0 then Even else Odd
let testNumber input =
match input with
| Even -> printfn $"{input} is even"
| Odd -> printfn $"{input} is odd"Another use of active patterns is to decompose data types in multiple ways, such as when the same underlying data has various possible representations. For example, a Color object could be decomposed into an RGB representation or an HSB representation.
open System.Drawing
let (|RGB|) (color: Color) = (color.R, color.G, color.B)
let (|RGBA|) (color: Color) = (color.R, color.G, color.B, color.A)
let (|HSB|) (color: Color) =
(color.GetHue(), color.GetSaturation(), color.GetBrightness())
let printRGB (color: Color) =
match color with
| RGB (r, g, b) -> printfn $"Red: {r}, Green: {g}, Blue: {b}"
let printHSB (color: Color) =
match color with
| HSB (h, s, b) -> printfn $"Hue: {h}, Saturation: {s}, Brightness: {b}"
let printAll (color: Color) =
printfn $"Color: {color}:"
color |> printRGB
color |> printRGBA
color |> printHSB
printAll Color.Red