
Yep you probably don't need the fundep, you just might need to provide more
signatures. It does imply one 'b' for an 'a' which probably isn't what you
want.
On Wed, Apr 6, 2011 at 6:13 PM, Yves Parès
Thank you all,
In fact, Brandon, I knew about Datatypes a la carte, I just found it overly complicated.
Thanks for you solution, Job. However (and even if it doesn't work without it) I fail to see why you need the functional dependency on Has... Doesn't it implies here that for one 'a' there can only be one 'b' such as 'Has b a'?
2011/4/6 Job Vranish
I think you want something like this:
{-# Language MultiParamTypeClasses , FlexibleInstances , FunctionalDependencies , UndecidableInstances , FlexibleContexts , OverlappingInstances
#-} data Character a = Character { life :: Int, charaInner :: a } deriving (Show)
data Gun a = Gun { firepower :: Int, gunInner :: a } deriving (Show)
data Armor a = Armor { resistance :: Int, armorInner :: a } deriving (Show)
class HasInner f where getInner :: f a -> a
instance HasInner Character where getInner = charaInner
instance HasInner Gun where getInner = gunInner
instance HasInner Armor where getInner = armorInner
class Has b a | a -> b where content :: a -> b
instance (Has b a, HasInner f) => Has b (f a) where content a = content $ getInner a
instance (HasInner f) => Has a (f a) where content a = getInner a
chara = Character 100 $ Armor 40 $ Gun 12 ()
itsGun :: (Has (Gun b) a) => a -> Gun b itsGun = content
You were missing a mechanism to extract the inner value from your datatypes.
- Job
On Wed, Apr 6, 2011 at 2:57 PM, Yves Parès
wrote: Hello Café,
I'm trying to get some modular data types. The idea that came to me is that I could stack them, for instance :
data Character a = Character { life :: Int, charaInner :: a }
data Gun a = Gun { firepower :: Int, gunInner :: a }
data Armor a = Armor { resistance :: Int, armorInner :: a }
Then a character with a gun and an armor can be build this way:
chara = Character 100 $ Armor 40 $ Gun 12
The idea now is to be able to get some part of the character:
itsGun :: Character ?? -> Gun ?? itsGun = content
Then content would be a class method:
class Has b a where content :: a -> b
And it would be recursively defined so that:
instance (Has c b, Has b a) => Has c a where content = (content :: b -> c) . (content :: a -> b)
Then itsGun would be more like:
itsGun :: (Has Gun a) => a -> Gun ?? itsGun = content
But after some juggling with extensions (ScopedTypeVariables, UndecidableInstances, IncoherentInstances...) I can't get it working.
Has someone a simpler way to achieve modular types?
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe