Is there a way to define a class constraint for a value constructor's parameter?
Something like this:
data Point2D = (Num a) => Point a a
so that Point can take any arguments as long as they belong to the Num class?
You can use ExistentialQuantification
or GADTs
, but neither is going to do what you want. You'll never be able to do arithmetic with two Point2D
values. All you know about the contents is that they're some instance of Num. You're telling the compiler to discard all other information about them. This means you're telling the compiler to discard any information it may have that a particular pair of Point2D
values contain the same type. And without that information, you won't be able to do any arithmetic on values from two Point2D
s together.
This almost certainly isn't what you want. You can't write a distance
function, for instance. What possible use could you have for such a limited type? About all you can do with them is convert their contents to a String
.
Edit:
I think I see what you're trying to do. You just want to ensure that everything in a Point2D is a number. I don't think you actually want type erasure.
In that case, I'd go with the GADT version, with one really important change:
{-# LANGUAGE GADTs #-}
data Point2D a where
Point :: (Num a) => a -> a -> Point2D a
The end result of this is that you can only use the Point
constructor with two values of the same instance of Num, but you don't lose what the type was. Furthermore, thanks to using GADTs
, pattern-matching on the Point
constructor recovers the Num context for you, which is basically what you'd expect.
But I think the most important thing here is not throwing away the type of the contents. Doing so makes the type basically impossible to work with.
Yes, but you'll have to realize that the meaning of your constraint is different from usual generic types.
Usually, generics like in type Foo a = (a, a)
mean
for all types
a
,Foo a
consists of twoa
's
However, in your example, one needs to phrase that differently:
For some type
a
,Point2D
consists of twoa
's
or
There is a type
a
thatPoint2D
consists of
Thus, the generic type is not universal (for all types...), but existential (it exists some type...). Under GHC, we can allow this through the extenstion
{-# ExistentialQuantification #-}
as described in this article on the topic. Your code, after all, is
data Point2D = forall a . Num a => Point a a
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With