簡體   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