Again Haskellers & Haskellettes,
I still have the problem, that I don't really know when to use (Class a) => a
, Type
or Type a
where Type is a "union type" as for example Val
and ExprTree
Now i want to make my datatype ExprTree
a bit more versatile by adding a few instances:
import Ratio
data Fun = Add|Sub|Mul|Div|Pow
deriving (Eq,Ord)
instance Show Fun where
show Add = "+"
show Sub = "-"
show Mul = "*"
show Div = "/"
show Pow = "^"
type Label = Rational
type Var = String
class Eval e where
eval :: (Num a) => e -> a -> a
data ExprTree a = Leaf {lab::Label, val::Val a}
| Node {lab::Label, fun::Fun, lBranch::ExprTree a, rBranch::ExprTree a}
deriving(Eq,Ord)
data Val a = Num a | Var String deriving (Eq, Ord, Show)
instance (Num a) => Num (ExprTree a) where
...
fromInteger i = Leaf (0%1) i -- <--error
instance Show (ExprTree a) where
show (Leaf l a) = show a -- <-- error
show (Node l f lb rb) = (show lb)++" "++(show l)
++(show f)++" "++(show rb)++"\n"
instance Eval (Val a) where
eval (Var v) n = n
eval a _ = a -- <-- error
I think this problems - are all of the same kind. And the NOT understanding the difference between class and type and so forth in a more than trivial setting - is a hole in the basis of my haskell programming; so i really want to understand this not to solve any homework.
Note: The label is a Rational - which makes inserting and searching much easier, than labelling with natural numbers or integers.
Thanks in advance!
The issue with the instance definition of Num
is that you say you are showing how any ExprTree
is an instance of Num
(meaning for any type a
) but instead you show how ExprTree Integer
is an instance of Num. In other words, you can't specialize that type variable if unless you want to declare your instance like this:
instance Num (ExprTree Integer) where
...
The Show instance has a sort of similar problem. You aren't showing how ExprTree a
is an instance of Show for any arbitrary a
, you are showing it only for a
s which are instances of Show already. In other words, you would need to change your instance declaration like so:
instance (Show a) => Show (ExprTree a) where
...
in order to make it work.
The third error in the Eval instance declaration comes from something unrelated and rather mundane, basically you are taking a function of type a -> e -> e and you are returning the first argument a
. Haskell is confused, since you've given it no indication that a
and e
are the same type, so there is no reason it should accept values of type a
as return types. (This might be just a case of you getting a little confused. eval
has the signature (Num e)=> e -> a -> a, but you've named your first variable a
in your instance declaration for Val a
.)
So, excluding the third instance declaration, your issue seems to be that you are promising Haskell that you will declare an instance of a typeclass for a very general type (like ExprTree a
for any a
) but then you renege on your promise by requiring that the a
be some more specific type like Integer
The problem with your fromInteger
is that i
needs to be converted to a Val a
.
instance Num a => Num (ExprTree a) where
-- ...
fromInteger i = Leaf (0%1) (Val (fromInteger i))
The Val
wrapper makes it a Val
; the inner fromInteger
creates an a
, which is a caller-specified type, which we know can be created with fromInteger
because of the Num a
constraint) from the Integer
. Pay close attention to that last: it's the reason behind typeclasses. The Num a =>
constraint insures that, given an a
, we know that we can use any of the Num
instance methods on it.
The other problem is the same issue in reverse: you are calling show
, but you haven't done anything to make sure that show
makes sense on an a
.
instance Show a => ExprTree a where
show (Leaf _ a) = show a -- this works now because we told it a is show-able
-- ...
The problem with Eval
is slightly different: a
just appears without any source, so the compiler doesn't know anything about it. In particular, eval a _ = a
requires that an e
be a valid a
— but a
is an unknown, so the compiler correctly says "what?". For this one you need to think about what you're really trying to do; the simplest solution is to drop the e
and use a
everywhere, but is that really what you intended?
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.