F# Training
Formation F#
Formation F#
  • Intro
  • Bases
    • Le F♯, c'est quoi ?
    • Syntaxe
    • Premiers concepts
    • 🍔 Quiz
  • Fonctions
    • Signature
    • Fonctions
    • Fonctions standard
    • OpĂ©rateurs
    • Fonctions : complĂ©ments
    • 🍔 Quiz
    • 📜 RĂ©cap’
  • Types composites
    • GĂ©nĂ©ralitĂ©s
    • Tuples
    • Records
    • Unions
    • Enums
    • Records anonymes
    • Types valeur
    • 🍔 Quiz
  • Types : ComplĂ©ments
    • Type unit
    • GĂ©nĂ©riques
    • Types flexibles
    • UnitĂ©s de mesure
    • Conversion
    • Exceptions F#
  • Pattern matching
    • Patterns
    • Match expression
    • 🚀 Active Patterns
    • 📜 RĂ©cap’
  • Collections
    • Vue d'ensemble
    • Types
    • Fonctions gĂ©nĂ©riques
    • Fonctions spĂ©cifiques
    • 🍔 Quiz
    • 📜 RĂ©cap’
  • Programmation asynchrone
    • Workflow asynchrone
    • Interop avec la TPL .NET
    • 📜 RĂ©cap’
  • Types monadiques
    • Type Option
    • Type Result
    • Smart constructor
    • 🚀 Computation expression (CE)
    • 🚀 CE - Fondements thĂ©oriques
    • 📜 RĂ©cap’
  • Module & namespace
    • Vue d'ensemble
    • Namespace
    • Module
    • 🍔 Quiz
    • 📜 RĂ©cap’
  • OrientĂ©-objet
    • Introduction
    • Membres
    • Extensions de type
    • Classe, structure
    • Interface
    • Expression objet
    • Recommandations
  • 🩚 Aller plus loin
Powered by GitBook
On this page
  • CE : le couteau suisse ✹
  • MonoĂŻde
  • CE monoĂŻdale
  • Monade
  • Lois
  • Langages
  • CE monadique
  • CE monadique et gĂ©nĂ©rique
  • Exemple avec le type Option
  • CE monadiques spĂ©cifiques
  • Applicative
  • CE applicative
  • Applicative vs Monade
  • Autres CE
  • Expecto
  • Farmer
  • Saturn
  • Aller + loin

Was this helpful?

Edit on GitHub
  1. Types monadiques

🚀 CE - Fondements thĂ©oriques

CE = Computation Expression

CE : le couteau suisse ✹

Les computation expressions servent à différentes choses :

  • C♯ yield return → F♯ seq {}

  • C♯ async/await → F♯ async {}

  • C♯ expressions LINQ from... select → F♯ query {}

  • ...

Fondements théoriques sous-jacents :

  • MonoĂŻde

  • Monade

  • Applicative

MonoĂŻde

≃ Type T dĂ©finissant un ensemble comportant :

  1. Opération (+) : T -> T -> T

    • Pour combiner des ensembles et garder le mĂȘme "type"

    • Associative : a + (b + c) ≡ (a + b) + c

  2. ÉlĂ©ment neutre (aka identity) ≃ ensemble vide

    • Combinable Ă  tout ensemble sans effet

    • a + e ≡ e + a ≡ a

CE monoĂŻdale

Le builder d'une CE monoĂŻdale (telle que seq) dispose a minima de :

  • Yield pour construire l'ensemble Ă©lĂ©ment par Ă©lĂ©ment

  • Combine ≡ (+) (Seq.append)

  • Zero ≡ Ă©lĂ©ment neutre (Seq.empty)

S'y ajoute généralement (entre autres) :

  • For pour supporter for x in xs do ...

  • YieldFrom pour supporter yield!

Monade

