Come funziona il tipo di opzione in F #
Domanda
Quindi ho letto il libro Expert F # di Apress, per lo più usandolo come riferimento quando ho costruito una libreria F # toy-ish, ma c'è una cosa che non sono riuscito a capire e questa è l'opzione &; " tipo.
Come funziona e qual è il suo utilizzo nel mondo reale?
Soluzione
Il tipo di opzione è almeno simile a Nullable<T>
e tipi di riferimento in C #. Un valore di tipo Option<T>
è None
il che significa che non esiste un valore incapsulato o Some
con un valore particolare di T
. Questo è proprio come il modo in cui Nullable<int>
in C # è o il valore null, o ha un int
associato - e il modo in cui un String
valore in C # è o riferimento null, o si riferisce a un oggetto String.
Quando si utilizza un valore di opzione, generalmente si specificano due percorsi: uno per il caso in cui è un valore associato e uno in cui non è . In altre parole, questo codice:
let stringLength (str:Option<string>) =
match str with
| Some(v) -> v.Length
| None -> -1
è simile a:
int StringLength(string str)
{
if (str != null)
{
return str.Length;
}
else
{
return -1;
}
}
Credo che l'idea generale sia che forzando tu (beh, quasi) per gestire il " nessun valore / oggetto associato " case rende il tuo codice più robusto.
Altri suggerimenti
Uno dei migliori esempi di utilizzo nel mondo reale è per TryParse in .Net. Vedi la prima metà di
http://lorgonblog.spaces.live.com/blog/ cns! 701679AD17B6D310! 181.entry
per una discussione.
È usato quando una funzione o un metodo dovrebbe " forse " oppure " facoltativamente " restituisce un valore. In C # probabilmente restituiresti null o restituiresti un Null Object o possibilmente un Nullable per valore tipi.
Il rovescio della medaglia di restituire null (il caso più comune) è che non è sicuro per i tipi: null è un'istanza di tutti i tipi, quindi ti imbatterai in tutti i tipi di situazioni pelose di riferimento null in seguito.
Il tipo di opzione è un cosiddetto tipo di unione discriminato con due costruttori: nessuno e alcuni a. Nessuno indica esplicitamente che non hai un valore. Fondamentalmente è il modello Null Object generalizzato.
Lo usi quando un valore è facoltativo. Un uso è avere una sorta di "riferimento null", ad es.
val x : int option ref = None
Quindi puoi aggiornare x in Some v. Lo usi con l'istruzione match, ad esempio
match !x with (* dereference x *)
None -> (* No value, do something *)
| Some v -> (* Value v, do something else *)
Per aggiungere alle altre risposte, il tipo di Opzione non è niente di speciale: è solo un'altra unione discriminata. Puoi definirlo tu stesso in una riga:
type 'a Option = None | Some of 'a
L'utilità, come altri hanno sottolineato, è che la corrispondenza dei modelli ti consentirà di decostruire in modo sicuro, invece di verificare la presenza di null o utilizzare qualche soluzione alternativa per indicare se un valore non è realmente un valore.
Un modello funzionale che utilizza il tipo di opzione:
Quando è necessario modificare parti di una struttura di dati ricorsiva, come un albero o un elenco, vorrai riutilizzare il più possibile la struttura di dati esistente. Il tipo di opzione può aiutarti in questo. Queste due funzioni sostituiscono entrambe tutte le occorrenze del numero 5 con 7, ma il primo copia l'intero albero. Il secondo no.
type Tree = Leaf of int
| Node of Tree * Tree
let rec replace_no_sharing tree =
match tree with
| Leaf 5 -> Leaf 7
| Leaf x -> Leaf x
| Node (a, b) -> Node (replace_no_sharing a, replace_no_sharing b)
let replace_with_sharing tree =
let rec replace_option tree =
match tree with
| Leaf 5 -> Leaf 7 |> Some
| Leaf x -> None
| Node (a, b) -> match replace_option a, replace_option b with
| None, None -> None
| Some a, Some b -> Node (a, b) |> Some
| Some a, None -> Node (a, b) |> Some
| None, Some b -> Node (a, b) |> Some
match replace_option tree with
| None -> tree
| Some tree -> tree
Potrebbe non essere necessario in tutti i casi, ma è una buona tecnica da sapere.