I am using a decision diagram library within a haskell program. For this i want to declare 2 different (new)types that keeps track of which kind of decision diagram i am dealing with. The library i am using is cudd, and decision diagram base type from there is a DdNode, but my question is only haskell related.
newtype Bdd = ToBdd Cudd.Cudd.DdNode
newtype Zdd = ToZdd Cudd.Cudd.DdNode
Normally i want to discriminate between them when calling functions, but now i want to use a function which does not have to discriminate between the 2 types. i mainly tried to solve this in 3 different ways:
data Dd = ToBdd Bdd | ToZdd Zdd
printDdInfo :: Dd -> IO()
printDdInfo (ToZdd dd) = do
putStrLn "Hello, zdd!"
Cudd.Cudd.cuddPrintDdInfo manager dd
printDdInfo (ToBdd dd) = do
putStrLn "Hello, bdd!"
Cudd.Cudd.cuddPrintDdInfo manager dd
printDdInfo :: Either Bdd Zdd -> IO()
printDdInfo (ToZdd dd) = do
putStrLn "Hello, zdd!"
Cudd.Cudd.cuddPrintDdInfo manager dd
printDdInfo (ToBdd dd) = do
putStrLn "Hello, bdd!"
Cudd.Cudd.cuddPrintDdInfo manager dd
printDdInfo :: Either Bdd Zdd -> IO()
printDdInfo dd = case dd of
Zdd dd -> do
putStrLn "Hello, bdd!"
Cudd.Cudd.cuddPrintDdInfo manager dd
Bdd dd -> do
putStrLn "Hello, bdd!"
Cudd.Cudd.cuddPrintDdInfo manager dd
All of these methods failed. What is the most elegant way of writing this code? Thanks for your attention.
I haven't dug too deeply into your code, but from your description it sounds like you might be interested in the idea of a phantom type.
Now you can distinguish between
Dd B
andDd Z
when you want, and work polymorphically withDd x
when you don't care.In modern GHC Haskell, if you want to indicate that
B
andZ
are the only tags, you can use theDataKinds
andKindSignatures
extensions and do it like this:In this context, you'll deal with
Dd 'B
andDd 'Z
, where the single quote (pronounced "tick") "promotes" the data constructor to the type level.To write a function that behaves differently depending on which tag the type has, you'll need a class.
Now you can write a
Zoop
instance forB
(or'B
) and one forZ
(or'Z
) to let users use the method for either. Remember, though, that types are erased in compilation, so you'll need aZoop a
constraint anytime you want to apply these methods with polymorphic tags.