Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is this Functor instance incorrect?

I've written this code:

newtype Pixel a = Pixel (a,a,a) deriving (Show)

instance Functor [Pixel Int] where
    fmap f [] = []
    fmap f [Pixel(a,b,c)] = [Pixel(f a, b, c)]

I want the functor to apply to the first element in the Pixel type, but I keep getting this error:

New.hs:17:18: error:
• Expecting one fewer arguments to ‘[Pixel Int]’
  Expected kind ‘* -> *’, but ‘[Pixel Int]’ has kind ‘*’
• In the first argument of ‘Functor’, namely ‘[Pixel Int]’
  In the instance declaration for ‘Functor [Pixel Int]’

I'm pretty lost on this issue, is there any way to apply a functor on an entire list? Or do I need to set up a functor for an individual Pixel type and then iterate through a list?

like image 390
hdizzle Avatar asked May 28 '26 18:05

hdizzle


2 Answers

From what I understand, you're given a list of pixels and you want to change the first component (i.e. the red component) of every pixel. Hence, you want the following function:

changeAllPixels :: [Pixel Int] -> [Pixel Int]

Q: How do we change every element of a list? A: We use map:

changeAllPixels = map changeOnePixel

changeOnePixel :: Pixel Int -> Pixel Int

We only want to change the red component. Hence, we have:

changeOnePixel = changeRedComponent doSomething

changeRedComponent :: (a -> a) -> Pixel a -> Pixel a
changeRedComponent f (Pixel (r, g, b)) = Pixel (f r, g, b)

doSomething :: Int -> Int

Now you only need to implement doSomething. For example, if you want to invert the red component then you could implement doSomething as follows:

doSomething x = 255 - x

Note that we didn't make Pixel an instance of Functor. This is because we only want to change the red component and leave the green and blue components alone. We did however use map which is the fmap for lists.

I think the biggest problem you have is that you don't understand functors well. You should probably spend some time getting acquainted with them.

like image 136
Aadit M Shah Avatar answered May 31 '26 08:05

Aadit M Shah


Actually, [Pixel Int] already has an instance of Functor because it is a list []. The Functor instance for list [] is defined in GHC base (it uses the definition of map). Now you just need a function that can be applied to each element of that list.

fmap show [(Pixel 0 0 0),(Pixel 1 0 0), (Pixel 0 1 0)]

Functor is generally defined for some container type. It takes a function and applies it to the contents of the container. Then when you call fmap on a container that has an instance of Functor, the compiler will check that the function can be applied to the elements of that container.

If you are still confused about Functors, I recommend this tutorial: Functors, Applicatives, And Monads In Pictures.

like image 40
MCH Avatar answered May 31 '26 07:05

MCH



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!