I have a data type with 3 phantom types attached so i can define functions classes for each combination. This method removes much duplicate code:
newtype Dd x y z = ToDd Cudd.DdNode deriving (Eq,Show)
--Class for all instances where the first subtype (x) is specified
class DdT a b c where
neg :: Dd a b c -> Dd a b c
--Class for all instances that are completely specified
class DdTFS a b c where
bot :: Dd a b c
top :: Dd a b c
with this i can define functions for multiple cases
--bot and top get no arguments, thus the instance types are fully specified
instance DdTFS B F1 S1 where
bot = ToDd (Cudd.readLogicZero mgr)
top = ToDd (Cudd.readOne mgr)
instance DdTFS Z F1 S1 where
bot = ToDd $ Cudd.zddReadZero
top = ToDd $ Cudd.zddReadOne
-- ..etc for every combination of types
--x is set to B, y and z are inferred
instance DdT B a b where
neg (ToDd b) = ToDd $ Cudd.cuddNot b
--x is set to Z, y and z are inferred
instance DdT Z a b where
neg (ToDd z) = ToDd $ Cudd.ifthenelse (ToDd z) (bot :: Dd Z a b) (top :: Dd Z a b)
In the last line lies my problem, i had hoped ghci would infer (for a and b) the data types from the given argument, z. Instead i get "No instance for (DdTFS Z a1 b1) arising from a use of ‘top’" and "No instance for (DdTFS Z a1 b1) arising from a use of ‘bot’" when compiling. Is there an easy fix for what i am trying to achieve? or am i approaching the problem wrong?
Edit: I tried
neg z = ToDd $ Cudd.ifthenelse z ((bot mgr)`asTypeOf` z) ((bot mgr)`asTypeOf` z)
but this tells me that "No instance for (DdTFS Z a b) arising from a use of ‘bot’"
Edit 2: replaced "z" in the last line with (ToDd z)
CodePudding user response:
If you want the compiler to infer some types of a MPTC for you, you need to declare a suitable functional dependency in the class.
{-# LANGUAGE FunctionalDependencies #-}
class DdT a b c | a->b, a->c where
But that doesn't really seem to be what you want. In particular, the instances you tried wouldn't work any better this way.
Instead, I think the DdT
should only have one parameter, and instead the method neg
should quantify over b
and c
. Also, to use methods of the DdTFS
class there, you need to constrain accordingly:
class DdT a where
neg :: DdTFS a b c => Dd a b c -> Dd a b c
Then it is a bit awkward to not have the b
and c
variables explicitly in scope, but as you already discovered asTypeOf
helps in this case:
instance DdT Z where
neg z = ToDd $ Cudd.ifthenelse z botdd topdd
where ToDD botdd = bot `asTypeOf` z
ToDD topdd = top `asTypeOf` z