В основном история. fmap отличается от map по педагогическим причинам, liftM отличается от fmap по историческим причинам (а именно, Functor не является суперклассом Monad)
Луки
12
Да, и просто для ясности: они «по сути» не делают то же самое. Как mapи liftMдолжно, безусловно , делать точно то же самое , как fmap.
CA McCann
2
Хотя fmapи liftMделают абсолютно то же самое, mapконечно, это лишь их частный случай, т.е. нечто иное. fmap id getLineхорошо напечатан, тогда map id getLineкак нет.
Вы можете спросить, зачем нам отдельная функция карты. Почему бы просто не отказаться от текущей функции отображения только списка и вместо этого переименовать fmap в map? Что ж, это хороший вопрос. Обычный аргумент состоит в том, что кто-то, кто только изучает Haskell, при неправильном использовании map, скорее увидит ошибку о списках, чем о функторах.
fmapи liftMсуществуют, потому что монады не были автоматически функторами в Haskell:
Тот факт, что у нас есть и fmap, и liftM, является неудачным следствием того факта, что класс типа Monad не требует экземпляра Functor, хотя с математической точки зрения каждая монада является функтором. Однако fmap и liftM по сути взаимозаменяемы, поскольку это ошибка (в социальном, а не в техническом смысле) для любого типа быть экземпляром Monad, но не быть также экземпляром Functor.
На самом деле это не так. Произошло то, что тип карты был обобщен для покрытия Functor в Haskell 1.3. Т.е. в Haskell 1.3 fmap назывался map. Затем это изменение было отменено в Haskell 1.4 и был представлен fmap. Причина этого изменения была педагогической; при обучении Haskell новичков использование очень общего типа карты затрудняло понимание сообщений об ошибках. На мой взгляд, это был неправильный способ решения проблемы.
И, с моей точки зрения, как человека, который впервые столкнулся с Haskell более чем через десять лет после изменения, описанного @augustss, и потратил много времени, помогая людям, изучающим язык сейчас, совсем не ясно, помогло ли это вообще тем не мение. Конечно, недостаточно, чтобы компенсировать бесполезную избыточность (которая сама по себе приводит к тому, что люди задают подобные вопросы); Functorкласс слишком часто , чтобы игнорировать, и новички часто путаются сообщения об ошибках в любом случае!
CA McCann,
11
Разве мы не можем просто удалить liftM? Пусть код ломается, кого это волнует, обычно требуется меньше 2 дней, чтобы код был исправлен на github, а затем загружен при взломе. Или я дикий и сумасшедший?
Tarrasch
1
@Tarrasch: не все используют github, не все пакеты имеют отличный послужной список для своевременного обновления, и я, например, предпочитаю использовать liftMв do-блоке, а не fmapпотому, что он лучше подходит, когда я использую liftM2, и т. Д. также.
@ L01man Да, это скоро будет исправлено. Предложение Applicative Monad Proposal (AMP) похоже перейдет в следующую версию Haskell. GHC 7.8.3 имеет новый флаг, --fwarn-ampпомогающий обновить существующий код для перехода.
map
иliftM
должно, безусловно , делать точно то же самое , какfmap
.fmap
иliftM
делают абсолютно то же самое,map
конечно, это лишь их частный случай, т.е. нечто иное.fmap id getLine
хорошо напечатан, тогдаmap id getLine
как нет.Ответы:
map
существует для упрощения операций со списками и по историческим причинам (см. В чем смысл карты в Haskell, когда есть fmap? ).- Типклассопедия , стр.20
fmap
иliftM
существуют, потому что монады не были автоматически функторами в Haskell:- Типеклассопедия , стр. 33
Изменить: история Agustuss
map
иfmap
:- В чем смысл карты в Haskell, когда есть fmap?
источник
Functor
класс слишком часто , чтобы игнорировать, и новички часто путаются сообщения об ошибках в любом случае!liftM
? Пусть код ломается, кого это волнует, обычно требуется меньше 2 дней, чтобы код был исправлен на github, а затем загружен при взломе. Или я дикий и сумасшедший?liftM
в do-блоке, а неfmap
потому, что он лучше подходит, когда я используюliftM2
, и т. Д. также.--fwarn-amp
помогающий обновить существующий код для перехода.