简体   繁体   English

为什么这个Functor实例不正确?

[英]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: 我想将仿函数应用于Pixel类型中的第一个元素,但我不断收到此错误:

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? 或者我是否需要为单个Pixel类型设置仿函数, 然后遍历列表?

From what I understand, you're given a list of pixels and you want to change the first component (ie 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 : 答:我们使用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 . 现在你只需要实现doSomething For example, if you want to invert the red component then you could implement doSomething as follows: 例如,如果要反转红色组件,则可以按如下方式实现doSomething

doSomething x = 255 - x

Note that we didn't make Pixel an instance of Functor . 请注意,我们没有让Pixel成为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. 然而,我们使用map作为列表的fmap

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. 你可能应该花一些时间熟悉它们。

Actually, [Pixel Int] already has an instance of Functor because it is a list [] . 实际上, [Pixel Int]已经有一个Functor实例,因为它是一个列表[] The Functor instance for list [] is defined in GHC base (it uses the definition of map ). list []Functor实例在GHC base中定义(它使用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. 通常为某些容器类型定义Functor 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. 然后,当您在具有Functor实例的容器上调用fmap时,编译器将检查该函数是否可以应用于该容器的元素。

If you are still confused about Functors, I recommend this tutorial: Functors, Applicatives, And Monads In Pictures . 如果你仍然对Functors感到困惑,我推荐这个教程: Functors,Applicatives和Monads In Pictures

Your syntax is a bit off, fmap applies a function to a data type and you tell it how. 你的语法有点偏, fmap将一个函数应用于数据类型,你告诉它如何。 To change values for a list of pixels you would need to map (fmap f) over the list. 要更改像素列表的值,您需要在列表上映射(fmap f)。 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 . 编辑这将不起作用,因为a,b,c需要是相同的类型,而functor允许类型a->b函数。

As @AlexisKing commented you should use fmap , but instead write a function like mapPixelFirst :: (a -> a) -> Pixel a -> Pixel a . 正如@AlexisKing评论你应该使用fmap ,而是写一个像mapPixelFirst :: (a -> a) -> Pixel a -> Pixel a的函数。 Then map this function over user list, don't use fmap. 然后将此功能映射到用户列表,不要使用fmap。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM