chipbk10
chipbk10

Reputation: 5955

Haskell functor error

I create my own data type, and try to implement functor method as follow:

data Hieu a = Hieu [a] deriving (Show, Read, Eq)

instance Functor Hieu where
        fmap f (Hieu [x]) = Hieu (f [x])

It's very simple piece of code but it failed. Can you explain why?


Thanks for all your responses. Now I understand that I apply functor only for one case. I tried to rewrite as follow, without using map

data Hieu a = Hieu [a] deriving (Show, Read, Eq)

consHieu :: a -> (Hieu a) -> (Hieu a)
consHieu x (Hieu xs) = Hieu (x:xs)

instance Functor Hieu where
    fmap f (Hieu (x:xs)) = consHieu (f x) (fmap f (Hieu xs))
    fmap f (Hieu []) = Hieu []

Thanks for all your responses. Now I understand that I apply functor only for one case. I tried to rewrite as follow, without using map

data Hieu a = Hieu [a] deriving (Show, Read, Eq)

consHieu :: a -> (Hieu a) -> (Hieu a)

consHieu x (Hieu xs) = Hieu (x:xs)

instance Functor Hieu where

    fmap f (Hieu (x:xs)) = consHieu (f x) (fmap f (Hieu xs))
    fmap f (Hieu []) = Hieu []

Upvotes: 2

Views: 223

Answers (2)

shachaf
shachaf

Reputation: 8930

You're only handling a single case, a one-element list, and handling it incorrectly. Type-level [a] (the type of lists of any length of as) is very different from value-level [x] (a list containing exactly one element, called x)!

The correct instance would involve using the function in a more involved way.

fmap :: (a -> b) -> Hieu a -> Hieu b
fmap f (Hieu xs) = Hieu (`...`)

At the ..., we have f :: a -> b and xs :: [a], and we want something :: [b]. There's a natural way to get that -- map the function over the list.

So a correct instance would look like:

instance Functor Hieu where
    fmap f (Hieu xs) = Hieu (map f xs)

Any other instance -- for example, one that only handles one-element lists -- wouldn't obey the Functor laws, since we want fmap id h to always be the same thing as h.

Upvotes: 4

hammar
hammar

Reputation: 139930

In the expression f [x] you're applying f to a list, but that's not allowed since the type signature of fmap is (a -> b) -> Hieu a -> Hieu b. You're not allowed to restrict f to [a] -> [b].

Perhaps you meant to write

instance Functor Hieu where
   fmap f (Hieu [x]) = Hieu [f x]

This would compile, but it would only work if the list has exactly one element. The normal way of making Hieu a functor would be to use map to apply the function to all of the elements like so:

instance Functor Hieu where
   fmap f (Hieu xs) = Hieu (map f xs)

Upvotes: 6

Related Questions