繁体   English   中英

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

[英]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.

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