代码:
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中做到这一点?
答案 0 :(得分:6)
{-# 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
答案 1 :(得分:4)
你可以通过说
来做到这一点data (Show a) => Exp a = Const a | Eq (Exp a) (Exp a)
但这几乎总是一个坏主意,因为它强制使用Exp
的每个函数提及show约束,即使它从不使用Show
方法。相反,将show约束放在与其相关的函数上。有关说明,请参阅Real World Haskell。
答案 2 :(得分:2)
如果您只想了解Const
的参数是show
,那么为什么不将结果String
值存储在构造函数中呢?例如:
data Exp = Const String | Eq Exp Expr
example = Eq (Const (show 0)) (Const (show ""))
这非常类似于您的C#版本。
答案 3 :(得分:1)
要回答第二个问题,在评论中询问,Eq (Const 0) (Const "")
无法使用您拥有的数据类型实现,因为Exp Integer
和Exp String
的类型不同。一种选择是做类似
data Exp = forall a . Show a => Const a | Eq Exp Exp
这对你有什么好处取决于你打算用这种类型做什么。
编辑:这确实需要启用语言扩展程序。
答案 4 :(得分:1)
我只是将您的数据类型声明为类型Show 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。