Code:
data Exp a = Const a | Eq (Exp a) (Exp a)开发者_高级运维
I want the Const a to contain a value of type show so that i can print it later. So in C# i would write:
class Const : Exp { IShow X; }
class Eq : Exp { Exp X, Y; }
How can i do that in Haskell?
{-# LANGUAGE GADTs #-}
data Exp a where
Const :: Show a => a -> Exp a
Eq :: Exp a -> Exp a -> Exp a
If you want to allow for varying data types in different branches of Eq
that's fine too.
data Exp where
Const :: Show a => a -> Exp
Eq :: Exp -> Exp -> Exp
You can do this by saying
data (Show a) => Exp a = Const a | Eq (Exp a) (Exp a)
But this is almost always a bad idea because it forces every function that uses Exp
to mention the show constraint, even if it never uses the Show
methods. Instead, put the show constraint on just the functions it's relevant for. See Real World Haskell for an explanation.
If all you want to know about the argument to Const
is that you can show
it, why not just store the resulting String
value in the constructor instead? For example:
data Exp = Const String | Eq Exp Expr
example = Eq (Const (show 0)) (Const (show ""))
This closely resembles your C# version.
To answer the second question, asked in comments, Eq (Const 0) (Const "")
is not achievable with the datatype you have because Exp Integer
and Exp String
are not the same type. One option is to do something like
data Exp = forall a . Show a => Const a | Eq Exp Exp
Whether that will do you any good depends on what you're planning on doing with the type.
Edit: This does require language extensions to be enabled as mentioned.
I would just declare your datatype an instance of the type class 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 ++ " ]"
Look what happens when you load this in ghci and do:
*Main> let x = Eq (Const 1) (Eq (Const 2) (Const 3))
*Main> x
[1 , [2 , 3] ]
Answering comment:
You can easily deal with different types. Suppose you want to parse mathematical expressions. You can have the following structure, for example:
data Expr = Var String | Sum (Expr) (Expr) | Number Int | Prod (Expr) (Expr)
This is enough to represent any expression made of sums and products of numbers and named variables. For example:
x = Sum (Var "x") (Prod (Number 5) (Var "y"))
represents: x + 5y
To print this beautifully I'd do:
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
This would do the trick. You could also use GADTs:
data Expr where
Var :: String -> Expr
Sum :: Expr -> Expr -> Expr
etc... and then instantiate this as Show.
精彩评论