Why can't I make an instance with this non-parameterized type?

Why is this code correct?

instance Functor IO where -- note that IO isn't parametrized, and it correct fmap f action = do result <- action return (f result) 

but does the following code have a compiler error?

 class Print a where print :: a -> String data A t = A t instance Print A where -- error: expecting one more argument to `A' print a = "abc" 
+6
source share
3 answers

This is because the types do not match. Regular types have the form * , while type constructors such as A or IO have the form * -> * , indicating that they need a type parameter to return the type.

In the definition of the Print class, the compiler reports that, since A used as a simple type, it must be of the form * . However, Functor works on type constructors of the form * -> * :

 class Functor f where fmap :: (a -> b) -> fa -> fb 

Here f not used as a regular type, but as a type constructor, so it displays the form * -> * . You can verify this with the :kind command in GHCi:

 > :kind Print Print :: * -> Constraint > :kind Functor Functor :: (* -> *) -> Constraint 
+10
source

When you speak

 class Print a where print' :: a -> String 

You make sure that a must be a type, but when you say

 data A t = A t 

you make a type constructor - a not a type, but A Int is, for example. a is a kind of function for types, but a in the Print class must be a type value, not a type function.

You could do

 instance Print (A Int) where print' a = "abc" 

This is normal for IO , because the Functor class requests a type constructor.

 class Functor f where fmap :: (a -> b) -> fa -> fb 

You can see that since fa is a type, f is a type constructor, like IO and a . You can do

 instance Functor A where -- OK, A is a constructor, Functor needs one fmap f (A x) = A (fx) 

and you cannot do

 instance Eq IO where -- not OK - IO is a constructor and Eq needs a type (==) = error "this code won't compile" 

(I used print' instead of print to avoid a collision with the standard print function.)

+9
source

Try mentally (or with a text editor) to populate the types specified in the class definition with the type that you used in the instance.

From:

 class Print a where print :: a -> String 

and

 data A t = A t 

we want

 instance Print A 

So, substituting a in the type class definition for a , we say it is instnace, we get the following:

 class Print a where print :: a -> String 

Ooh A -> String does not make sense as a type, since the function type of the arrow takes the type on the left and the type on the right and gives you the type of the function. But a not a type since you declared a with data A t ; A t is a type for any type of t , but a is a type constructor. It can create a type if you apply it to a type, but a by itself is something else. So you can make A t into a Print instance, but not a .

So why did instance Functor IO ? Let's look at the class definition:

 class Functor f where fmap :: (a -> b) -> fa -> fb 

Now try substituting IO for f :

 class Functor IO where fmap :: (a -> b) -> IO a -> IO b 

IO at the end applies to type parameters, so it all works. Here we ran into problems if we tried to make a concrete type of type Int or A t instance of Functor .

+1
source

All Articles