Consider the following:
data A = A1 | A2 Integer
x = [A1, A2 999]
elem A1 x == True
Is there a way to do the following test?
elem (A2 _) x == True
Consider the following:
data A = A1 | A2 Integer
x = [A1, A2 999]
elem A1 x == True
Is there a way to do the following test?
elem (A2 _) x == True
No, but you could rephrase that using any.
hasA2 :: [A] -> Bool
hasA2 = any $ \x -> case x of { A2 _ -> True ; _ -> False }
No, for two reasons:
No syntactic support for expressions of this sort.
elem
requiring a concrete first argument to search for in the list passed in as the second argument (so you can't do it with some minor fix to the syntax alone).
You can use Data.List.find
instead:
import Data.List
isA2 A1 = False
isA2 (A2 _) = True
find isA2 [A1, A2 999]
-- => Just (A2 999)
Update: Well, Dietrich beat me to it, but I'll leave this answer here for the alternative solution (plus the explanation on top, FWIW).
A solution using Template 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
is in the "peakachu" hackage package, temporarily. This functionality will be added to "derive" and then removed from "peakachu".
instance Eq A where
A1 == A1 = True
A2 _ == A2 _ = True
_ == _ = False
elem (A2 undefined) x == True
Of course, this has effects beyond what you've asked for.
To expand on Dietrich's answer:
If you simply want to match on a constructor name, disregarding all fields, you can use this pattern: A2 {}
.
hasA2 :: [A] -> Bool
hasA2 = any $ \x -> case x of { A2 {} -> True; _ -> False }
This function will continue to work if you later decide to add another field to the A2
constructor.
And, if you're using ephemient Eq
instance, you could also call it like so:
elem (A2 {})
Again, disregarding all fields (initializing them to bottom).
Yes, this is doable! And if you don't like template haskell (used in another answer) then you can use either the "DrIFT" or "derive" tools.
{-! global : is !-}
data Foo = A1 | A2 Int deriving (Show, Eq, Ord)
hasA2 :: [Foo] -> Bool
hasA2 = any isA2
That is the code you type and as part of the compiler pipleine you run the source through DrIFT which generates the is* functions for all data types in the module:
{-* Generated by DrIFT : Look, but Don't Touch. *-}
isA1 (A1) = True
isA1 _ = False
isA2 (A2 _) = True
isA2 _ = False
Alternatively you can use "derive". Use the above code, remove the {-! ... !-} directive and insert:
{-!
deriving instance Is Foo
!-}
or you could save some typing and modify the original code to read:
data Foo = A1 | A2 Int deriving (Show, Eq, Ord {-! Is !-})
And "derive" will generate:
isA1 :: Foo -> Bool
isA1 (A1{}) = True
isA1 _ = False
isA2 :: Foo -> Bool
isA2 (A2{}) = True
isA2 _ = False