3

代码:

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

4

5 回答 5

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
于 2009-12-07T01:40:21.363 回答
4

你可以这样说

data (Show a) => Exp a = Const a | Eq (Exp a) (Exp a)

但这几乎总是一个坏主意,因为它强制每个Exp用于提及显示约束的函数,即使它从不使用这些Show方法。相反,将显示约束仅放在与其相关的功能上。有关解释,请参阅Real World Haskell

于 2009-12-07T01:00:55.753 回答
2

如果你想知道的参数Const只是你能show做到,为什么不把结果String值存储在构造函数中呢?例如:

data Exp = Const String | Eq Exp Expr

example = Eq (Const (show 0)) (Const (show ""))

这与您的 C# 版本非常相似。

于 2009-12-07T22:20:01.707 回答
1

要回答评论中提出的第二个问题,Eq (Const 0) (Const "")您拥有的数据类型无法实现,因为Exp Integer它们Exp String不是同一类型。一种选择是做类似的事情

data Exp = forall a . Show a => Const a | Eq Exp Exp

这是否对你有任何好处取决于你打算用这种类型做什么。

编辑:这确实需要如上所述启用语言扩展。

于 2009-12-07T20:38:41.997 回答
1

我只是将您的数据类型声明为类型类 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。

于 2009-12-09T15:05:18.463 回答