2015-08-12 28 views
9

Sto tentando di impostare valori predefiniti in un oggetto record che può essere sovrascritto.Come impostare i valori predefiniti in un record

data Car c y = Car { 
    company :: c, 
    year :: y 
    } 

Quello che mi piacerebbe fare è impostare un default:

data Car c y = Car { 
    company :: c -- OR "Ford" 
    year :: y 
    } 

Finora ho provato a fare questo impostando il tipo di c a un tipo Maybe:

data Car = Car { 
    company:: Maybe String 
    year :: Maybe Int 
    } 

Tuttavia ottengo questo errore prevedibile:

Fields of `Car' not initialised: year 

Ironia della sorte, questa è esattamente la cosa che sto cercando di aggirare. Voglio produrre un nuovo record con i valori che non sto impostando già inizializzati. Un modo che ho trovato è quello di applicare parzialmente il tipo Car:

data Car c y = { 
    company :: c, 
    year :: y 
    } 

let ford = Car "Ford" 

-- This produces a function (y -> Car [Char] y) 

Tuttavia questo produce 2 nuovi problemi:

  1. Nel caso il mio tipo di dati ha più di 100 tipi di campo, sarò terminare con 100 funzioni aleatorie fattoriali

  2. Le funzioni parzialmente applicate che posso creare dipendono dall'ordine delle variabili nella dichiarazione. Noterai che non riesco a produrre una funzione car1988, ad esempio.

Come posso scrivere una funzione che mi consente di creare record con valori predefiniti? Per favore aiuto.

risposta

15

Questo è il tipo di cosa Haskell prefers to handle in a library, piuttosto che l'hacking di un supporto linguistico cablato (che probabilmente causerebbe tutti i tipi di problemi, proprio come avviene in C++).

import Data.Default 

instance Default Car where 
    def = Car Nothing Nothing 
      -- or whatever you want as the defaults 

ford :: Car 
ford = def { company = Just "Ford" } 

GHCi> ford
Car {company = Just "Ford", year = Nothing}

Invece di utilizzare la classe Default si può anche solo definire un defaultCar.

Potrebbe essere necessario utilizzare la cabala per installare data-default, se non è già installato nel sistema.

+3

Per aggiungere a questo, ["costruttori intelligenti"] (https://wiki.haskell.org/Smart_constructors) (questo stile di costruzione) sono sempre il modo migliore per andare qui. Puoi avere tutto ciò che vuoi con gli argomenti che preferisci, esportare alcuni dal modulo e altri no, e se il tuo tipo è polimorfico hai la possibilità di avere un costruttore diverso per ogni tipo più specifico che vuoi gestire. – bheklilr

+0

Molto bello. Ma cosa intendi "piuttosto che usare la classe' Default' "? Per definire 'defaultCar' avrei bisogno di usare questo costrutto' Default' giusto? – dopatraman

+0

no, puoi semplicemente definire un valore normale 'defaultCar' e modificarlo quando hai bisogno di un'auto non standard. inoltre, se si desidera utilizzare 'Default', si dovrebbe usare semplicemente il pacchetto' data-default-class', poiché è un po 'più leggero – Fraser