Везде, где я пробовал пользоваться map, fmapтоже работает. Почему создатели Haskell почувствовали необходимость в mapфункции? Разве это не может быть то, что сейчас известно как язык, fmapи что fmapего можно удалить?
На самом деле это не так. Произошло то, что тип карты был обобщен для покрытия Functor в Haskell 1.3. Т.е. в Haskell 1.3 fmap назывался map. Затем это изменение было отменено в Haskell 1.4 и был представлен fmap. Причина этого изменения была педагогической; при обучении Haskell новичков использование очень общего типа карты затрудняло понимание сообщений об ошибках. На мой взгляд, это был неправильный способ решения проблемы.
Haskell 98 рассматривается некоторыми Haskellers (включая меня) как шаг назад, поскольку в предыдущих версиях была определена более абстрактная и последовательная библиотека. Ну что ж.
Эти шаги назад собраны и задокументированы где-нибудь? Было бы интересно посмотреть, что еще считается шагом назад, и есть ли для них лучшие решения.
Davorak
3
Он map and fmapсуществует уже давно - он был повторно разогрет в списке рассылки Haskell-prime в августе 2006 года - haskell.org/pipermail/haskell-prime/2006-August/thread.html . В качестве контрапункта я предпочитаю статус-кво. Мне кажется ценным наличие подмножества Haskell, примерно соответствующего Миранде. В Великобритании Миранда использовалась в качестве языка обучения для студентов-математиков, а не только для студентов-информатиков. Если эта ниша еще не потеряна для нефункционального языка (например, Mathematica), я не вижу Haskell с унифицированным mapзаполнением.
Стивен Тетли
35
И еще я хотел бы отметить, для тех, кто еще не знает, что август - это Леннарт Аугустссон, который во всех практических целях был частью сообщества Haskell еще до того, как Haskell появился, ср. История Haskell , поэтому данный комментарий ни в коем случае не является слухом!
Забавно, что это решение было принято из педагогических соображений, потому что я все время путал fmap с flatmap при изучении Haskell. Они должны были собрать вместе фокус-группу из n00b. :)
Вы можете спросить, зачем нам отдельная mapфункция. Почему бы просто не отказаться от текущей mapфункции только для списка и
вместо этого переименовать ее fmapв map? Что ж, это хороший вопрос. Обычный аргумент состоит в том, что кто-то, кто только изучает Haskell, при mapнеправильном использовании , скорее увидит ошибку о списках, чем о Functor.
На сайте приложения они выглядят одинаково, но, конечно, они разные. Когда вы применяете одну из этих двух функций mapили fmapк списку значений, они дадут одинаковый результат, но это не значит, что они предназначены для одной и той же цели.
Запустите сеанс GHCI (интерактивный компилятор Glasgow Haskell), чтобы запросить информацию об этих двух функциях, затем посмотрите на их реализации, и вы обнаружите много различий.
карта
Запросите GHCI информацию о map
Prelude>:info map
map ::(a -> b)->[a]->[b]-- Defined in ‘GHC.Base’
и вы увидите, что она определена как функция высокого порядка, применимая к списку значений любого типа, в aрезультате чего получается список значений любого типа b. Хотя и полиморфна ( aи bв приведенном выше определении обозначают любой тип), mapфункция предназначена для применения к списку значений, который является лишь одним из возможных типов данных среди многих других в Haskell. mapФункция не может быть применена к чему - то, не является списком значений.
Как видно из исходного кода GHC.Base , mapфункция реализована следующим образом
map _[]=[]
map f (x:xs)= f x : map f xs
который использует сопоставление с образцом, чтобы вытащить голову (the x) из хвоста (the xs) списка, а затем создает новый список с помощью :конструктора значения (cons), чтобы добавить f x(прочтите его как «f, примененный к x» ) к рекурсии mapнад хвостом, пока список не станет пустым. Стоит отметить, что реализация mapфункции не зависит от какой-либо другой функции, а только от себя.
fmap
Теперь попробуйте запросить информацию, fmapи вы увидите совсем другое.
Prelude>:info fmap
class Functor (f ::*->*)where
fmap ::(a -> b)-> f a -> f b
...-- Defined in ‘GHC.Base’
На этот раз fmapопределяется как одна из функций, реализация которой должна быть обеспечена теми типами данных, которые хотят принадлежать к Functorклассу типов. Это означает, что может быть более одного типа данных, а не только тип данных «список значений» , способных обеспечить реализацию fmapфункции. Это fmapприменимо к гораздо большему набору типов данных: действительно, к функторам!
Как вы можете прочитать из исходного кода GHC.Base , возможная реализация fmapфункции обеспечивается Maybeтипом данных:
instance Functor Maybe where
fmap _ Nothing = Nothing
fmap f (Just a)= Just (f a)
и другая возможная реализация - это тот, который предоставляется типом данных с двумя кортежами
instance Functor ((,) a)where
fmap f (x,y)=(x, f y)
и другая возможная реализация - это тот, который предоставляется типом данных списка (конечно!):
instance Functor []where
fmap f xs = map f xs
который полагается на mapфункцию.
Вывод
mapФункция может быть применена ни к чему не более чем список значений (где значения являются любого типа) , в то время как fmapфункция может быть применена гораздо больше типов данных: все те , которые принадлежат к классу функтора (например maybes, кортежи, списки и т.д. ). Так как тип данных «список значений» также является функтором (потому что он обеспечивает его реализацию), то fmapего можно применять и к нему, что дает тот же результат, что и map.
fmap
. Это для сопоставления функции с экземпляром Functor. Мне интересно узнать о цели специализацииmap
.Ответы:
Я хотел бы дать ответ, чтобы привлечь внимание к комментарию Августы :
Haskell 98 рассматривается некоторыми Haskellers (включая меня) как шаг назад, поскольку в предыдущих версиях была определена более абстрактная и последовательная библиотека. Ну что ж.
источник
map and fmap
существует уже давно - он был повторно разогрет в списке рассылки Haskell-prime в августе 2006 года - haskell.org/pipermail/haskell-prime/2006-August/thread.html . В качестве контрапункта я предпочитаю статус-кво. Мне кажется ценным наличие подмножества Haskell, примерно соответствующего Миранде. В Великобритании Миранда использовалась в качестве языка обучения для студентов-математиков, а не только для студентов-информатиков. Если эта ниша еще не потеряна для нефункционального языка (например, Mathematica), я не вижу Haskell с унифицированнымmap
заполнением.Цитата из
Functor
документации на https://wiki.haskell.org/Typeclassopedia#Functorисточник
На сайте приложения они выглядят одинаково, но, конечно, они разные. Когда вы применяете одну из этих двух функций
map
илиfmap
к списку значений, они дадут одинаковый результат, но это не значит, что они предназначены для одной и той же цели.Запустите сеанс GHCI (интерактивный компилятор Glasgow Haskell), чтобы запросить информацию об этих двух функциях, затем посмотрите на их реализации, и вы обнаружите много различий.
карта
Запросите GHCI информацию о
map
и вы увидите, что она определена как функция высокого порядка, применимая к списку значений любого типа, в
a
результате чего получается список значений любого типаb
. Хотя и полиморфна (a
иb
в приведенном выше определении обозначают любой тип),map
функция предназначена для применения к списку значений, который является лишь одним из возможных типов данных среди многих других в Haskell.map
Функция не может быть применена к чему - то, не является списком значений.Как видно из исходного кода GHC.Base ,
map
функция реализована следующим образомкоторый использует сопоставление с образцом, чтобы вытащить голову (the
x
) из хвоста (thexs
) списка, а затем создает новый список с помощью:
конструктора значения (cons), чтобы добавитьf x
(прочтите его как «f, примененный к x» ) к рекурсииmap
над хвостом, пока список не станет пустым. Стоит отметить, что реализацияmap
функции не зависит от какой-либо другой функции, а только от себя.fmap
Теперь попробуйте запросить информацию,
fmap
и вы увидите совсем другое.На этот раз
fmap
определяется как одна из функций, реализация которой должна быть обеспечена теми типами данных, которые хотят принадлежать кFunctor
классу типов. Это означает, что может быть более одного типа данных, а не только тип данных «список значений» , способных обеспечить реализациюfmap
функции. Этоfmap
применимо к гораздо большему набору типов данных: действительно, к функторам!Как вы можете прочитать из исходного кода GHC.Base , возможная реализация
fmap
функции обеспечиваетсяMaybe
типом данных:и другая возможная реализация - это тот, который предоставляется типом данных с двумя кортежами
и другая возможная реализация - это тот, который предоставляется типом данных списка (конечно!):
который полагается на
map
функцию.Вывод
map
Функция может быть применена ни к чему не более чем список значений (где значения являются любого типа) , в то время какfmap
функция может быть применена гораздо больше типов данных: все те , которые принадлежат к классу функтора (например maybes, кортежи, списки и т.д. ). Так как тип данных «список значений» также является функтором (потому что он обеспечивает его реализацию), тоfmap
его можно применять и к нему, что дает тот же результат, что иmap
.источник