Lets say we have this type declaration:
data D a = A a | B a | C a | D a | E a | F a
and want to define a function over it which divides the data constructors in 2 sets. It would be nice to write something like that:
g x | x `is` [A,B,C] = 1
| x `is` [D,E,F] = 2
instead of matching on each constructor separately.
Is there any way to achieve this? I looked at uniplate but couldn't find a way to do it.
If you often need to match for the same set of constructors, a helper function could be the simplest solution. For example:
getAbc :: D a -> Maybe a
getAbc (A v) = Just v
getAbc (B v) = Just v
getAbc (C v) = Just v
getAbc _ = Nothing
With such a helper function, the definition of g
can be simplified like this:
g x = g_ (getAbc x)
where
g_ (Just v) = 1
g_ Nothing = 2
Or, using the maybe
function:
g = maybe 2 (\v -> 1) . getAbc
Edit: If all constructors have the same type of fields, you could abuse Functor:
{-# LANGUAGE DeriveFunctor #-}
data D a = A a | B a | C a | D a | E a | F a
deriving (Eq, Functor)
isCons :: (Eq (f Int), Functor f) => f a -> (Int -> f Int) -> Bool
isCons k s = fmap (const 42) k == s 42
is :: (Eq (f Int), Functor f) => f a -> [Int -> f Int] -> Bool
is k l = any (isCons k) l
g :: D a -> Int
g x | x `is` [A,B,C] = 1
| x `is` [D,E,F] = 2
You could try
{-# LANGUAGE DeriveDataTypeable #-}
import Data.Data
data D a = A a | B a | C a | D a | E a | F a
deriving (Typeable, Data)
g :: Data a => D a -> Int
g x | y `elem` ["A","B","C"] = 1
| y `elem` ["D","E","F"] = 2
where y = showConstr (toConstr x)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With