Ricerca…


Definizione dell'opzione

Option è un'unione discriminata con due casi, None o Some .

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

Usa l'opzione <'T> su valori nulli

Nei linguaggi di programmazione funzionale come F# null valori null sono considerati potenzialmente dannosi e di stile scadente (non idiomatici).

Considera questo codice C# :

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

x.Length getterà se x è null aggiungiamo protezione:

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

O:

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

O:

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

In F# idiomatic null valori null non sono usati, quindi il nostro codice assomiglia a questo:

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

Tuttavia, a volte è necessario rappresentare valori vuoti o non validi. Quindi possiamo usare Option<'T> :

let SomeFunction () : string option = ...

SomeFunction restituisce Some valore di string o None . Estraiamo il valore della string utilizzando la corrispondenza del modello

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

Il motivo per cui questo codice è meno fragile di:

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

È perché non possiamo chiamare la Length su string option . Abbiamo bisogno di estrarre il valore della string usando la corrispondenza del modello e così facendo ci garantisce che il valore della string è sicuro da usare.

Il modulo opzionale consente la programmazione orientata alle ferrovie

La gestione degli errori è importante ma può trasformare un elegante algoritmo in un pasticcio. ROP ( Railway Oriented Programming ) è utilizzato per rendere la gestione degli errori elegante e componibile.

Considera la semplice funzione 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

Lo scopo di f è quello di analizzare il valore della string input (se c'è Some ) in un int . Se int è maggiore di 0 lo gettiamo in un float . In tutti gli altri casi eseguiamo il salvataggio con None .

Sebbene, una funzione estremamente semplice, la match annidata diminuisce significativamente la leggibilità.

ROP osserva che abbiamo due tipi di percorsi di esecuzione nel nostro programma

  1. Percorso felice: alla fine calcolerà Some valore
  2. Percorso errore: tutti gli altri percorsi generano None

Poiché i percorsi di errore sono più frequenti tendono a prendere il controllo del codice. Vorremmo che il codice percorso felice fosse il percorso di codice più visibile.

Una funzione equivalente g usa ROP potrebbe assomigliare a questa:

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

Assomiglia molto a come tendiamo a elaborare elenchi e sequenze in F# .

Si può vedere Option<'T> come una List<'T> che può contenere solo 0 o 1 elemento dove Option.bind si comporta come List.pick (concettualmente Option.bind meglio a List.collect ma List.pick potrebbe essere più facile da capire).

bind , filter e map gestisce i percorsi di errore e g contengono solo il codice percorso felice.

Tutte le funzioni che accettano direttamente l' Option<_> e restituiscono l' Option<_> sono direttamente componibili con |> e >> .

ROP quindi aumenta la leggibilità e la componibilità.

Utilizzo dei tipi di opzioni da C #

Non è una buona idea esporre i tipi di opzioni al codice C #, poiché C # non ha un modo per gestirli. Le opzioni sono o per introdurre FSharp.Core come dipendenza nel tuo progetto C # (che è quello che dovresti fare se stai consumando una libreria F # non progettata per l'interoperabilità con C #), o per modificare i valori None su null .

Pre-F # 4.0

Il modo per farlo è creare una funzione di conversione personalizzata:

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

Per i tipi di valore dovresti ricorrere al pugilato o all'utilizzo di System.Nullable .

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

F # 4.0

In F # 4.0, le funzioni ofObj , toObj , ofNullable e toNullable introdotte nel modulo Option . In F # interattiva possono essere usati come segue:

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

Si noti che None compila in null internamente. Tuttavia, per quanto riguarda F # è 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
Autorizzato sotto CC BY-SA 3.0
Non affiliato con Stack Overflow