代码:
data Exp a = Const a | Eq (Exp a) (Exp a)
我希望Const a包含一个 show 类型的值,以便我以后可以打印它。所以在 C# 中我会写:
class Const : Exp { IShow X; }
class Eq : Exp { Exp X, Y; }
我怎么能在 Haskell 中做到这一点?
代码:
data Exp a = Const a | Eq (Exp a) (Exp a)
我希望Const a包含一个 show 类型的值,以便我以后可以打印它。所以在 C# 中我会写:
class Const : Exp { IShow X; }
class Eq : Exp { Exp X, Y; }
我怎么能在 Haskell 中做到这一点?
{-# LANGUAGE GADTs #-}
data Exp a where
Const :: Show a => a -> Exp a
Eq :: Exp a -> Exp a -> Exp a
如果你想在不同的分支中允许不同的数据类型Eq
也可以。
data Exp where
Const :: Show a => a -> Exp
Eq :: Exp -> Exp -> Exp
你可以这样说
data (Show a) => Exp a = Const a | Eq (Exp a) (Exp a)
但这几乎总是一个坏主意,因为它强制每个Exp
用于提及显示约束的函数,即使它从不使用这些Show
方法。相反,将显示约束仅放在与其相关的功能上。有关解释,请参阅Real World Haskell。
如果你想知道的参数Const
只是你能show
做到,为什么不把结果String
值存储在构造函数中呢?例如:
data Exp = Const String | Eq Exp Expr
example = Eq (Const (show 0)) (Const (show ""))
这与您的 C# 版本非常相似。
要回答评论中提出的第二个问题,Eq (Const 0) (Const "")
您拥有的数据类型无法实现,因为Exp Integer
它们Exp String
不是同一类型。一种选择是做类似的事情
data Exp = forall a . Show a => Const a | Eq Exp Exp
这是否对你有任何好处取决于你打算用这种类型做什么。
编辑:这确实需要如上所述启用语言扩展。
我只是将您的数据类型声明为类型类 Show 的实例:
data Exp a = Const a | Eq (Exp a) (Exp a)
instance (Show a) => Show (Exp a) where
show (Const a) = show a
show (Eq x y ) = "[ " ++ show x ++ " , " ++ show y ++ " ]"
看看当你在 ghci 中加载它并执行以下操作时会发生什么:
*Main> let x = Eq (Const 1) (Eq (Const 2) (Const 3))
*Main> x
[1 , [2 , 3] ]
回复评论:
您可以轻松处理不同的类型。假设您要解析数学表达式。您可以具有以下结构,例如:
data Expr = Var String | Sum (Expr) (Expr) | Number Int | Prod (Expr) (Expr)
这足以表示由数字和命名变量的总和和乘积组成的任何表达式。例如:
x = Sum (Var "x") (Prod (Number 5) (Var "y"))
表示:x + 5y
为了精美地打印出来,我会这样做:
instance Show Expr where
show (Var s) = show s
show (Sum x y) = (show x) ++ " + " (show y)
show (Prod x y) = (Show x) ++ (show y)
show (Number x) = show x
这可以解决问题。您还可以使用 GADT:
data Expr where
Var :: String -> Expr
Sum :: Expr -> Expr -> Expr
等等...然后将其实例化为 Show。