web-dev-qa-db-fra.com

Manière abrégée d'affecter un seul champ dans un enregistrement, tout en copiant le reste des champs?

Disons que j'ai le record ADT suivant:

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

Je veux une fonction qui prend un enregistrement et renvoie un enregistrement (du même type) où tous les champs sauf un ont des valeurs identiques à celle passée en argument, comme ceci:

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

Ce qui précède fonctionne, mais pour un enregistrement avec plus de champs (disons 10), la création d'une telle fonction impliquerait beaucoup de saisie que je trouve tout à fait inutile.

Existe-t-il des moyens moins fastidieux de faire de même?

106
jaymmer

Oui, il existe une bonne façon de mettre à jour les champs d'enregistrement. Dans GHCi, vous pouvez faire -

> 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" }
139
Chris Taylor

C'est un bon travail pour lentilles :

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

test = Foo 1 2 "Hello"

Ensuite:

setL c "Goodbye" test

mettrait à jour le champ "c" de "test" dans votre chaîne.

31
Don Stewart

Vous n'avez pas besoin de définir de fonctions auxiliaires ou d'employer des objectifs. Standard Haskell a déjà ce dont vous avez besoin. Prenons l'exemple de Don Stewart:

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

test = Foo 1 2 "Hello"

Ensuite, vous pouvez simplement dire test { c = "Goodbye" } pour obtenir un enregistrement mis à jour.

10
Wolfgang Jeltsch