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