Skip to content

Instantly share code, notes, and snippets.

@vzarytovskii
Created December 15, 2022 09:06
Show Gist options
  • Save vzarytovskii/7df29fd67bd9cfbbca27da7f4f6e6a4f to your computer and use it in GitHub Desktop.
Save vzarytovskii/7df29fd67bd9cfbbca27da7f4f6e6a4f to your computer and use it in GitHub Desktop.
F# 7
marp title theme progress paginate
true
F#7 and next
uncover
true
true

What's new in F# 7

and what's next


Static abstracts in interfaces

(runtime SRTPs, sort of)


Declaration

type IAddition<'T when 'T :> IAddition<'T>> =
    static abstract op_Addition: 'T * 'T -> 'T

Implementation

type Number<'T when IAddition<'T>>(value: 'T) =
    member _.Value with get() = value
    interface IAddition<Number<'T>> with
        static member op_Addition(a, b) = Number(a.Value + b.Value)

Consuming

let add<'T when IAddition<'T>>(x: 'T) (y: 'T) = 'T.op_Addition(x,y)
// or using the operator form
let add<'T when IAddition<'T>>(x: 'T) (y: 'T) = x + y

Generic math examples

open System.Numerics

let sum<'T when INumber<'T>>(values: seq<'T>) =
    let mutable result = 'T.Zero
    for value in values do
        result <- result + value
    result

SRTP Changes

Simplified syntax, constraints grouping

Example of a function with static trait

let inline average< ^T
               when ^T: (static member (+): ^T * ^T -> ^T)
               and  ^T: (static member DivideByInt : ^T * int -> ^T)
               and  ^T: (static member Zero : ^T)>
               (xs: ^T array) =
    let mutable sum : ^T = (^T : (static member Zero: ^T) ())
    for x in xs do
        sum <- (^T : (static member op_Addition: ^T * ^T -> ^T) (sum, x))
    (^T : (static member DivideByInt: ^T * int -> ^T) (sum, xs.Length))

Simplified call syntax and unified constraints

let inline average<'T
              when 'T: (static member (+): 'T * 'T -> 'T)
              and  'T: (static member DivideByInt : 'T * int -> 'T)
              and  'T: (static member Zero : 'T)>
              (xs: 'T array) =
    let mutable sum = 'T.Zero
    for x in xs do
        sum <- sum + x
    'T.DivideByInt(sum, xs.Length)

Constraints/traits grouping

type AverageOps<'T when 'T: (static member (+): 'T * 'T -> 'T)
                   and  'T: (static member DivideByInt : 'T*int -> 'T)
                   and  'T: (static member Zero : 'T)> = 'T

let inline average<'T when AverageOps<'T>>(xs: 'T array) =
    let mutable sum = 'T.Zero
    for x in xs do
        sum <- sum + x
    'T.DivideByInt(sum, xs.Length)

also works with instance members

type Length<'T when 'T: (member Length: int)> = 'T
let inline len<'T when Length<'T>>(x: 'T) =
    x.Length

Other F# 7 features

  • Required and init-only properties checking.
  • Reference assemblies support (still experimental).
  • Better self-contained deployments and NAOT support (reflection-free compilation).
  • ARM64 platform-specific compiler, and ARM64 target support in F# compiler.
  • Parallel type- and project-checking support (experimental, enabled via VS flag or by tooling authors).
  • General .NET7 improvements F# benefits from - https://devblogs.microsoft.com/dotnet/performance_improvements_in_net_7/

What's next (F# 8)

  • Better nullable interop (exhaustiveness, respecting and emitting .NET metadata, ? postfixed types support (under consideration))
  • Extension members support in SRTPs.
      type Option<'T> with
          member _.Bind(...) = ...
      type Result<'T> with
          member _.Bind(...) = ...
      let inline bind<'M when 'M: (member Bind: ... -> ...)> f (m: 'M) = m.Bind(f)
  • Scoped refs and better escape analysis

Continued

  • Anonymous type-tagged unions support
    let intOrString : (int|string) = if true then 1 else "Hello"
    let prettyPrint (x: (int8|int16|int64|string)) =
        match x with
        | :? int8 -> prettyPrintInt8 x
        | :? int16 -> prettyPrintInt16 x
        | :? int64 -> prettyPrintInt64 x
        | :? string as y -> prettyPrintString y
  • Tooling performance improvements - parallel type-checking, incremental compilation.
  • Optional fun keyword for lambdas.
  • Raw interpolated strings (aka double-dollar or $$).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment