Home > Software engineering >  Reference inferred type in multi parameter type classes
Reference inferred type in multi parameter type classes

Time:07-17

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
  • Related