Haskell问题:限制使用show的数据类型

时间:2009-12-07 00:28:28

标签: haskell types typeclass existential-type gadt

代码:

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中做到这一点?

5 个答案:

答案 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 IntegerExp 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。