Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Making a basic Haskell type an instance of a new typeclass

Tags:

haskell

Say I'm trying to define a new typeclass in Haskell, and among other things, it must have a + operation:

class Foo a where
    (+) :: a -> a -> a

(In practice the typeclass Foo would have more stuff, but let me stop here to keep this minimal.)

Now, I want to make the basic "Integer" type an instance of Foo; and as far as the + operation goes, I just want to keep the usual addition, which is already defined. How do I do that?

Needless to say, the following makes no sense:

instance Foo Integer where
    (+) x y = x+y

It loops forever when I ask Haskell to compute 2+3, but I suppose that's to be expected! I also tried putting nothing at all:

instance Foo Integer

This compiles, but then when I ask for 2+3 I get "No instance nor default method for class operation +". Again, it makes sense...

But how do we do that then?

I guess it's a general question "about the namespace", I mean, when two typeclasses use the same names, what happens? In my case, I get issues when trying to make a type (Integer) an instance of two typeclasses with such a name clash (Num and Foo).

From reading this question, I'm now afraid that what I'm asking for is just prohibited...

like image 467
Pierre Avatar asked Aug 23 '18 15:08

Pierre


People also ask

What is an instance of a Haskell type class?

An instance of a class is an individual object which belongs to that class. In Haskell, the class system is (roughly speaking) a way to group similar types. (This is the reason we call them "type classes"). An instance of a class is an individual type which belongs to that class.

What is the difference between type and data in Haskell?

Type and data type refer to exactly the same concept. The Haskell keywords type and data are different, though: data allows you to introduce a new algebraic data type, while type just makes a type synonym. See the Haskell wiki for details.

Does Haskell have different types?

Everything in Haskell has a type, so the compiler can reason quite a lot about your program before compiling it. Unlike Java or Pascal, Haskell has type inference.


2 Answers

To give a specific solution, something like this would work without having to deal with clashing with (+):

class Foo a where
  (<+>) :: a -> a -> a

infixl 6 <+>

instance Foo Integer where
  (<+>) = (+)

Now your class Foo has its own operator, and the fixity declaration means that (<+>) will be parsed the same way as (+).

like image 105
Samuel Barr Avatar answered Sep 29 '22 19:09

Samuel Barr


If you really want to call your operation +, and you want to define it in terms of the + from Prelude, you can do it like this:

import Prelude (Integer, print)
import qualified Prelude ((+))

class Foo a where
  (+) :: a -> a -> a

instance Foo Integer where
  (+) x y = x Prelude.+ y

main = print (2 + 3 :: Integer)

This will output 5.

To prove that the definition of main is really using our new + operator and not the original one, we can change our definition of +:

import Prelude (Integer, print)
import qualified Prelude ((+))

class Foo a where
  (+) :: a -> a -> a

instance Foo Integer where
  (+) x y = x Prelude.+ y Prelude.+ 1

main = print (2 + 3 :: Integer)

This will output 6.

like image 43
Tanner Swett Avatar answered Sep 29 '22 19:09

Tanner Swett