2010-11-28 62 views

Répondre

29
data Color = Red 
      | Yellow 
      | Green 
      deriving Enum 

allColors = [Red ..] 
+3

Cela se décomposera lorsque nous ajouterons '| Rose'. – delnan

+3

s/Rouge .. Vert/Rouge ../ et cela fonctionne. – adamse

+0

Génial, merci beaucoup! – Guy

57

Vous ne savez pas si c'est un anti-pattern (et je ne pense pas à un bon usage en ce moment), mais c'est possible. Utilisez le Enum (permet de générer une liste comme [someCtor .. someOtherCtor]) et Bounded (pour minBound et maxBound). Heureusement, vous pouvez obtenir à la fois:

data Color = Red 
      | Yellow 
      | Green 
      deriving (Enum, Bounded) 

allColors = [(minBound :: Color) ..] 

Si jamais vous ajoutez une autre couleur, allColors sont mis à jour automatiquement. Une restriction cependant: Enum exige que tous les contructeurs soient nuls, c'est-à-dire que l'ajout de Foo Int casse le tout. Heureusement, parce qu'une liste de toutes les valeurs possibles pour cela serait beaucoup trop grande.

Editer: L'autre réponse fonctionne aussi, peut-être mieux car elle ne nécessite pas de dériver Bounded et est donc un peu plus courte. Je laisserai toujours le mien parce que j'aime le code sur-machiné mais extrêmement générique;)

35

Sûrement la réponse de delnan est meilleure. Puisque je ne sais pas comment inclure un morceau de code dans un commentaire, je vais donner une généralisation en tant que réponse séparée ici.

allValues :: (Bounded a, Enum a) => [a] 
allValues = [minBound..] 

Maintenant, cela fonctionne pour tout type avec un Bounded et Enum par exemple! Et allColors est un cas particulier:

allColors :: [Color] 
allColors = allValues 

Dans de nombreux cas, vous aurez même pas besoin de définir allColors séparément.

+2

Je suis d'accord avec vous, puisque les solutions de Delnan ne nécessitent aucune référence à une valeur réelle du type. Sur une note SO, peut-être que j'ai accepté trop rapidement, mais la réponse par adamse a fonctionné exactement comme je l'ai demandé. – Guy

+0

+1 bon point. (Vous pouvez utiliser les backticks comme d'habitude dans les commentaires, les retours à la ligne seront supprimés si - aussi, cela ne rentre pas dans un commentaire et vous méritez un rep pour ça de toute façon :)) – delnan

3

Voici un exemple d'utilisation de cette technique pour analyser les énumérations avec parsec

data FavoriteColor = Maroon | Black | Green | Red | 
        Blue | Pink | Yellow | Orange 
          deriving (Show, Read, Enum, Bounded) 

Et l'analyseur parsec

parseColor :: Parser FavoriteColor   
parseColor = fmap read . foldr1 (<|>) $ map (try . string . show) 
    [ minBound :: FavoriteColor ..] 

bien sûr l'essai pourrait pourrait être appliquée par une meilleure par correspondance de motif et un peu d'autres choses pourraient le rendre plus agréable mais c'est juste un exemple d'utilisation de la technique.