Reputation: 367
If I have a constructor which is:
data Garage = Gar String
if I want to test whether a type is equal to my garage type I would do something like this:
(==(Gar _)) (Gar "g")
However, the compiler complains about the underscore. If I replace this with "g"
it returns True
. Is there a way so that I can compare with a wildcard?
Upvotes: 0
Views: 1526
Reputation: 11208
A function like
isGarage (Gar _) = True
isGarage _ = False
is pretty useless as it has type Garage -> Bool
. So it will always return True
for Garage
type and type check failure will occur for any other type.
I think patter matching would be sufficient for your requirement. But just to show that you can have such kind of function using type classes if you know the types you will be acting on. So possibly if you know you will be getting values from a given set of types then you can do something like
{-# LANGUAGE FlexibleInstances #-}
data Garage = Gar String
class IsGarage a where
isGarage :: a -> Bool
isGarage _ = False
instance IsGarage Garage where
isGarage _ = True
instance IsGarage [Char]
In ghci
*Main> :t isGarage
isGarage :: IsGarage a => a -> Bool
*Main> isGarage "3"
False
*Main> isGarage (Gar "2")
True
Upvotes: 0
Reputation: 32455
Maybe your question assumes that you'll need to do run-time type checking in Haskell, but that's not necessary. Haskell will ensure all your types are correct at compile time, so a function which checks whether data is part of your Garage
data type is not needed and wouldn't work:
justPrintGarages (Gar x) = print x -- if the argument is a Garage, print its content
justPrintGarages _ = return () -- if it's anything else, do nothing.
If we ask ghci what type justPrintGarages
has, it will tell us
printGarages :: Garage -> IO ()
Yikes! Our function that was supposed to tell us whether we had a garage only works on garages??? Yup. That's because Haskell deliberately stops you from mixing types up, because it's a quagmire of runtime errors. Static typing is your friend. Static typing takes away a world of pain. Because of static typing, you can't define
printGaragesAndShebangs (Gar x) = print x
printGaragesAndShebangs ('#':'!':xs) = putStr xs
printGaragesAndShebangs _ = return ()
You'll get a type error. You can't just treat String
s and Garage
s the same.
If you want to mix garages and strings, here's the way to do it, keeping type safety:
data GarageStringInt = GsiG Garage | GsiS String | GsiI Int
(GarageStringInt
is a horrible name and so are GisG
etc, but if you need this in your code it'll represent something sensible (I hope) and you can give it a name that describes what it represents.)
Now we can write
printGaragesAndShebangs :: GarageStringInt -> IO ()
printGaragesAndShebangs (GsiG (Gar x)) = print x
printGaragesAndShebangs (GsiS ('#':'!':xs)) = putStr xs
printGaragesAndShebangs _ = return ()
Upvotes: 0
Reputation: 49085
Why doesn't your code work?
It looks like you want to pattern match, but actually you're calling the function ==
with arguments Gar _
and Gar "g"
. So Haskell gets confused and says something like "Pattern syntax in expression context: _".
How can it be fixed?
You can:
add deriving Eq
to the end of the data declaration, or
implement Eq
yourself:
instance Eq Garage where
(Gar l) == (Gar r) = l == r
Is it possible to pattern match against constructor wildcards? (for completeness)
Yes, here's a nonsense function:
f :: Garage -> Int
f (Gar "abc") = 12
f (Gar _) = 4
This would probably be more useful with a datatype that had multiple constructors, though.
Upvotes: 4
Reputation: 12296
you want to do pattern match, like this:
case x of
Gar _ -> True
_ -> False
if you want it as function, then add somsthing like
isGarage (Gar _) = True
isGarage _ = False
Upvotes: 2