I'm trying to model some polymorphic-type data in haskell. I understand why the following code doesn't work, but I'm hoping it illustrates what I'm trying to do. My question is: what is an idiomatic way to model this with Haskell? (You don't need to keep the input format the same if there is a better way - I don't have any existing code or data.)
data Running = Sprint | Jog deriving (Show)
data Lifting = Barbell | Dumbbell deriving (Show)
data Time = Time Integer deriving (Show)
data Pounds = Pounds Integer deriving (Show)
data TimedActivity = TimedActivity Running Time deriving (Show)
data WeightedActivity = WeightedActivity Lifting Pounds deriving (Show)
class Activity a
instance Activity TimedActivity
instance Activity WeightedActivity
-- I have a list of activities
main :: IO ()
main = putStrLn $ show [ TimedActivity Sprint (Time 10)
, WeightedActivity Barbell (Pounds 100)
]
-- I then want to apply functions to generate summaries and
-- reports from those activities, i.e.:
extractLifts :: (Activity x) => [x] -> [WeightedActivity]
extractTimes :: (Activity x) => [x] -> [TimedActivity]
Check out http://www.haskell.org/haskellwiki/Heterogenous_collections for different techniques.
For your specific example, you can use an Either
to unify both types within the same list:
both :: [Either TimedActivity WeightedActivity]
both = [ Left $ TimedActivity Sprint (Time 10)
, Right $ WeightedActivity Barbell (Pounds 100)
]
extractLifts :: [Either TimedActivity WeightedActivity] -> [WeightedActivity]
extractLifts = rights
extractTimes :: [Either TimedActivity WeightedActivity] -> [TimedActivity]
extractTimes = lefts
For more than two types, just define your own abstract data type to unify them:
data Multiple = Case1 Type1 | Case2 Type2 | ...
... and extraction functions like so:
extractCase1 :: [Multiple] -> [Type1]
extractCase1 ms = [t1 | Case1 t1 <- ms]
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