Skip to content
Draft
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
486 changes: 485 additions & 1 deletion docs/fsharp/whats-new/fsharp-8.md

Large diffs are not rendered by default.

22 changes: 22 additions & 0 deletions docs/fsharp/whats-new/snippets/fsharp-8/LiteralArithmetic.fsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Arithmetic operators in literals
let [<Literal>] bytesInKB = 2f ** 10f
let [<Literal>] bytesInMB = bytesInKB * bytesInKB
let [<Literal>] bytesInGB = 1 <<< 30
let [<Literal>] customBitMask = 0b01010101uy
let [<Literal>] inverseBitMask = ~~~ customBitMask

printfn "Bytes in KB: %f" bytesInKB
printfn "Bytes in MB: %f" bytesInMB
printfn "Bytes in GB: %d" bytesInGB
printfn "Custom bit mask: %d" customBitMask
printfn "Inverse bit mask: %d" inverseBitMask

// Works for enum values
type MyEnum =
| A = (1 <<< 5)
| B = (17 * 45 % 13)
| C = bytesInGB

printfn "MyEnum.A: %d" (int MyEnum.A)
printfn "MyEnum.B: %d" (int MyEnum.B)
printfn "MyEnum.C: %d" (int MyEnum.C)
34 changes: 34 additions & 0 deletions docs/fsharp/whats-new/snippets/fsharp-8/NestedRecordUpdate.fsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// Nested record field copy and update
type SteeringWheel = { Type: string }
type CarInterior = { Steering: SteeringWheel; Seats: int }
type Car = { Interior: CarInterior; ExteriorColor: string option }

let myCar = {
Interior = {
Steering = { Type = "wheel" }
Seats = 4
}
ExteriorColor = Some "red"
}

// Before F# 8
let beforeThisFeature x =
{ x with Interior = { x.Interior with
Steering = {x.Interior.Steering with Type = "yoke"}
Seats = 5
}
}

// With F# 8
let withTheFeature x = { x with Interior.Steering.Type = "yoke"; Interior.Seats = 5 }

let updatedCar1 = beforeThisFeature myCar
let updatedCar2 = withTheFeature myCar

printfn "Before: %A" updatedCar1
printfn "After: %A" updatedCar2

// Works for anonymous records too
let alsoWorksForAnonymous (x:Car) = {| x with Interior.Seats = 7; Price = 99_999 |}
let anonResult = alsoWorksForAnonymous myCar
printfn "Anonymous: %A" anonResult
32 changes: 32 additions & 0 deletions docs/fsharp/whats-new/snippets/fsharp-8/PropertyShorthand.fsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// Property shorthand examples
type Person = {Name : string; Age : int}
let people = [ {Name = "Joe"; Age = 20} ; {Name = "Will"; Age = 30} ; {Name = "Joe"; Age = 51}]

// Before F# 8
let beforeThisFeature =
people
|> List.distinctBy (fun x -> x.Name)
|> List.groupBy (fun x -> x.Age)
|> List.map (fun (x,y) -> y)
|> List.map (fun x -> x.Head.Name)
|> List.sortBy (fun x -> x.ToString())

printfn "Before: %A" beforeThisFeature

// With F# 8
let possibleNow =
people
|> List.distinctBy _.Name
|> List.groupBy _.Age
|> List.map snd
|> List.map _.Head.Name
|> List.sortBy _.ToString()

printfn "After: %A" possibleNow

// Standalone lambda functions
let ageAccessor : Person -> int = _.Age
let getNameLength = _.Name.Length

printfn "Age accessor: %d" (ageAccessor people[0])
printfn "Name length: %d" (getNameLength people[0])
14 changes: 14 additions & 0 deletions docs/fsharp/whats-new/snippets/fsharp-8/StaticInInterfaces.fsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// Static members in interfaces
[<Interface>]
type IDemoable =
abstract member Show: string -> unit
static member AutoFormat(a) = sprintf "%A" a

// Example implementation
type MyType() =
interface IDemoable with
member _.Show(s) = printfn "Showing: %s" s

let value = 42
let formatted = IDemoable.AutoFormat(value)
printfn "Formatted: %s" formatted
24 changes: 24 additions & 0 deletions docs/fsharp/whats-new/snippets/fsharp-8/StaticLetInDU.fsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// Static let in discriminated unions
open FSharp.Reflection

type AbcDU = A | B | C
with
static let namesAndValues =
FSharpType.GetUnionCases(typeof<AbcDU>)
|> Array.map (fun c -> c.Name, FSharpValue.MakeUnion (c,[||]) :?> AbcDU)
static let stringMap = namesAndValues |> dict
static let mutable cnt = 0

static do printfn "Init done! We have %i cases" stringMap.Count
static member TryParse text =
let cnt = System.Threading.Interlocked.Increment(&cnt)
stringMap.TryGetValue text, sprintf "Parsed %i" cnt

// Test the functionality
let result1 = AbcDU.TryParse "A"
let result2 = AbcDU.TryParse "B"
let result3 = AbcDU.TryParse "Invalid"

printfn "Parse 'A': %A" result1
printfn "Parse 'B': %A" result2
printfn "Parse 'Invalid': %A" result3
18 changes: 18 additions & 0 deletions docs/fsharp/whats-new/snippets/fsharp-8/StringInterpolation.fsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// Extended string interpolation syntax
let classAttr = "item-panel"

// Before F# 8 - braces must be doubled
let cssOld = $""".{classAttr}:hover {{background-color: #eee;}}"""
printfn "CSS Old: %s" cssOld

// With F# 8 - multiple $ signs to define interpolation level
let cssNew = $$""".{{classAttr}}:hover {background-color: #eee;}"""
printfn "CSS New: %s" cssNew

// HTML templating with triple $$$
let templateNew = $$$"""
<div class="{{{classAttr}}}">
<p>{{title}}</p>
</div>
"""
printfn "Template: %s" templateNew
22 changes: 22 additions & 0 deletions docs/fsharp/whats-new/snippets/fsharp-8/TailCallAttribute.fsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// TailCall attribute examples

// This produces a warning - not tail recursive
[<TailCall>]
let rec factorialClassic n =
match n with
| 0u | 1u -> 1u
| _ -> n * (factorialClassic (n - 1u))

// This is tail recursive - no warning
[<TailCall>]
let rec factorialWithAcc n accumulator =
match n with
| 0u | 1u -> accumulator
| _ -> factorialWithAcc (n - 1u) (n * accumulator)

// Test both
let result1 = factorialClassic 5u
let result2 = factorialWithAcc 5u 1u

printfn "Classic factorial(5): %d" result1
printfn "Accumulator factorial(5): %d" result2
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// try-with within collection expressions
let sum =
[ for x in [0;1] do
try
yield 1
yield (10/x)
yield 100
with _ ->
yield 1000 ]
|> List.sum

printfn "Sum: %d" sum
printfn "Expected: 1112 (list is [1;1000;1;10;100])"
Loading