How do I write something like the following in Haskell:
showSquare :: (Show a, Num a) => a -> String
showSquare x = "The square of " ++ (show x) ++ " is " ++ (show (x * x))
showSquare :: (Show a, not Num a) => a -> String
showSquare x = "I don't know how to square " ++ (show x)
Basically, something like boost::enable_if in C++.
GHC extensions are ok.
Why would you want this? The typechecker makes sure that you will never call showSquare
on something which isn't a Num
in the first case. There is no instanceof
in Haskell, as everything is typed statically.
It doesn't work for arbitrary types: you can only define your own type class, e.g.
class Mine a where
foo :: a -> String
instance (Num a) => Mine a where
foo x = show x*x
And you can add more instances for other classes, but you won't be able to write just instance Mine a
for an arbitrary a
. An additional instance (Show a) => ...
will also not help, as overlapping instances are also not allowed (the link describes a way to work around it, but it requires quite a bit of additional machinery).
First, giving different type signature to different equations for the same function isn't possible at all. Any function can have only one type, regardless of how much equations it has.
Second, negative constraints does not (would not) have any sound meaning in Haskell. Recall what class constraint mean:
f :: Num a => a -> a -> a
f x y = x + y
Num a
in the type of f
means that we can apply any class methods of Num
type class to values of type a
. We are consciously not naming concrete type in order to get generic behavior. Essentially, we are saying "we do not care what a
exactly is, but we do know that Num
operations are applicable to it". Consequently, we can use Num
methods on x
and y
, but no more than that, that is, we cannot use anything except for Num
methods on x
and y
. This is what type class constraints are and why are they needed. They are specifying generic interface for the function.
Now consider your imaginary not Num a
constraint. What information does this statement bring? Well, we know that a
should not be Num
. However, this information is completely useless for us. Consider:
f :: not Num a => a -> a
f = ???
What can you place instead of ???
? Obviously, we know what we cannot place. But except for that this signature has no more information than
f :: a -> a
and the only operation f
could be is id
(well, undefined
is possible too, but that's another story).
Finally consider your example:
showSquare :: (Show a, not Num a) => a -> String
showSquare x = "I don't know how to square " ++ (show x)
I do not give first part of your example intentionally, see the first sentence in my answer. You cannot have different equations with different types. But this function alone is completely useless. You can safely remove not Num a
constraint here, and it won't change anything.
The only usage for such negative constrains in statically typed Haskell is producing compile-time errors when you supply, say, Int
for not Num a
-constrainted variable. But I see no use for this.
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