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 BandDd Zwhen you want, and work polymorphically withDd xwhen you don't care.In modern GHC Haskell, if you want to indicate that
BandZare the only tags, you can use theDataKindsandKindSignaturesextensions and do it like this:In this context, you'll deal with
Dd 'BandDd '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
Zoopinstance 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 aconstraint anytime you want to apply these methods with polymorphic tags.