Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Haskell type class instance syntax

Tags:

haskell

Suppose i have a datatype MayFail defined as following

data MayFail e a = Error e | Result a
    deriving (Show)

So it's either a result or an error. I now want to write a Functor for it but this is where it gets confusing.

MayFail has two types, either e or a. So why do I have to write the functor as follows

instance Functor (MayFail e) where
  fmap _ (Error e)  = Error e
  fmap f (Result x) = Result (f x)

and not instance Functor (MayFail e a) where?

What is the syntactic rule behind this?

like image 954
Wouter Vandenputte Avatar asked Aug 19 '19 18:08

Wouter Vandenputte


2 Answers

Your question is a bit unclear, but I assume you're asking why you have to use e in instance Functor (MayFail e) instead of just writing instance Functor MayFail.

This is because Functor takes a type parameter of kind Type -> Type, and MayFail on its own would have kind Type -> Type -> Type. (Using MayFail e a would also be wrong, as its kind is just Type.)

like image 195
Joseph Sible-Reinstate Monica Avatar answered Sep 25 '22 21:09

Joseph Sible-Reinstate Monica


MayFail :: Type -> Type -> Type is not a functor, but a bifunctor:

-- somewhat simplified definition
class Bifunctor p where
    -- p :: Type -> Type -> Type
    bimap :: (a -> c) -> (c -> d) -> p a b -> p c d

instance Bifunctor MayFail where
    bimap f _ (Error e) = Error (f e)
    bimap _ g (Result x) = Result (g x)

But, for any fixed error type e, the result of the partial application MayFail e :: Type -> Type is a functor:

instance Functor (MayFail e) where
    fmap _ (Error e) = Error e
    fmap f (Result x) = Result (f x)
    -- Or, using the Bifunctor instance,
    -- fmap = bimap id

In some sense, a bifunctor is a mapping of types to functors.

like image 38
chepner Avatar answered Sep 21 '22 21:09

chepner