我写了这段代码:
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
类型设置仿函数,然后然后遍历列表?
答案 0 :(得分:5)
根据我的理解,您将获得一个像素列表,并且您想要更改每个像素的第一个分量(即红色分量)。因此,您需要以下功能:
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
。
我认为你遇到的最大问题是你不能很好地理解仿函数。你可能应该花一些时间熟悉它们。
答案 1 :(得分:2)
实际上,auto [a, b] = func1(x, y, z);
std::tie(a, b) = func2(x, y, z);
已经有[Pixel Int]
的实例,因为它是一个列表Functor
。列表[]
的{{1}}实例在GHC base中定义(它使用Functor
的定义)。现在您只需要一个可以应用于该列表的每个元素的函数。
[]
map
通常是针对某种容器类型定义的。它需要一个函数并将其应用于容器的内容。然后,当您在具有fmap show [(Pixel 0 0 0),(Pixel 1 0 0), (Pixel 0 1 0)]
实例的容器上调用Functor
时,编译器将检查该函数是否可以应用于该容器的元素。
如果您仍然对Functors感到困惑,我建议您使用本教程:Functors, Applicatives, And Monads In Pictures。
答案 2 :(得分:1)
您的语法有点偏离,fmap
将函数应用于数据类型,并告诉它如何。要更改像素列表的值,您需要在列表上映射(fmap f)。
试试这个实现。
instance Functor Pixel where
fmap f (Pixel (a,b,c)) = Pixel (f a, b, c)
编辑这不会起作用,因为a,b,c需要属于同一类型,而仿函数允许类型为a->b
的函数。
正如@AlexisKing所述,您应该使用fmap
,而是编写类似mapPixelFirst :: (a -> a) -> Pixel a -> Pixel a
的函数。然后将此功能映射到用户列表,不要使用fmap。