Почему этот экземпляр Functor неверен? - PullRequest
0 голосов
/ 14 мая 2018

Я написал этот код:

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 и , а затем перебрать список?

Ответы [ 3 ]

0 голосов
/ 14 мая 2018

Насколько я понимаю, у вас есть список пикселей, и вы хотите изменить первый компонент (то есть красный компонент) каждого пикселя.Следовательно, вам нужна следующая функция:

changeAllPixels :: [Pixel Int] -> [Pixel Int]

Q: Как мы можем изменить каждый элемент списка? A: Мы используем 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 для списков.

Я думаю, что самая большая проблема у вас заключается в том, что вы плохо понимаете функторы.Возможно, вам стоит потратить некоторое время на знакомство с ними.

0 голосов
/ 14 мая 2018

На самом деле, [Pixel Int] уже имеет экземпляр Functor, потому что это список [].Экземпляр Functor для списка [] определен в GHC base (используется определение map).Теперь вам просто нужна функция, которую можно применить к каждому элементу этого списка.

fmap show [(Pixel 0 0 0),(Pixel 1 0 0), (Pixel 0 1 0)]

Functor обычно определяется для некоторого типа контейнера.Он берет функцию и применяет ее к содержимому контейнера.Затем, когда вы вызываете fmap для контейнера, который имеет экземпляр Functor, компилятор проверит, можно ли применить эту функцию к элементам этого контейнера.

Если вы все еще не уверены относительно Functors,Я рекомендую этот урок: Функторы, аппликативы и монады в картинках .

0 голосов
/ 14 мая 2018

Ваш синтаксис немного отключен, 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.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...