2013-02-19 5 views
88

Diciamo che ho il seguente ADT cronaca:Modo abbreviato per assegnare un singolo campo in un record, mentre si copia il resto dei campi?

data Foo = Bar { a :: Integer, b :: String, c :: String } 

Voglio una funzione che prende un record e restituisce un record (dello stesso tipo), dove tutti, ma uno dei campi hanno valori identici a quello passato come argomento, in questo modo:

walkDuck x = Bar { a = a x, b = b x, c = lemonadeStand (a x) (b x) } 

I lavori di cui sopra, ma per un record con più campi (diciamo 10), la creazione di una tale funzione comporterebbe un sacco di battitura che sento è abbastanza inutile.

Ci sono modi meno noiosi di fare lo stesso?

+2

La sintassi di registrazione per l'aggiornamento esiste, ma diventa rapidamente ingombrante. Date un'occhiata a [obiettivi] (http://stackoverflow.com/questions/5767129/lenses-fclabels-data-accessor-which-library-for-structure-access-and-mutatio). –

risposta

115

Sì, c'è un bel modo di aggiornare i campi dei record. In GHCi si può fare -

> data Foo = Foo { a :: Int, b :: Int, c :: String } -- define a Foo 
> let foo = Foo { a = 1, b = 2, c = "Hello" }   -- create a Foo 
> let updateFoo x = x { c = "Goodbye" }    -- function to update Foos 
> updateFoo foo          -- update the Foo 
Foo {a = 1, b = 2, c = "Goodbye" } 
+4

Anche l'estensione 'RecordWildCards' può essere utile per" decomprimere "i campi in un ambito. Per gli aggiornamenti non è altrettanto bello: 'incrementA x @ Foo {..} = x {a = succ a}' –

+1

BTW, in Frege (un Haskell per la JVM) definiresti la funzione come '' 'updateFoo x = x. {c = "Arrivederci"} '' '(notare l'operatore' '. .'''). – 0dB

28

Questo è un buon lavoro per lenses:

data Foo = Foo { a :: Int, b :: Int , c :: String } 

test = Foo 1 2 "Hello" 

Poi:

setL c "Goodbye" test 

sarebbe aggiornare campo 'C' di 'test' per il tuo stringa.

+4

E i pacchetti simili a obiettivi spesso definiscono gli operatori oltre alle funzioni per ottenere e impostare i campi. Ad esempio, 'test $ c. ~" Arrivederci "' è come 'lens' lo farebbe irirc. Non sto dicendo che questo è intuitivo, ma una volta che conosci gli operatori, mi aspetto che sarebbe facile come $. –

+2

Sai dove è finito _setL_? Sto importando _Control.Lens_, ma ghc sta segnalando che _setL_ non è definito. – dbanas