≃ Type gĂ©nĂ©rique M<'T> comportant :

  1. Fonction return de construction

    • Signature : (value: 'T) -> M<'T>

    • ≃ Wrap une valeur

  2. Fonction bind de "liaison" (aka opérateur >>=)

    • Signature : (f: 'T -> M<'U>) -> M<'T> -> M<'U>

    • Utilise la valeur wrappĂ©e, la "map" avec la fonction f vers une valeur d'un autre type et "re-wrap" le rĂ©sultat

Lois

return ≡ Ă©lĂ©ment neutre pour bind

  • À gauche : return x |> bind f ≡ f x

  • À droite : m |> bind return ≡ m

bind est associatif

  • m |> bind f |> bind g ≡ m |> bind (fun x -> f x |> bind g)

Langages

Haskell

  • Monades beaucoup utilisĂ©es. Les + communes : IO, Maybe, State, Reader.

  • Monad est une classe de type pour crĂ©er facilement ses propres monades.

F♯

  • Certaines CE permettent des opĂ©rations monadiques.

  • Plus rarement utilisĂ©es directement (sauf par des Haskellers)

C♯

  • Monade implicite dans LINQ

  • Librairie LanguageExt de programmation fonctionnelle

CE monadique

Le builder d'une CE monadique dispose des méthodes Return et Bind.

Les types Option et Result sont monadiques. → On peut leur crĂ©er leur propre CE :

type OptionBuilder() =
    member _.Bind(x, f) = x |> Option.bind f
    member _.Return(x) = Some x

type ResultBuilder() =
    member _.Bind(x, f) = x |> Result.bind f
    member _.Return(x) = Ok x

CE monadique et générique

FSharpPlus propose une CE monad → Marche pour tous les types monadiques : Option, Result, ... et mĂȘme Lazy !

#r "nuget: FSharpPlus"
open FSharpPlus

let lazyValue = monad {
    let! a = lazy (printfn "I'm lazy"; 2)
    let! b = lazy (printfn "I'm lazy too"; 10)
    return a + b
} // System.Lazy<int>

let result = lazyValue.Value
// I'm lazy
// I'm lazy too
// val result : int = 12

Exemple avec le type Option

#r "nuget: FSharpPlus"
open FSharpPlus

let addOptions x' y' = monad {
    let! x = x'
    let! y = y'
    return x + y
}

let v1 = addOptions (Some 1) (Some 2) // Some 3
let v2 = addOptions (Some 1) None     // None
#r "nuget: FSharpPlus"
open FSharpPlus

let v1 = monad {
    let! a = Ok 2
    let! b = Some 10
    return a + b
} // đŸ’„ Error FS0043...

let v2 = monad {
    let! a = Ok 2
    let! b = Some 10 |> Option.toResult
    return a + b
} // val v2 : Result<int,unit> = Ok 12

CE monadiques spécifiques

Librairie FsToolkit.ErrorHandling propose : ‱ CE option {} spĂ©cifique au type Option<'T> (exemple ci-dessous) ‱ CE result {} spĂ©cifique au type Result<'Ok, 'Err>

☝ RecommandĂ© car + explicite que CE monad

#r "nuget: FSToolkit.ErrorHandling"
open FsToolkit.ErrorHandling

let addOptions x' y' = option {
    let! x = x'
    let! y = y'
    return x + y
}

let v1 = addOptions (Some 1) (Some 2) // Some 3
let v2 = addOptions (Some 1) None     // None

Applicative

A.k.a Applicative Functor

≃ Type gĂ©nĂ©rique M<'T>

3 "styles" :

Style A : Applicatives avec apply/<*> et pure/return ‱ ❌ Pas facile Ă  comprendre ‱ 💡 PrĂ©sentĂ© par JĂ©rĂ©mie Chassaing dans le talk ❝Applicatives in real life❞ ‱ ☝ DĂ©conseillĂ© par Don Syme dans cette note de nov. 2020

Style B : Applicatives avec mapN ‱ map2, map3... map5 combine 2 Ă  5 valeurs wrappĂ©es

Style C : Applicatives avec let! ... and! ... dans une CE ‱ MĂȘme principe : combiner plusieurs valeurs wrappĂ©es ‱ Disponible Ă  partir de F♯ 5 (annonce de nov. 2020)

☝ Conseil : Styles B et C sont autant recommandĂ©s l'un que l'autre.

CE applicative

Librairie FsToolkit.ErrorHandling propose : ‱ Type Validation<'Ok, 'Err> ≡ Result<'Ok, 'Err list> ‱ CE validation {} supportant syntaxe let!...and!...

Permet d'accumuler les erreurs → Usages : ‱ Parsing d'inputs externes ‱ Smart constructor (Exemple de code slide suivante...)

#r "nuget: FSToolkit.ErrorHandling"
open FsToolkit.ErrorHandling

type [<Measure>] cm
type Customer = { Name: string; Height: int<cm> }

let validateHeight height =
    if height <= 0<cm>
    then Error "Height must me positive"
    else Ok height

let validateName name =
    if System.String.IsNullOrWhiteSpace name
    then Error "Name can't be empty"
    else Ok name

module Customer =
    let tryCreate name height : Result<Customer, string list> =
        validation {
            let! validName = validateName name
            and! validHeight = validateHeight height
            return { Name = validName; Height = validHeight }
        }

let c1 = Customer.tryCreate "Bob" 180<cm>  // Ok { Name = "Bob"; Height = 180 }
let c2 = Customer.tryCreate "Bob" 0<cm> // Error ["Height must me positive"]
let c3 = Customer.tryCreate "" 0<cm>    // Error ["Name can't be empty"; "Height must me positive"]

Applicative vs Monade

Soit N opérations tryXxx renvoyant un Option ou Result

Style monadique :

  • Avec bind ou CE let! ... let! ...

  • ChaĂźne les opĂ©rations, exĂ©cutĂ©e 1 Ă  1, la N dĂ©pendant de la N-1

  • S'arrĂȘte Ă  1Ăšre opĂ©ration KO → juste 1Ăšre erreur dans Result ①

  • Railway-oriented programming de Scott Wlaschin

module Result =
    // f : 'T -> Result<'U, 'Err>
    // x': Result<'T, 'Err>
    //  -> Result<'U, 'Err>
    let bind f x' =
        match x' with
        | Error e  -> Error e // 👈 (1)
        | Ok value -> f value

Style applicatif :

  • Avec mapN ou CE let! ... and! ...

  • Combine 2..N opĂ©rations indĂ©pendantes → parallĂ©lisables 👍

  • Permet de combiner les cas Error contenant une List ②

module Validation =
    // f : 'T -> 'U -> Result<'V, 'Err list>
    // x': Result<'T, 'Err list>
    // y': Result<'U, 'Err list>
    //  -> Result<'V, 'Err list>
    let map2 f x' y' =
        match x', y' with
        | Ok x, Ok y -> f x y
        | Ok _, Error errors | Error errors, Ok _ -> Error errors
        | Error errors1, Error errors2 -> Error (errors1 @ errors2) // 👈 ②

Autres CE

On a vu 2 librairies qui Ă©tendent F♯ et proposent leurs CE :

  • FSharpPlus → monad

  • FsToolkit.ErrorHandling → option, result, validation

Beaucoup de librairies ont leur propre DSL (Domain Specific Language.) Certaines s'appuient alors sur des CE :

  • Expecto

  • Farmer

  • Saturn

Expecto

❝ Librairie de testing : assertions + runner ❞ 🔗 https://github.com/haf/expecto

open Expecto

let tests =
  test "A simple test" {
    let subject = "Hello World"
    Expect.equal subject "Hello World" "The strings should equal"
  }

[<EntryPoint>]
let main args =
  runTestsWithCLIArgs [] args tests

Farmer

❝ Infrastructure-as-code pour Azure ❞

🔗 github.com/compositionalit/farmer

// Create a storage account with a container
let myStorageAccount = storageAccount {
    name "myTestStorage"
    add_public_container "myContainer"
}

// Create a web app with application insights that's connected to the storage account
let myWebApp = webApp {
    name "myTestWebApp"
    setting "storageKey" myStorageAccount.Key
}

// Create an ARM template (Azure Resource Manager)
let deployment = arm {
    location Location.NorthEurope
    add_resources [
        myStorageAccount
        myWebApp
    ]
}

// Deploy it to Azure!
deployment
|> Writer.quickDeploy "myResourceGroup" Deploy.NoParameters

Saturn

❝ Framework Web au-dessus de ASP.NET Core, pattern MVC ❞

🔗 saturnframework.org

open Saturn
open Giraffe

let app = application {
    use_router (text "Hello World from Saturn")
}

run app

Aller + loin

đŸ“č Extending F# through Computation Expressions - 📜 Slides

🔗 Computation Expressions Workshop

Previous🚀 Computation expression (CE)Next📜 RĂ©cap’

Last updated 2 years ago

Was this helpful?

Limite : on ne peut pas mélanger plusieurs types monadiques !

⚠