Reputation: 7417
Currently I have something like this:
data MyData = SomeData | MoreData | EvenMore
data DataLists = DataLists [MyData] [MyData]
Which allows me to obviously do something like this:
myDataList :: DataLists
myDataList = DataLists [SomeData, MoreData] [EvenMore, SomeData]
But I would like to instead do something like this:
-- Static Module File:
class MyClass b where
evaluate :: b -> Int
data SomeData = SomeData
data MoreData = MoreData
data EvenMore = EvenMore
instance MyClass SomeData where
evaluate _ = 2
instance MyClass MoreData where
evaluate _ = 3
instance MyClass EvenMore where
evaluate _ = 4
data DataList = DataList [MyClass] [MyClass] -- Obviously this is wrong
I would like that part of my code to remain static. Because later I would like to add in some types using that module to put in the Data List. I need this separate because the overall module will be used in 2 different projects and I don't want to have to keep going into edit it.
data MyVeryOwnData = MyVeryOwnData
--I should be able to make up as many datastructures as I want
instance MyClass MyVeryOwnData where
evaluate _ = 99
myList :: DataList
myList = DataList [MyVeryOwnData, SomeData] [SomeData, EvenMore]
I realize that I could simply put MyVeryOwnData in the module file like this:
data MyData = SomeData | MyVeryOwnData ...
instance MyClass MyData where
evaluate SomeData = 2
evaluate MoreData = 3
... etc.
But I dont want to do that since as I said before I want to add an arbitrary amount of datatypes in.
Upvotes: 4
Views: 174
Reputation: 10547
What you're looking for is called Heterogenous lists, and haskell supports them in mainly two ways, Existentials or GADTs. I show you a runnable code example that solved the problem with existentials.
{-# LANGUAGE ExistentialQuantification #-}
class Eval b where
evaluate :: b -> Int
data SomeData = SomeData
data MoreData = MoreData
data EvenMore = EvenMore
instance Eval SomeData where
evaluate _ = 2
instance Eval MoreData where
evaluate _ = 3
instance Eval EvenMore where
evaluate _ = 4
data Evalable = forall a . Eval a => Evalable a
instance Eval Evalable where
evaluate (Evalable a) = evaluate a
pack :: Eval a => a -> Evalable
pack = Evalable
data DataLists = DataLists [Evalable] [Evalable]
getFirst :: DataLists -> [Evalable]
getFirst (DataLists xs ys) = xs
main = do
let dl = DataLists [pack SomeData, pack EvenMore] [pack MoreData]
print . map evaluate . getFirst $ dl
It should be clear that you can add instance Eval MyVeryOwnData
in outside modules, and you can then pack
those values so they become Evalable
and you can then put them inside your Datalists
.
Upvotes: 6