Considérez ce qui suit:Dans Haskell, existe-t-il un moyen de faire "elem" sur un constructeur avec un argument?
data A = A1 | A2 Integer
x = [A1, A2 999]
elem A1 x == True
est-il un moyen de faire le test suivant?
elem (A2 _) x == True
Considérez ce qui suit:Dans Haskell, existe-t-il un moyen de faire "elem" sur un constructeur avec un argument?
data A = A1 | A2 Integer
x = [A1, A2 999]
elem A1 x == True
est-il un moyen de faire le test suivant?
elem (A2 _) x == True
instance Eq A where
A1 == A1 = True
A2 _ == A2 _ = True
_ == _ = False
elem (A2 undefined) x == True
Bien sûr, cela a des effets au-delà de ce que vous avez demandé.
Dans mon cas, je pense que ([z | (A2 z) <- x]/= []) est le plus simple car je ne dois l'utiliser qu'une fois mais je pense que définir une instance de A est probablement l'alternative la plus appropriée. Merci, éphémère. – me2
@ me2: N'utilisez pas '/ = []'; Au lieu de cela, utilisez 'non. null'. Voir http://www.haskell.org/haskellwiki/Haskell_programming_tips#Don.27t_ask_for_the_length_of_a_list_when_you_don.27t_need_it pour la justification. – ephemient
Non, mais vous pourriez en reformuler l'utilisation.
hasA2 :: [A] -> Bool
hasA2 = any $ \x -> case x of { A2 _ -> True ; _ -> False }
Non, pour deux raisons:
Pas de support syntaxique pour les expressions de ce genre.
elem
nécessitant un premier argument concret à rechercher dans la liste transmise en tant que second argument (donc vous ne pouvez pas le faire avec une correction mineure à la seule syntaxe).
Vous pouvez utiliser Data.List.find
à la place:
import Data.List
isA2 A1 = False
isA2 (A2 _) = True
find isA2 [A1, A2 999]
-- => Just (A2 999)
Mise à jour: Eh bien, Dietrich m'a battu à lui, mais je vais laisser cette réponse ici pour la solution alternative (plus l'explication sur le dessus, FWIW).
Une solution utilisant le modèle Haskell:
{-# LANGUAGE TemplateHaskell #-}
import Data.ADT.Getters
import Data.Maybe
data A = A1 | A2 Integer
$(mkADTGetters ''A)
hasA2 = any (isJust . gA2)
Note: Data.ADT.Getters
est dans le paquet "peakachu" de hackage, temporairement. Cette fonctionnalité sera ajoutée à "derive", puis supprimée de "peakachu".
Pour développer la réponse de Dietrich:
Si vous voulez simplement correspondre à un nom de constructeur, sans tenir compte tous les champs, vous pouvez utiliser ce modèle: A2 {}
.
hasA2 :: [A] -> Bool
hasA2 = any $ \x -> case x of { A2 {} -> True; _ -> False }
Cette fonction continuera à travailler si vous décidez ultérieurement d'ajouter un autre champ au constructeur A2
.
Et, si vous utilisez ephemient Eq
exemple, vous pouvez également l'appeler comme ceci:
elem (A2 {})
Encore une fois, sans tenir compte tous les champs (les) en bas d'initialisation.
Oui, c'est faisable! Et si vous n'aimez pas haskell de modèle (utilisé dans une autre réponse) alors vous pouvez utiliser les outils "DrIFT" ou "dériver".
{-! global : is !-}
data Foo = A1 | A2 Int deriving (Show, Eq, Ord)
hasA2 :: [Foo] -> Bool
hasA2 = any isA2
C'est le code que vous tapez et dans le cadre du pipleine du compilateur vous exécutez la source à travers DÉRIVE qui génère les est fonctions * pour tous les types de données dans le module:
{-* Generated by DrIFT : Look, but Don't Touch. *-}
isA1 (A1) = True
isA1 _ = False
isA2 (A2 _) = True
isA2 _ = False
Sinon, vous pouvez utilisez "dériver". Utilisez le code ci-dessus, supprimez le {-! ! ... -} directive et insérer:
{-!
deriving instance Is Foo
!-}
ou vous pourriez économiser quelques secondes et modifier le code original à lire:
data Foo = A1 | A2 Int deriving (Show, Eq, Ord {-! Is !-})
Et "dérivent" va générer:
isA1 :: Foo -> Bool
isA1 (A1{}) = True
isA1 _ = False
isA2 :: Foo -> Bool
isA2 (A2{}) = True
isA2 _ = False
derive vit sur Hackage tandis que DrIFT peut être trouvé ailleurs.
Semble que j'ai trouvé une solution alternative pour cela: ([z | (A2 z) <- x]/= []) – me2
Si vous voulez être nitpicky, il vaut mieux utiliser 'null' plutôt que '/ = [] 'car il ne nécessite pas la contrainte Ord: not $ null [() | A2 _ <- x] – Martijn