Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pattern match data types and their nested name in Haskell

I have:

data Color = Blue | Green | Red | White | Yellow deriving (Eq,Ord)

And then

data Term = Color | ...
data Bag = Bag {
color :: Color
...
}

Now I want to be able to pattern match to make sure that the term given is a Color and if so check it's "value" (Blue/Green...). Something like this:

func :: Term -> Bag -> Bool
func (c :: Color) bag = (color bag) == c

But (c :: Color) does not seem to work.

like image 798
Daniel O Avatar asked Jul 19 '26 06:07

Daniel O


2 Answers

data Color = Blue | Green | Red | White | Yellow deriving (Eq,Ord)

data Term = Color Color | Trash

data Bag = Bag {
  color :: Color
}

func (Color x) bag = (color bag) == x

-- With the above, a call of func Trash something will fail.
-- (unexhastive pattern match). You can add

func Trash bag = False

-- or

func _ _ = False

-- and it will work all time.
like image 129
sdcvvc Avatar answered Jul 22 '26 00:07

sdcvvc


Here is a somewhat wordier account, no different in content from sdcvvc's, I think.

data Color = Blue | Green | Red | White | Yellow deriving (Eq,Ord,Show)
data Size = Small | Medium | Large deriving (Eq, Ord, Show)

data Term = TColor Color | TSize Size | Trash deriving Show
data Bag = Bag {color :: Color , size :: Size} deriving Show

Notice that unlike sdcvvc I used "TColor Color". It's no different since the typechecker can tell that one is an already established type the other is a new constructor of a new type, even if they're spelled the same. It's just little less confusing. Something like "Color Color" would not be so uncommon these days, but in a older book like Bird's "Intro to FP with Haskell," he wouldn't do this sort of thing. It's a bit like the Haskeller's vogue for things like "\file -> readFile file" which has its advantages, but is potentially confusing and it seems pretty recent; formerly it would have been just \x -> readFile x or something.

theMrsThatcher :: Bag
theMrsThatcher = Bag Blue Large

theMrsRobinson :: Bag
theMrsRobinson = Bag {color = Green, size = Small}  -- to use the other syntax

colorCheck :: Term -> Bag -> Bool
colorCheck (TColor c) b = True
colorCheck (TSize s) b = False  -- as sdcvvc says, this and
colorCheck Trash b = False      -- the next clause can be replaced by 
                                -- colorCheck _ _ = False

Note also that in colorCheck the bag is irrelevant. It isn't clear from what you say why you need the intermediate type Term.

colorTest :: Color -> Bag -> Bool
colorTest c b = color b == c

colorCheckTest :: Term -> Bag -> Bool
colorCheckTest (TColor c) b = color b == c
colorCheckTest (TSize s) b = False    -- as above, the last clauses are 
colorCheckTest Trash b = False        -- wordier than need be since any  
                                      -- but the first pattern is a loser.

Results:

*Main> colorCheck (TColor Blue) theMrsRobinson  
True  
*Main> colorCheck (TColor Blue) theMrsThatcher  
True  
*Main> colorCheckTest (TColor Blue) theMrsRobinson  
False  
*Main> colorCheckTest (TColor Blue) theMrsThatcher  
True  
*Main> colorTest Blue theMrsThatcher  
True  
*Main> colorTest Blue theMrsRobinson  
False  
like image 32
Arthur Avatar answered Jul 22 '26 02:07

Arthur



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!