2013-02-19 11 views
88

Powiedzmy mam następujący zapis ADT:Skrócony sposób na przypisanie pojedynczego pola do rekordu, podczas kopiowania pozostałych pól?

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

chcę funkcję, która pobiera rekord i zwraca rekord (tego samego typu), gdzie wszystko ale jedno z pól mają identyczne wartości do jednego przeszedł jako argument, tak jak poniżej:

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

powyższe działa, ale do rekordu z kilku dziedzin (słownie 10), tworząc taką funkcję wiązałoby dużo pisania, że ​​czuję się zupełnie niepotrzebne.

Czy istnieją mniej żmudne sposoby robienia tego samego?

+2

Składnia rekordów do aktualizacji istnieje, ale szybko staje się kłopotliwa. Zobacz zamiast tego [soczewki] (http://stackoverflow.com/questions/5767129/lenses-fclabels-data-accessor-which-library-for-structure-access-and-mutatio). –

Odpowiedz

115

Tak, istnieje przyjemny sposób aktualizowania pól rekordów. W GHCi można zrobić -

> 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

Rozszerzenie 'RecordWildCards' może być również miłe, aby" rozpakować "pola w zakresie. W przypadku aktualizacji nie jest to jednak takie przyjemne: 'incrementA x @ Foo {..} = x {a = succ a}' –

+1

BTW, w Fregge (Haskell dla JVM) zdefiniowałbyś funkcję jako '' updateFoo x = x. {c = "Do widzenia"} '' '(zwróć uwagę na operator' '' .'''). – 0dB

28

To jest dobra praca dla lenses:

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

test = Foo 1 2 "Hello" 

Następnie:

setL c "Goodbye" test 

będzie aktualizować polu 'C' z 'testu' do listy strunowy.

+4

Pakiety podobne do soczewek często określają operatorów oprócz funkcji uzyskiwania i ustawiania pól. Na przykład 'test $ c. ~" Do widzenia "' to jak 'soczewka' zrobiłaby to Iirc. Nie mówię, że to jest intuicyjne, ale kiedy już znasz operatorów, spodziewam się, że przyjdzie to równie łatwo jak '$'. –

+2

Czy wiesz, gdzie odszedł _setL_? Importuję _Control.Lens_, ale ghc zgłasza, że ​​_setL_ jest niezdefiniowane. – dbanas