[英]Why is this Functor instance incorrect?
我写了这段代码:
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)]
我想将仿函数应用于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]’
我在这个问题上很丢失,有没有办法在整个列表中应用仿函数? 或者我是否需要为单个Pixel
类型设置仿函数, 然后遍历列表?
根据我的理解,你会得到一个像素列表,你想要改变每个像素的第一个分量(即红色分量)。 因此,您需要以下功能:
changeAllPixels :: [Pixel Int] -> [Pixel Int]
问:我们如何更改列表中的每个元素? 答:我们使用map
:
changeAllPixels = map changeOnePixel
changeOnePixel :: Pixel Int -> Pixel Int
我们只想更改红色组件。 因此,我们有:
changeOnePixel = changeRedComponent doSomething
changeRedComponent :: (a -> a) -> Pixel a -> Pixel a
changeRedComponent f (Pixel (r, g, b)) = Pixel (f r, g, b)
doSomething :: Int -> Int
现在你只需要实现doSomething
。 例如,如果要反转红色组件,则可以按如下方式实现doSomething
:
doSomething x = 255 - x
请注意,我们没有让Pixel
成为Functor
一个实例。 这是因为我们只想更改红色组件并单独留下绿色和蓝色组件。 然而,我们使用map
作为列表的fmap
。
我认为你遇到的最大问题是你不能很好地理解仿函数。 你可能应该花一些时间熟悉它们。
实际上, [Pixel Int]
已经有一个Functor
实例,因为它是一个列表[]
。 list []
的Functor
实例在GHC base中定义(它使用map
的定义)。 现在您只需要一个可以应用于该列表的每个元素的函数。
fmap show [(Pixel 0 0 0),(Pixel 1 0 0), (Pixel 0 1 0)]
通常为某些容器类型定义Functor
。 它需要一个函数并将其应用于容器的内容。 然后,当您在具有Functor
实例的容器上调用fmap
时,编译器将检查该函数是否可以应用于该容器的元素。
如果你仍然对Functors感到困惑,我推荐这个教程: Functors,Applicatives和Monads In Pictures 。
你的语法有点偏, fmap
将一个函数应用于数据类型,你告诉它如何。 要更改像素列表的值,您需要在列表上映射(fmap f)。 试试这个实现。
instance Functor Pixel where
fmap f (Pixel (a,b,c)) = Pixel (f a, b, c)
编辑这将不起作用,因为a,b,c需要是相同的类型,而functor允许类型a->b
函数。
正如@AlexisKing评论你应该使用fmap
,而是写一个像mapPixelFirst :: (a -> a) -> Pixel a -> Pixel a
的函数。 然后将此功能映射到用户列表,不要使用fmap。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.