I have this code:
data SafeValue a = SafeValue a a a deriving Eq
class Safe a where
check::a->Bool
(+++)::a->a->a
instance (Num a, Eq a) => Safe (SafeValue a) where
check (SafeValue x y z) | x == y = True
| x == z = True
| y == z = True
| otherwise = False
(SafeValue a b c)+++(SafeValue x y z) = let new_val = SafeValue (a+x) (b+y) (c+z)
in if check new_val then new_val
else error "Error"
I would like to add to class Safe a function such as:
make_new 3 --> SafeValue 3 3 3
I don’t know how to add it, since the tipy should be something like:
make_new::b->a
but in the istance declaration ghci claims that it is not sure about what b is.
Can someone help, please?
The core problem is that you’re promising that
make_newworks for all typesbto produce a value ofa. However, this doesn’t make sense given howSafeValue aworks: given some typea, you get aSafeValue aout. So what you really want is formake_newto take a value of some typeabut give you a value ofSafeValue a. More generally, you want the result to be of some types awheresis the actual type you’re writing an instance for andacan be any type.What you need to do is make the class accept values of a “higher-kinded” type. (What this means is that the class should expect a type like
SafeValuethat takes a further parameter. You can do that like this:Then your instance will look like this:
Note the important difference: instead of making an instance for
SafeValue a, you’re making on forSafeValuewithout the type parameter.However, this has another problem: now you cannot constrain
ato be part ofNumandEq!You can solve this with an extension called multi-parameter type classes. So your final version would be:
and your instance would be:
To make all this work, you need to enable two extensions:
The first one lets you write instances in more ways. Normally, you can only write instances for a type that looks like
T a b cwhereTis a type anda b care type variables; with this extension, the restriction is lifted and you can write instances like the one I showed.The multiparameter typeclass extension allows typeclasses that act on more than one type. This allows you to make a class that depends on both
sanda.A final note: using typeclasses at all may not be the right choice for your example. Are you planning to write any more types for the
Safeclass? If you aren’t, then you shouldn’t use a typeclass at all. However, learning a bit about multiparameter typeclasses is still useful, so you should consider playing around with them at some point.