2012-01-11 8 views
7

Così ho avuto modo di registrare nel mio viaggio in F # e all'inizio sembrano piuttosto pericolosi. In un primo momento questo sembrava intelligente:Record F #: pericoloso, solo per uso limitato o funzionalità ben utilizzata?

type Card = { Name : string; 
      Phone : string; 
      Ok : bool } 

let cardA = { Name = "Alf" ; Phone = "(206) 555-0157" ; Ok = false } 

L'idea che la cartaA è il patten è stata abbinata a quella del cartoncino. Per non parlare del modello semplificato di corrispondenza qui:

let withTrueOk = 
    list 
    |> Seq.filter 
    (function 
     | { Ok = true} -> true 
     | _ -> false 
) 

Il problema è:

type Card = { Name : string; 
      Phone : string; 
      Ok : bool } 

type CardTwo = { Name : string; 
      Phone : string; 
      Ok : bool } 

let cardA = { Name = "Alf" ; Phone = "(206) 555-0157" ; Ok = false } 

Carda è ora di tipo CardTwo che sto indovinando ha a che fare con F # in esecuzione tutto in ordine.

Ora questa potrebbe essere una situazione impossibile poiché potrebbe non esserci mai la possibilità che la stessa firma prenda due tipi, ma è una possibilità.

Sta registrando qualcosa che ha un uso limitato o sto solo pensando a questo?

+8

Stai pensando troppo: dai ai tuoi elementi discografici nomi distinti o qualifica pienamente quale tipo di record intendi per abbinare/istanziare ad es 'let cardA = {Card.Name =" Alf "; Phone = "(206) 555-0157"; Ok = falso} '. – ildjarn

+14

La mutabilità IMHO per impostazione predefinita, l'ereditarietà e la mancanza di uguaglianza strutturale rendono le classi più pericolose dei record, ma non si vedono molte persone lamentarsi di questo ;-) –

+7

@MauricioScheffer Aggiungi a tale valore di default per impostazione predefinita. –

risposta

18

Non sono pericolosi e non sono solo per uso limitato.

Penso che sia molto raro che si abbiano due tipi con gli stessi membri. Ma se si fa incontrare questa situazione, è possibile qualificare il tipo di record che si desidera utilizzare:

let cardA = { Card.Name = "Alf" ; Phone = "(206) 555-0157" ; Ok = false } 

Records sono molto utili per la creazione di (soprattutto) le strutture di dati immutabili. E il fatto che è possibile creare facilmente una copia con solo alcuni campi cambiato è troppo grande:

let cardB = { cardA with Ok = true } 
12

Sono d'accordo, i campi dei record come membri del racchiude modulo/namespace sembra strano in un primo momento provenienti da altri linguaggi OO tradizionali. Ma F # offre una buona dose di flessibilità qui. Penso che troverete solo circostanze artificiose causano problemi, come ad esempio due record che

  1. identici
  2. avere un rapporto sottoinsieme/superset

Il primo caso non dovrebbe mai accadere. Quest'ultimo potrebbe essere risolto dal record B con un campo di registrazione A.

È necessario che un campo sia diverso per distinguere i due. Oltre a questo, le definizioni possono essere le stesse.

type Card = 
    { Name : string 
    Phone: string 
    Ok : bool } 

type CardTwo = 
    { Name : string 
    Phone: string 
    Age : int } 

let card = { Name = "Alf" ; Phone = "(206) 555-0157" ; Ok = false } 
let cardTwo = { Name = "Alf" ; Phone = "(206) 555-0157" ; Age = 21 } 

pattern matching è anche abbastanza flessibile come solo è necessario far corrispondere sui campi abbastanza per distinguerlo da altri tipi.

let readCard card = 
    match card with 
    | { Ok = false } ->() //OK 
    | { Age = 21 } ->() //ERROR: 'card' already inferred as Card, but pattern implies CardTwo 

Per inciso, lo scenario è facilmente risolto con un tipo di annotazione:

let cardA : Card = { Name = "Alf" ; Phone = "(206) 555-0157" ; Ok = false } 
+0

Perché un rapporto sottoinsieme/superset sarebbe un problema? AFAIK, devi sempre specificare tutte le proprietà. – svick

+2

Quando si abbina il modello. Devi solo abbinare su abbastanza campi per distinguerlo da altri tipi di record. Controlla il mio codice. – Daniel

6

Al fine che si apprezzano ciò che F # offre, voglio solo ricordare che non v'è alcuna di accesso completo per i record in OCaml.Pertanto, per distinguere tra i tipi di record con gli stessi campi, è necessario inserirli in sottomoduli e farvi riferimento utilizzando i prefissi dei moduli.

Quindi la tua situazione in F # è molto meglio. Qualsiasi ambiguità tra i tipi di record simili potrebbe essere risolto rapidamente utilizzando di accesso di registrazione:

type Card = { Name: string; 
      Phone: string; 
      Ok: bool } 

type CardSmall = { Address: string; 
      Ok: bool } 

let withTrueOk list = 
    list 
    |> Seq.filter (function 
       | { Card.Ok = true} -> true (* ambiguity could happen here *) 
       | _ -> false) 

Inoltre, F # record non si limita affatto. Fornisce molte belle funzionalità out-of-the-box tra cui la corrispondenza dei modelli, l'immutabilità predefinita, l'uguaglianza strutturale, ecc.

+9

Se si definiscono due tipi di record con gli stessi campi, è possibile impedire l'accesso non completo (e l'ambiguità intrinseca) annotando i tipi con '[]'. – Daniel

+0

@Daniel: bella cattura. – pad

Problemi correlati