
Matthias Fischmann wrote:
hi,
this is one of those situations that always make scheme and perl hackers laugh at me: i have written a piece of code that is intuitively clear, and now i am trying to turn it into something that compiles. and here it goes.
i have a type class that looks something like this:
class Resource a where resourceName :: a -> String resourceAdvance :: a -> a resourceStarved :: a -> Bool resourceSpend :: a -> Int -> a resourceEarn :: a -> Int -> a
resource types are rice, crude oil, pizza, software code, and so on.
If there is a known list of resources, then they could all be a single data type.
they all have a different internal structure and the same abstract interface, that's why i have defined this type class.
now i want to create a list of a type similar to
[r1, r2, r3] :: (Resource a) => [a]
The above only works if r1 :: a, r2 :: a, and r3 :: a But this is not what you want, since pizza and crude oil are different types.
but with r1 being pizza, r2 being crude oil, and so on. my first idea was this:
data Rs = forall a . (Resource a) => Rs a unRs (Rs a) = a rsName :: Rs -> String rsName = resourceName . unRs ...
and then export Rs as an abstract data type. this would allow for lists of type [Rs], which is exactly what i want.
but what is the type of unRs? or better: can i make it type at all?
No. You cannot make unRs like that.
and isn't this solution a little redundant and verbose? should i do it like in the example for existentially quantified types in the ghc manual?
http://www.haskell.org/ghc/docs/latest/html/users_guide/type-extensions.html
but wouldnt't the code become really messy? or should i do the type class and instances, and then do Rs the existentially quantified way, with all class methods arguments to the Rs constructor? or is there a completely different way to do this (besides using scheme or perl :-)?
thanks, matthias
But you can make a list of such things: (Why isn't it "resourceName :: String" ?) class Resource a where resourceName :: a -> String resourceAdvance :: a -> a resourceStarved :: a -> Bool resourceSpend :: a -> Int -> a resourceEarn :: a -> Int -> a data R where { R :: Resource a => a -> R } instance Resource R where resourceName (R a) = resourceName a resourceAdvance (R a) = R (resourceAdvance a) resourceStarved (R a) = resourceStarved a resourceSpend (R a) i = R (resourceSpend a i) resourceEarn (R a) i = R (resourceEarn a i) data Pizza=Pizza data Oil=Oil instance Resource Pizza where resourceName _ = "pizza" instance Resource Oil where resourceName _ = "oil" list = [R Pizza, R Oil] names = map resourceName list -- Chris