Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

"enable_if" in Haskell

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.

like image 627
Clinton Avatar asked Aug 10 '12 06:08

Clinton


2 Answers

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).

like image 125
Volker Stolz Avatar answered Sep 29 '22 01:09

Volker Stolz


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.

like image 38
Vladimir Matveev Avatar answered Sep 29 '22 01:09

Vladimir Matveev