2012-01-18 11 views
9

Mentre ero writing up an answer poco fa, mi sono imbattuto in un problema interessante:Record valore di sintassi predefinita per di accesso

data Gender = Male | Female 
      deriving (Eq, Show) 

data Age = Baby | Child | PreTeen | Adult 
     deriving (Eq, Show, Ord) 

data Clothing = Pants Gender Age 
       | Shirt Gender Age 
       | Skirt Age   -- assumed to be Female 
       deriving (Show, Eq) 

Supponiamo che desidero scrivere il tipo di dati finale con la sintassi di registrazione:

data Clothing = Pants {gender :: Gender, age :: Age} 
       | Shirt {gender :: Gender, age :: Age} 
       | Skirt {age :: Age} 
       deriving (Show, Eq) 

Il problema è che voglio sempre valutare FemaleFemale (indipendentemente da foo, che è un Age). Mi vengono in mente un paio di modi per ottenere questo, ma richiedono che io sia costruttori intelligenti

  1. uso, in teoria permettere Skirt Male foo ma non esporre Costruttori
  2. definire la mia gender funzione

Con # 1, non esponendo il costruttore nel modulo, impedisco effettivamente agli utenti del modulo di sfruttare la sintassi dei record. Con # 2, devo assolutamente rinunciare alla sintassi del record, o definire una funzione aggiuntiva gender', che di nuovo sconfigge la sintassi del record.

Esiste un modo per trarre vantaggio dalla sintassi dei record e fornire anche un valore "predefinito", immutabile per uno dei miei costruttori? Sono aperto anche a soluzioni per la sintassi non-record (le lenti, forse?) Purché siano altrettanto eleganti (o più).

+4

Un obiettivo normale non funzionerebbe, dal momento che è possibile assegnare il campo 'gender' con due dei costruttori, ma non l'altro. Penso che farlo sia una cattiva idea; se 'pippo' è un accessorio di registrazione, e' pippo x' funziona, allora anche 'x {pippo = y}' dovrebbe. – ehird

+0

Di solito vado con 2. – augustss

+0

Come aggiungere una funzione 'gender'' (o potrei chiamarla' totalGender' o 'safeGender' o giù di lì) sconfiggere la sintassi del record? –

risposta

0

C'è un modo per trarre vantaggio dalla sintassi dei record e fornire anche un valore "predefinito", immutabile per uno dei miei costruttori?

In assenza di un controesempio convincente, la risposta sembra essere "no".

0

Sì, c'è una tensione tra tipi e dati ... che, a proposito, mostra quanto sia sottile la linea.

La risposta pratica consiste nell'utilizzare un'istanza predefinita come indicato in Haskell Wiki. Risponde alla tua domanda esatta poiché devi rinunciare all'uso diretto del costruttore.

Così per il vostro esempio,

data Age = Baby | Child | PreTeen | Adult | NoAge 
data Clothing = Pants {gender :: Gender, age :: Age} 
       | Shirt {gender :: Gender, age :: Age} 
       | Skirt {gender :: Gender, age :: Age} 
       deriving (Show, Eq) 

skirt = Skirt { gender=Female, age=NoAge } 

allora sviluppatori possono creare nuove istanze con valori predefiniti, utilizzando l'impianto di copia e aggiornamento della sintassi record di

newSkirt = skirt { age=Adult } 

e gender newSkirt viene valutato come Female

Voglio sottolineare che questo approccio porta a definire valori predefiniti a livello di tipo, che penso sia un Good Thing (ovviamente il costruttore NoAge è il Nothing di un tipo Maybe Age).