map :: (a -> b) -> [a] -> [b]
fmap :: Functor f => (a -> b) -> f a -> f b
liftM :: Monad m => (a -> b) -> m a -> m b
Почему у нас есть три разные функции, которые по сути делают одно и то же?
map :: (a -> b) -> [a] -> [b]
fmap :: Functor f => (a -> b) -> f a -> f b
liftM :: Monad m => (a -> b) -> m a -> m b
Почему у нас есть три разные функции, которые по сути делают одно и то же?
map
и liftM
должно, безусловно , делать точно то же самое , как fmap
.
fmap
и liftM
делают абсолютно то же самое, map
конечно, это лишь их частный случай, т.е. нечто иное. fmap id getLine
хорошо напечатан, тогда map id getLine
как нет.
Ответы:
map
существует для упрощения операций со списками и по историческим причинам (см. В чем смысл карты в Haskell, когда есть fmap? ).
Вы можете спросить, зачем нам отдельная функция карты. Почему бы просто не отказаться от текущей функции отображения только списка и вместо этого переименовать fmap в map? Что ж, это хороший вопрос. Обычный аргумент состоит в том, что кто-то, кто только изучает Haskell, при неправильном использовании map, скорее увидит ошибку о списках, чем о функторах.
- Типклассопедия , стр.20
fmap
и liftM
существуют, потому что монады не были автоматически функторами в Haskell:
Тот факт, что у нас есть и fmap, и liftM, является неудачным следствием того факта, что класс типа Monad не требует экземпляра Functor, хотя с математической точки зрения каждая монада является функтором. Однако fmap и liftM по сути взаимозаменяемы, поскольку это ошибка (в социальном, а не в техническом смысле) для любого типа быть экземпляром Monad, но не быть также экземпляром Functor.
- Типеклассопедия , стр. 33
Изменить: история Agustuss map
и fmap
:
На самом деле это не так. Произошло то, что тип карты был обобщен для покрытия Functor в Haskell 1.3. Т.е. в Haskell 1.3 fmap назывался map. Затем это изменение было отменено в Haskell 1.4 и был представлен fmap. Причина этого изменения была педагогической; при обучении Haskell новичков использование очень общего типа карты затрудняло понимание сообщений об ошибках. На мой взгляд, это был неправильный способ решения проблемы.
Functor
класс слишком часто , чтобы игнорировать, и новички часто путаются сообщения об ошибках в любом случае!
liftM
? Пусть код ломается, кого это волнует, обычно требуется меньше 2 дней, чтобы код был исправлен на github, а затем загружен при взломе. Или я дикий и сумасшедший?
liftM
в do-блоке, а не fmap
потому, что он лучше подходит, когда я использую liftM2
, и т. Д. также.
--fwarn-amp
помогающий обновить существующий код для перехода.