Recherche…


Définition de l'option

Une Option est une union discriminée avec deux cas, None ou Some .

type Option<'T> = Some of 'T | None

Utilisez Option <'T> sur des valeurs nulles

Dans les langages de programmation fonctionnels comme null valeurs null F# sont considérés comme potentiellement nuisibles et de style médiocre (non idiomatique).

Considérez ce code C# :

string x = SomeFunction ();
int    l = x.Length;

x.Length lancera si x est null ajoutons une protection:

string x = SomeFunction ();
int    l = x != null ? x.Length : 0;

Ou:

string x = SomeFunction () ?? "";
int    l = x.Length;

Ou:

string x = SomeFunction ();
int    l = x?.Length;

Dans les idiomatiques F# null valeurs null ne sont pas utilisées, notre code ressemble à ceci:

let x = SomeFunction ()
let l = x.Length

Cependant, il est parfois nécessaire de représenter des valeurs vides ou invalides. Ensuite, nous pouvons utiliser Option<'T> :

let SomeFunction () : string option = ...

SomeFunction soit retourne Some string valeur ou None . Nous extrayons la valeur de string utilisant une correspondance de modèle

let v =
  match SomeFunction () with
  | Some x  -> x.Length
  | None    -> 0

La raison pour laquelle ce code est moins fragile que:

string x = SomeFunction ();
int    l = x.Length;

C'est parce que nous ne pouvons pas appeler Length sur une string option . Nous devons extraire la valeur de string utilisant la correspondance de modèle et, ce faisant, nous sommes sûrs que la valeur de string est sûre à utiliser.

Le module d'option permet la programmation orientée chemin de fer

La gestion des erreurs est importante mais peut rendre un algorithme élégant en désordre. La programmation orientée chemin de fer ( ROP ) est utilisée pour rendre la gestion des erreurs élégante et composable.

Considérons la fonction simple f :

let tryParse s =
  let b, v = System.Int32.TryParse s
  if b then Some v else None

let f (g : string option) : float option =
  match g with
  | None    -> None
  | Some s  ->
    match tryParse s with           // Parses string to int
    | None              -> None
    | Some v when v < 0 -> None     // Checks that int is greater than 0
    | Some v -> v |> float |> Some  // Maps int to float

Le but de f est d'analyser l'entrée string valeur (s'il y a Some ) en un int . Si l' int est supérieur à 0 on le transforme en float . Dans tous les autres cas, nous renflouons avec None .

Bien que la fonction imbriquée soit extrêmement simple, la match imbriquée diminue considérablement la lisibilité.

ROP observe que nous avons deux types de chemins d'exécution dans notre programme

  1. Happy path - calculera éventuellement une Some valeur
  2. Chemin d'erreur - Tous les autres chemins produisent None

Comme les chemins d’erreur sont plus fréquents, ils ont tendance à prendre le relais. Nous aimerions que le code de chemin heureux soit le chemin de code le plus visible.

Une fonction équivalente g utilisant ROP pourrait ressembler à ceci:

let g (v : string option) : float option =
  v
  |> Option.bind    tryParse  // Parses string to int
  |> Option.filter  ((<) 0)   // Checks that int is greater than 0
  |> Option.map     float     // Maps int to float

Cela ressemble beaucoup à la façon dont nous avons tendance à traiter les listes et les séquences en F# .

On peut voir une Option<'T> comme une List<'T> qui ne peut contenir que 0 ou 1 élément où Option.bind se comporte comme List.pick (conceptuellement, Option.bind mieux List.collect à List.collect mais List.pick peut être plus facile à comprendre).

bind , filter et map gère les chemins d’erreur et g ne contient que le code de chemin heureux.

Toutes les fonctions qui acceptent directement l' Option<_> et renvoient l' Option<_> sont directement composables avec |> et >> .

ROP augmente donc la lisibilité et la composabilité.

Utiliser les types d'option de C #

Ce n'est pas une bonne idée d'exposer les types d'options au code C #, car C # ne permet pas de les gérer. Les options sont soit d'introduire FSharp.Core comme une dépendance dans votre projet C # (ce que vous devez faire si vous utilisez une bibliothèque F # non conçue pour l'interopérabilité avec C #), soit de changer les valeurs None en null .

Pré-F # 4.0

Pour ce faire, créez votre propre fonction de conversion:

let OptionToObject opt =
    match opt with
    | Some x -> x 
    | None -> null

Pour les types de valeur, vous devez avoir recours à la boxe ou à System.Nullable .

let OptionToNullable x = 
    match x with 
    | Some i -> System.Nullable i
    | None -> System.Nullable ()

F # 4.0

Dans F # 4.0, les fonctions ofObj , toObj , ofNullable et toNullable introduites dans le module Option . Dans F # interactive, ils peuvent être utilisés comme suit:

let l1 = [ Some 1 ; None ; Some 2]
let l2 = l1 |> List.map Option.toNullable;;

// val l1 : int option list = [Some 1; null; Some 2]
// val l2 : System.Nullable<int> list = [1; null; 2]

let l3 = l2 |> List.map Option.ofNullable;;
// val l3 : int option list = [Some 1; null; Some 2]

// Equality
l1 = l2 // fails to compile: different types
l1 = l3 // true

Notez que None compile en null interne. Cependant, en ce qui concerne F #, il s'agit d'un None .

let lA = [Some "a"; None; Some "b"]
let lB = lA |> List.map Option.toObj

// val lA : string option list = [Some "a"; null; Some "b"]
// val lB : string list = ["a"; null; "b"]

let lC = lB |> List.map Option.ofObj
// val lC : string option list = [Some "a"; null; Some "b"]

// Equality
lA = lB // fails to compile: different types
lA = lC // true


Modified text is an extract of the original Stack Overflow Documentation
Sous licence CC BY-SA 3.0
Non affilié à Stack Overflow