I have a data type like this:
data ABCS = A Int | B Int | ... | Z Int deriving (Data, Typeable)
In a test, I want to dynamically extract all the constructors, make an instance from each constructor, then run the test.
I have been looking through Data.Typeable
and Data.Data
, but I have not yet seen/understood exactly how to do this starting with only the type (ABC).
Help is much appreciated.
If you're OK with using Data.Data
, it works for this use case, but is a little clunky because of the Int
parameters.
{-# LANGUAGE ScopedTypeVariables #-}
import Data.Data
import Data.Typeable
allCtors :: forall a. Data a => [Int -> a]
allCtors = map observeCtor $ dataTypeConstrs $ dataTypeOf (undefined :: a)
where
observeCtor :: Constr -> Int -> a
observeCtor c i = fromJust $ fromConstrM (cast i) c
Then we have e.g.
λ data ABC = A Int | B Int | C Int deriving (Show, Data, Typeable)
data ABC = A Int | B Int | C Int
λ map ($ 2) allCtors :: [ABC]
[A 2,B 2,C 2]
If you don't want to use Data.Data
, you might to be able to do this with GHC.Generics
and -XDefaultSignatures
FWIW, you wouldn't have to deal with any of this if you could refactor ABC so that the A,B,C tags were their own type...
data ABCTagged = ABCTagged ABC Int deriving Show
data ABC = A | B | C deriving (Show, Eq, Ord, Enum. Bounded)
... then just use enumFrom minBound :: [ABC]
to get the whole list. Easy! Not sure how feasible this is for you though.
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