Почему у нас есть карта, fmap и liftM?

map :: (a -> b) -> [a] -> [b]

fmap :: Functor f => (a -> b) -> f a -> f b

liftM :: Monad m => (a -> b) -> m a -> m b

Почему у нас есть три разные функции, которые делают практически одно и то же?

Ответ 1

map существует для упрощения операций над списками и по историческим причинам (см. Какова точка карты в Haskell, когда есть fmap?).

3Вы можете спросить, почему нам нужна отдельная функция отображения. Почему бы просто не покончить с текущим отображение только списка, а вместо этого переименовать fmap? Ну, это хороший вопрос. обычный аргумент состоит в том, что кто-то, просто изучая Haskell, неправильно использует карту, скорее посмотрите ошибку о списках, чем о функторах.

- Typeclassopedia, стр. 20

fmap и liftM существуют потому, что монады не были автоматически функторами в Haskell:

Тот факт, что мы имеем как fmap, так и liftM, является неудачное следствие того, что класс типа Монада не требует экземпляр Functor, хотя математически говоря, каждая монада является функтор. Однако fmap и liftM существенно взаимозаменяемы, поскольку ошибка (в социальном, а не техническом смысле) для любого типа, являющегося экземпляром из Монады, не являясь также экземпляром Functor.

- Typeclassopedia, стр. 33

Изменить: история agustuss map и fmap:

Это не так, как это происходит. Случилось так, что тип карты был обобщен, чтобы охватить Functor в Haskell 1.3. I.e., в Haskell 1.3 fmap называлась картой. Затем это изменение было возвращено в Haskell 1.4 и введен fmap. Причина этого изменения была педагогической; при обучении Haskell новичкам очень общий тип карты затруднял понимание сообщений об ошибках. По-моему, это был неправильный способ решить проблему.

- Какова точка карты в Haskell, когда есть fmap?