Обобщение Хаскелла функции отображения для функтора

#list #haskell #functor #map-function

#Список #хаскелл #функтор #карта-функция

Вопрос:

mapFunctor :: Functor f => (a -> b) -> [f a] -> [f b]

какая эта функция должна быть обобщением карты. Он работает так же, как map функция, и работает для любых функторов, а не только Maybe .

Я застрял на этом. Любые подсказки будут полезны! Спасибо.

Комментарии:

1. Подсказка: взгляните на fmap .

2. Подсказка: подумайте о сигнатуре типа как (a -> b) -> ([f a] -> [f b]) — т.е. Учитывая функцию a -> b , как вы получаете новую функцию [f a] -> [f b] ? Если вы не видите, как это сделать, можете ли вы сначала получить функцию f a -> f b ? Если да, можете ли вы увидеть, как перейти от этого к нужному вам типу?

3. когда я использую fmap, появляется сообщение об ошибке, в котором ожидаемый тип: [f b], фактический тип [b]

4. @Jacky: да, вы не можете использовать fmap напрямую, так как тогда он будет смотреть на конструктор внешнего типа, видеть [] и специализироваться f ~ [] . Вам нужно fmap map как-то объединить и.

5. Еще одна полезная вещь, которую следует иметь в виду, [x] это синтаксический сахар для [] x , так что, например [f a] , = [] (f a) и [[a]] = [] ([] a)

Ответ №1:

Сыграйте в головоломку типов / соедините провода (какую бы метафору вы ни предпочитали):

 mapFunctor :: Functor f 
           => (a -> b) -> [f a] -> [f b]
mapFunctor    f           []     = []
mapFunctor    f           (x:xs) = (y:ys)
  where
  --        (x:xs) :: [f a]
  --           xs  :: [f a]
  --         x     ::  f a
  --       f       ::    a  ->    b
  --  fmap f       ::  f a  ->  f b
  --  fmap f x     ::           f b 
  --        (y:ys) ::          [f b]
  --         y     ::           f b 
  --           ys  ::          [f b]
  -- mapFunctor f  :: [f a] -> [f b]
  -- mapFunctor f xs        :: [f b]
  y  =  ....
  ys =  ..... 

Когда вы узнаете больше, вы увидите, что [] тип также является функтором, поэтому ваша функция справедлива fmap . fmap . Но это будет позже.

Ответ №2:

Это всего лишь комбинация map и fmap . Это fmap :: Functor f => (a -> b) -> f a -> f b функция, которая выполняет сопоставление для каждого типа, являющегося экземпляром класса типов Functor , и map :: (c -> d) -> [c] -> [d] используется для создания функции, которая содержит результат применения функции к каждому элементу.

Я оставляю это как упражнение для объединения двух в функцию mapFunctor :

 mapFunctor :: Functor f => (a -> b) -> [f a] -> [f b]
mapFunctor = …