Opérateurs

Opérateur

Est défini comme une fonction :

  • Opérateur unaire : let (~symbols) = ...

  • Opérateur binaire : let (symbols) = ...

  • Symbols = combinaison de % & * + - . / < = > ? @ ^ | ! $

2 façons d'utiliser les opérateurs :

  • En tant qu'opérateur → infixe 1 + 2 ou préfixe -1

  • En tant que fonction → chars entre () : (+) 1 21 + 2

Opérateurs standards

Également définis dans FSharp.Core

  • Opérateurs arithmétiques : +, -...

  • Opérateurs de pipeline

  • Opérateurs de composition

Opérateurs Pipe

Opérateurs binaires, placés entre une valeur simple et une fonction

  • Appliquent la valeur à la fonction = Passe la valeur en argument

  • Permettent d'éviter la mise entre parenthèses / précédence

  • ∃ plusieurs pipes

    • Pipe right |> : le pipe "classique"

    • Pipe left <| a.k.a. pipe inversé

    • Pipe right 2 ||>

    • Etc.

Opérateur Pipe right |>

Inverse l'ordre entre fonction et valeur : val |> fnfn val

  • Ordre naturel "sujet verbe", comme appel méthode d'un objet (obj.M(x))

  • Pipeline : enchaîner appels de fonctions, sans variable intermédiaire

  • Aide inférence d'objet. Exemple :

Opérateur Pipe left <|

fn <| expressionfn (expression)

  • ☝ Usage un peu moins courant que |>

  • ✅ Avantage mineur : permet d'éviter des parenthèses

  • ❌ Inconvénient majeur : se lit de droite à gauche → Inverse du sens lecture naturel en anglais et ordre exécution

Quid d'une expression telle que x |> fn <| y

Exécutée de gauche à droite : (x |> fn) <| y(fn x) <| yfn x y

  • En théorie : permettrait d'utiliser fn en position infixée

  • En pratique : difficile à lire à cause du double sens de lecture ❗

👉 Conseil : À ÉVITER

Opérateur Pipe right 2 ||>

(x, y) ||> fnfn x y

  • Pour passer 2 arguments à la fois, sous la forme d'un tuple

  • Usage peu fréquent mais pratique avec fold pour passer la valeur initiale (seed) et la liste avant de définir la fonction folder.

☝️ Cet opérateur correspond à la notion de "décurryfication" c'est-à-dire à pouvoir appeler une fonction f curryfiée en lui passant ces 2 paramètres sous la forme d'un tuple :

Opérateur Compose >>

Opérateurs binaires, placés entre deux fonctions → Le résultat de la 1ère fonction servira d'argument à la 2e fonction

f >> gfun x -> g (f x)fun x -> x |> f |> g

💡 Peut se lire « f ensuite g »

⚠️️ Les types doivent correspondre : f: 'T -> 'U et g: 'U -> 'V → On obtient une fonction de signature 'T -> 'V

Opérateur Compose inverse <<

Sert rarement, sauf pour retrouver un ordre naturel des termes

Exemple avec opérateur not (qui remplace le ! du C♯) :

Pipe |> ou Compose >> ?

Compose let h = f >> g

  • Composition de 2 fonctions f et g

  • Renvoie une nouvelle fonction

  • Les fonctions f et g ne sont exécutées que lorsque h l'est

Pipe let result = value |> f

  • Juste une syntaxe différente pour passer un argument

  • La fonction f est :

    • Exécutée si elle n'a qu'1! param → result est une valeur

    • Appliquée partiellement sinon → result est une fonction

Style Point-free

A.k.a Programmation tacite

Fonction définie par composition ou application partielle ou avec functionParamètre implicite (point fait référence à un point dans un espace)

💡 Conseil : l'expression anglaise Point-free est trompeuse en français car le terme Point désigne un point dans l'espace et non pas le point pour accéder à un membre d'un objet : obj.Member qui correspond à dot en Anglais. Mieux vaut employer Programmation tacite.

Pros/Cons ⚖️

✅ Avantages

Style concis • Abstraction des paramètres, opère au niveau fonctions

❌ Inconvénients

Perd le nom du paramètre devenu implicite dans la signature → Sans importance si la fonction reste compréhensible :

  • Nom du param non significatif (ex. x)

  • Type du param et nom de la fonction suffisent → Déconseillé pour une API publique

Limite 🛑

Marche mal avec fonctions génériques :

🔗 https://docs.microsoft.com/en-us/dotnet/fsharp/style-guide/conventions #partial-application-and-point-free-programming

Opérateurs personnalisés

2 possibilités :

  • Surcharge d'opérateurs

  • Création d'un nouvel opérateur

Surcharge d'opérateurs

En général, concerne un type spécifique → Surcharge définie à l'intérieur du type associé (comme en C♯)

Création d'un nouvel opérateur

  • Définition plutôt dans un module ou dans un type associé

  • Cas d'usage classique : alias fonction existante, utilisé en infixe

Symboles autorisés dans un opérateur

Opérateur unaire "tilde"~ suivi de +, -, +., -., %, %%, &, &&

Opérateur unaire "snake" → Plusieurs ~, ex : ~~~~

Opérateur unaire "bang"! suivi combinaison de !, %, &, *, +, ., /, <, =, >, @, ^, |, ~, ? → Sauf != (!=) qui est binaire

Opérateur binaire → Toute combinaison de !, %, &, *, +, ., /, <, =, >, @, ^, |, ~, ? → qui ne correspond pas à un opérateur unaire

Symboles à l'usage

Tout opérateur s'utilise tel quel ❗ Sauf opérateur unaire "tilde" : s'utilise sans le ~ initial

Opérateur
Déclaration
Usage

Unaire tilde

let (~&&) x = …

&&x

Unaire snake

let (~~~) x = …

~~~x

Unaire bang

let (!!!) x = …

!!!x

Binaire

let (<ˆ>) x y = …

x <ˆ> y

☝ Pour définir un opérateur commençant ou terminant par un *, il faut mettre un espace entre ( et * ainsi qu'entre * et ) pour distinguer d'un bloc de commentaires F# (* *)let ( *+ ) x y = x * y + y

Opérateur ou fonction ?

Opérateur infixe vs fonction

👍 Pour :

  • Respecte l'ordre naturel de lecture (gauche → droite)

  • Permet d'éviter des parenthèses → 1 + 2 * 3 vs multiply (add 1 2) 3

⚠️ Contre :

  • Un opérateur "folklorique" (ex : @!) sera moins compréhensible qu'une fonction dont le nom utilise le langage du domaine

Utiliser un opérateur en tant que fonction

💡 On peut utiliser l'application partielle d'un opérateur binaire :

Exemples :

  • A la place d'une lambda : → (+) 1fun x -> x + 1

  • Pour définir une nouvelle fonction : → let isPositive = (<) 0let isPositive x = 0 < xx >= 0

Last updated

Was this helpful?