#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 = …