haskell 中 2 个新类型的“或”模式匹配

Dan*_*ema 0 import haskell either binary-decision-diagram newtype

我在 haskell 程序中使用决策图库。为此,我想声明 2 种不同的(新)类型来跟踪我正在处理的决策图。我使用的库是 cudd,决策图基类型有一个 DdNode,但我的问题仅与 Haskell 相关。

newtype Bdd = ToBdd Cudd.Cudd.DdNode
newtype Zdd = ToZdd Cudd.Cudd.DdNode
Run Code Online (Sandbox Code Playgroud)

通常我想在调用函数时区分它们,但现在我想使用一个不必区分这两种类型的函数。我主要尝试通过 3 种不同的方式来解决这个问题:

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
Run Code Online (Sandbox Code Playgroud)

所有这些方法都失败了。编写这段代码最优雅的方式是什么?感谢您的关注。

dfe*_*uer 5

我没有深入研究你的代码,但从你的描述来看,你可能对幻影类型的想法感兴趣。

newtype Dd x = ToDd (Cudd.Cudd.DdNode)
data B
data Z
Run Code Online (Sandbox Code Playgroud)

现在,您可以区分何时需要Dd BDd Z何时需要,并Dd x在您不关心时进行多态处理。

在现代 GHC Haskell 中,如果你想表明BandZ唯一的标签,你可以使用DataKindsandKindSignatures扩展并这样做:

newtype Dd (x :: DdTag) = ToDd (Cudd.Cudd.DdNode)
data DdTag = B | Z
Run Code Online (Sandbox Code Playgroud)

在此上下文中,您将处理Dd 'Band Dd 'Z,其中单引号(发音为“tick”)将数据构造函数“提升”到类型级别。

要编写一个根据类型所具有的标签而行为不同的函数,您需要一个类。

class Zoop tag where
  zoop :: Dd tag -> Int
  zeep :: Char -> Dd tag
  zaaaaap :: Dd tag -> Dd tag
Run Code Online (Sandbox Code Playgroud)

现在,你可以写一个Zoop,例如B(或'B正向)和一个Z(或'Z)让用户使用方法的那么多。但是请记住,这些类型在编译时会被擦除,因此您在Zoop a任何时候想要将这些方法与多态标签一起应用时都需要一个约束。