简体   繁体   中英

haskell make (class a) instance of other class'

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM