haskell 中 2 个新类型 'Or' 的模式匹配
Patternmatching on 'Or' of 2 newtypes in haskell
我在 haskell 程序中使用决策图库。为此,我想声明 2 种不同的(新)类型,以跟踪我正在处理的决策图类型。我正在使用的库是 cudd,决策图基本类型是 DdNode,但我的问题仅 haskell 相关。
newtype Bdd = ToBdd Cudd.Cudd.DdNode
newtype Zdd = ToZdd Cudd.Cudd.DdNode
通常我想在调用函数时区分它们,但现在我想使用一个不必区分这两种类型的函数。我主要尝试通过 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
所有这些方法都失败了。编写这段代码最优雅的方式是什么?
感谢您的关注。
我会采用与您的第一种方法非常相似的方法,但您需要重命名不同于新型构造函数的构造函数:
data Dd = FromBdd Bdd | FromZdd Zdd
printDdInfo :: Dd -> IO()
printDdInfo (FromZdd (ToZdd dd)) = do
putStrLn "Hello, zdd!"
Cudd.Cudd.cuddPrintDdInfo manager dd
printDdInfo (FromBdd (ToBdd dd)) = do
putStrLn "Hello, bdd!"
Cudd.Cudd.cuddPrintDdInfo manager dd
或者,知道所有不同的 dd 类型共享相同的底层表示,您也可以放弃存储新类型,而是独立设置 Dd
:
data DdKind = IsBdd | IsZdd
data Dd = Dd { ddKind :: DdKind
, ddImplementation :: Cudd.Cudd.DdNode }
printDdInfo :: Dd -> IO()
printDdInfo (Dd ddk dd) = do
putStrLn $ case ddk of
IsBdd -> "Hello, bdd!"
IsZdd -> "Hello, zdd!"
Cudd.Cudd.cuddPrintDdInfo manager dd
我没有深入研究你的代码,但从你的描述来看,你可能对幻像类型的想法感兴趣。
newtype Dd x = ToDd (Cudd.Cudd.DdNode)
data B
data Z
现在您可以在需要时区分 Dd B
和 Dd Z
,而在您不关心时使用 Dd x
进行多态工作。
在现代GHC Haskell中,如果你想表明B
和Z
是only标签,你可以使用DataKinds
和 KindSignatures
扩展并像这样做:
newtype Dd (x :: DdTag) = ToDd (Cudd.Cudd.DdNode)
data DdTag = B | Z
在此上下文中,您将处理 Dd 'B
和 Dd 'Z
,其中单引号(发音为“tick”)将数据构造函数“提升”到类型级别。
要编写一个根据类型具有的标签而表现不同的函数,您需要 class.
class Zoop tag where
zoop :: Dd tag -> Int
zeep :: Char -> Dd tag
zaaaaap :: Dd tag -> Dd tag
现在可以为B
(或'B
)写一个Zoop
实例,为Z
(或'Z
)写一个实例,让用户使用两者的方法。不过请记住,类型在编译中会被删除,因此只要您想要将这些方法与多态标记一起应用,就需要一个 Zoop a
约束。
我在 haskell 程序中使用决策图库。为此,我想声明 2 种不同的(新)类型,以跟踪我正在处理的决策图类型。我正在使用的库是 cudd,决策图基本类型是 DdNode,但我的问题仅 haskell 相关。
newtype Bdd = ToBdd Cudd.Cudd.DdNode
newtype Zdd = ToZdd Cudd.Cudd.DdNode
通常我想在调用函数时区分它们,但现在我想使用一个不必区分这两种类型的函数。我主要尝试通过 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
所有这些方法都失败了。编写这段代码最优雅的方式是什么? 感谢您的关注。
我会采用与您的第一种方法非常相似的方法,但您需要重命名不同于新型构造函数的构造函数:
data Dd = FromBdd Bdd | FromZdd Zdd
printDdInfo :: Dd -> IO()
printDdInfo (FromZdd (ToZdd dd)) = do
putStrLn "Hello, zdd!"
Cudd.Cudd.cuddPrintDdInfo manager dd
printDdInfo (FromBdd (ToBdd dd)) = do
putStrLn "Hello, bdd!"
Cudd.Cudd.cuddPrintDdInfo manager dd
或者,知道所有不同的 dd 类型共享相同的底层表示,您也可以放弃存储新类型,而是独立设置 Dd
:
data DdKind = IsBdd | IsZdd
data Dd = Dd { ddKind :: DdKind
, ddImplementation :: Cudd.Cudd.DdNode }
printDdInfo :: Dd -> IO()
printDdInfo (Dd ddk dd) = do
putStrLn $ case ddk of
IsBdd -> "Hello, bdd!"
IsZdd -> "Hello, zdd!"
Cudd.Cudd.cuddPrintDdInfo manager dd
我没有深入研究你的代码,但从你的描述来看,你可能对幻像类型的想法感兴趣。
newtype Dd x = ToDd (Cudd.Cudd.DdNode)
data B
data Z
现在您可以在需要时区分 Dd B
和 Dd Z
,而在您不关心时使用 Dd x
进行多态工作。
在现代GHC Haskell中,如果你想表明B
和Z
是only标签,你可以使用DataKinds
和 KindSignatures
扩展并像这样做:
newtype Dd (x :: DdTag) = ToDd (Cudd.Cudd.DdNode)
data DdTag = B | Z
在此上下文中,您将处理 Dd 'B
和 Dd 'Z
,其中单引号(发音为“tick”)将数据构造函数“提升”到类型级别。
要编写一个根据类型具有的标签而表现不同的函数,您需要 class.
class Zoop tag where
zoop :: Dd tag -> Int
zeep :: Char -> Dd tag
zaaaaap :: Dd tag -> Dd tag
现在可以为B
(或'B
)写一个Zoop
实例,为Z
(或'Z
)写一个实例,让用户使用两者的方法。不过请记住,类型在编译中会被删除,因此只要您想要将这些方法与多态标记一起应用,就需要一个 Zoop a
约束。