代码:
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; }
{-# LANGUAGE GADTs #-}
data Exp a where
Const :: Show a => a -> Exp a
Eq :: Exp a -> Exp a -> Exp a
如果您希望在不同分支中允许不同的数据类型,那也可以。
data Exp where
Const :: Show a => a -> Exp
Eq :: Exp -> Exp -> Exp
show
的函数仍然必须在其签名中包含该约束。我能想到的唯一原因是提供有关“a”类型变量实际应该是什么的提示。我可能错过了其他好处吗? - Michael SteeleEq (Const 0) (Const "")
是合法的。而且,不需要 Show
约束,因为类型系统已经保证了 Const
不会与任何缺少 show
的内容一起打包。请参见 http://www.haskell.org/haskellwiki/GADT。 - ephemientdata (Show a) => Exp a = Const a | Eq (Exp a) (Exp a)
Exp
的函数都提到show约束条件,即使它从未使用Show
方法。相反,只将展示约束条件放在相关的函数上。请参见Real World Haskell以了解说明。0==""
是类型错误),正确的做法是创建一个用于你的语言值的类型,而不是直接重用Haskell的:data IObj = IInt Int | IStr String |...
。现在将Exp
更改为data Exp = Const IObj | Eq IObj IObj
。否则,你会发现很难编写一个可以检查两种不同类型的equals
函数。 - Nathan Shively-SandersConst
的参数,为什么不直接在构造函数中存储生成的String
值,这样你就可以show
它了。例如:data Exp = Const String | Eq Exp Expr
example = Eq (Const (show 0)) (Const (show ""))
example = Eq (mkConst 0) (mkConst "")
通常我会使用小写的构造函数名称作为函数名,但那个已经被占用了... - yatima2975Eq (Const 0) (Const "")
在您拥有的数据类型中是无法实现的,因为Exp Integer
和Exp String
不是相同的类型。一个选项是做类似于以下的操作:data Exp = forall a . Show a => Const a | Eq Exp Exp
这是否对你有所帮助取决于你打算如何使用该类型。
编辑:如上所述,这需要启用语言扩展。
{-# LANGUAGE ExistentialQuantification #-}
或 -XExistentialQuantification
或类似的语法。个人而言,我更喜欢 GADT 风格,但它们是等效的。 - ephemientdata 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
这样就可以了。你也可以使用GADTs:
data Expr where
Var :: String -> Expr
Sum :: Expr -> Expr -> Expr
等等……然后将其实例化为Show。