Question

Si UnType est défini comme suit:

data SomeType = X {myBool :: Bool} 
                | Y {myString :: String} 
                | Z {myString :: String}

et je vais mettre à jour un arbitraire X, en fonction de son genre comme suit:

changeST :: SomeType -> SomeType
changeST (X b) = (X True)
changeST (Y s) = (Y "newString")
changeST (Z s) = (Z "newString")

La troisième et la quatrième ligne font la même, ils mettent à jour la chaîne dans le type donné. Est-il possible de remplacer ces deux lignes par un seul, par exemple. en affectant le type d'une variable?

Était-ce utile?

La solution

Non en affectant le type à une variable, mais en faisant le remplacement du terrain:

changeST :: SomeType -> SomeType
changeST (X b) = (X True)
changeST st = st { myString = "newString" }

retourne la même st comme argument, mais avec la valeur du champ de myString remplacé. Il est l'une des fonctionnalités intéressantes de champs que vous pouvez le faire sans se soucier que constructeur de données est, tant qu'il est l'un des constructeurs de données qui utilise myString.

Autres conseils

Vous pouvez utiliser Scrap-votre-boilerplate pour cela.

{-# LANGUAGE DeriveDataTypeable #-}

import Data.Generics

data SomeType
  = X { myBool :: Bool }
  | Y { myString :: String }
  | Z { myString :: String }
  deriving (Data, Typeable)

changeST :: SomeType -> SomeType
changeST = everywhere (mkT (const True)) . everywhere (mkT (const "newString"))

Ce changeST change tous les String internes dans votre structure "newString" et chaque Bool à True.

Je préfère la solution de Dan, mais les gardes de motif dans GHC (standard Haskell 2010) sont une alternative propre à la proposition de Michael:

{-# LANGUAGE PatternGuards #-}
changeST :: SomeType -> SomeType
changeST x | X _ <- x = X True
           | Y _ <- x = Y newString
           | Z _ <- x = Z newString
  where    newString = "newString"

Vos trois définitions de changeST sont séparées les unes des autres, de sorte que la réponse est « non ». Il y a, cependant, au moins deux façons dont vous pouvez le faire.

correspondance de motif à la fois les constructeurs de Y et Z à la fois:

Vous pouvez combiner les 2e et 3e définition en rendant votre modèle correspondant plus général:

changeST x = x { myString = "newString"}

Cela crée une nouvelle version de x, que ce soit un Y ou un Z, en remplacement de l'élément de chaîne. Vous devez être prudent lorsque vous faites cela, cependant. Si vous renommez plus tard, le champ de chaîne de Z, par exemple, vous obtiendrez des échecs d'exécution match de modèle lors de l'appel changeST avec un argument Z.

Utiliser une expression de cas:

Si vous combinez vos trois définitions en un seul, vous pouvez partager des données entre eux.

changeST :: SomeType -> SomeType
changeST x = case x of
    X _ -> X True
    Y _ -> Y newString
    Z _ -> Z newString
  where
    newString = "newString"
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top