Reputation: 107
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?
Upvotes: 3
Views: 170
Reputation: 2204
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.
Upvotes: 2
Reputation: 1645
Your syntax is a bit off, fmap
applies a function to a data type and you tell it how. To change values for a list of pixels you would need to map (fmap f) over the list.
Give this implementation a try.
instance Functor Pixel where
fmap f (Pixel (a,b,c)) = Pixel (f a, b, c)
Edit this won't work because a,b,c need to be of the same type and functors allow functions of type a->b
.
As @AlexisKing commented you should use fmap
, but instead write a function like mapPixelFirst :: (a -> a) -> Pixel a -> Pixel a
. Then map this function over user list, don't use fmap.
Upvotes: 1
Reputation: 74204
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.
Upvotes: 5