2013-06-25 7 views
22

Sto cercando di ottenere le basi di F # clear prima di passare a esempi complessi. Il materiale che sto imparando ha introdotto sia i tipi Discriminate Unions che Record. Ho esaminato il materiale per entrambi, ma non mi è ancora chiaro perché dovremmo usarne uno sull'altro.Quando utilizzare un tipo discriminatorio per l'unione e il record in F #

La maggior parte degli esempi di giocattoli che ho creato sembrano essere implementabili in entrambi. Records sembrano essere molto vicino a quello che penso a come un oggetto in C#, ma sto cercando di evitare di fare affidamento sulla mappatura per C# come un modo per capire F #

Quindi ...

  • Are c'è una ragione chiara per usare l'una sull'altra?

  • Ci sono alcuni casi canonici in cui si applica?

  • Esistono alcune funzionalità disponibili in una, ma non nell'altra ?

+1

Questa pagina ha un breve paragrafo http://msdn.microsoft.com/en-us/library/dd233205.aspx alla fine. –

risposta

25

Pensate che un Record è "e", mentre un'unione discriminata è "o". Questa è una stringa e un int:

type MyRecord = { myString: string 
        myInt: int } 

mentre questo è un valore che è una stringa o un int, ma non entrambi:

type MyUnion = | Int of int 
       | Str of string 

Questo gioco fittizia può essere nella schermata di titolo , In-game o visualizzazione del punteggio finale, ma solo una di queste opzioni.

type Game = 
    | Title 
    | Ingame of Player * Score * Turn 
    | Endgame of Score 
+0

Quindi, nel DU c'è un modo per creare un tipo combinato che estende il gioco? Ad esempio | InGameTitle of Title * Ingame. cioè una tupla contenente Titolo * Giocatore * Punteggio * Girare –

+0

@Chris: Ciò solleva solo la domanda: perché dovresti _want_? – ildjarn

+0

@ildjarn Hai perfettamente ragione. Quando ho scritto per la prima volta questo commento, non avevo una piena comprensione degli scopi delle DU. La risposta di MisterMetaphor mi ha aiutato a capire perché lo avresti usato come ha fatto Robert, ma non come ho delineato. –

7

Se si proviene da C#, si può capire record come sigillati classi con valori aggiunti:

  • Immutabile di default
  • uguaglianza strutturale di default
  • facile pattern match
  • ecc.

Unioni discriminate codificare alternative ad es.

type Expr = 
    | Num of int 
    | Var of int 
    | Add of Expr * Expr 
    | Sub of Expr * Expr 

Il DU sopra è come segue: un'espressione è sia un numero intero, o una variabile, o un'aggiunta di due espressioni o sottrazione tra due espressioni. Questi casi non possono accadere contemporaneamente.

Sono necessari tutti i campi per creare un record. È inoltre possibile utilizzare DU in record e viceversa

type Name = 
    { FirstName : string; 
     MiddleName : string option; 
     LastName : string } 

L'esempio sopra mostra che il secondo nome è facoltativo.

In F #, si avvia spesso la modellazione di dati con tuple o record. Quando sono richieste funzionalità avanzate, puoi spostarle in classi.

D'altra parte, le unioni discriminate vengono utilizzate per modellare alternative e mutuo esclusivo rapporto tra i casi.

+0

Grazie. Questa risposta e l'altra indicano entrambi il fatto che il DU è una specie di relazione OR. Ma come si capisce, un DU può contenere più valori. Ad esempio, il "tipo Nome" potrebbe avere un valore per "Nome, Nome centrale e Cognome". Ciò mi lascia ancora un po 'incerto su quale sia la differenza tra un record che ha valori per tutti i campi e un DU con valori per tutti i campi. È possibile che il DU possa fare qualche forma di inferenza o operazione che il record non può? O è la proprietà immutabile la differenza qui? –

11

utilizzare i record (tipi di chiamata di prodotto in teoria programmazione funzionale) per i dati complessi, che viene descritto da diverse proprietà, come un record di database o di qualche modello di entità:

type User = { Username : string; IsActive : bool } 

type Body = { 
    Position : Vector2<double<m>> 
    Mass : double<kg> 
    Velocity : Vector2<double<m/s>> 
} 

Usa discriminato sindacati (chiamati tipi somma) per dati possibili valori per i quali possono essere elencati. Ad esempio:

type NatNumber = 
| One 
| Two 
| Three 
... 

type UserStatus = 
| Inactive 
| Active 
| Disabled 

type OperationResult<'T> = 
| Success of 'T 
| Failure of string 

noti che i valori possibili per un valore un'unione discriminata sono mutuamente esclusivi - un risultato per un'operazione può essere Success o un Failure, ma non entrambi allo stesso tempo.

è possibile utilizzare un tipo di record per codificare un risultato di un'operazione, in questo modo:

type OperationResult<'T> = { 
    HasSucceeded : bool 
    ResultValue : 'T 
    ErrorMessage : string 
} 

Ma in caso di fallimento dell'operazione, è ResultValue non ha senso. Così, pattern matching su una versione un'unione discriminata di questo tipo sarebbe simile a questa:

match result with 
| Success resultValue -> ... 
| Failure errorMessage -> ... 

E se modello corrisponde alla versione tipo di record del nostro tipo di operazione renderebbe meno senso:

match result with 
| { HasSucceeded = true; ResultValue = resultValue; ErrorMessage = _ } -> ... 
| { HasSucceeded = false; ErrorMessage = errorMessage; ResultValue = _ } -> ... 

Sembra prolisso e goffo, ed è probabilmente meno efficiente. Penso che quando senti una sensazione del genere è probabile che tu stia usando uno strumento sbagliato per il compito.

+0

Grazie per questa risposta. Ora vedo dove un DU ha un senso particolare. –

2

Un modo (leggermente imperfetto) per capire un DU è guardarlo come un immaginario "unione" C#, mentre un record è più simile a un oggetto ordinario (con più campi indipendenti).

Un altro modo di guardare un DU è guardare a un DU come una gerarchia di classi a due livelli, in cui il primo tipo di DU è una classe di base astratta ei casi del DU sono sottoclassi. Questa vista è in realtà vicina all'attuale implementazione .NET, sebbene questo dettaglio sia nascosto dal compilatore.

+0

Una importante differenza rispetto a una gerarchia di ereditarietà OO è che i diversi casi di un DU sono solo tag, ma non diversi (sotto) tipi. Questo a volte confonde i nuovi arrivati. – Frank

Problemi correlati