Какой смысл карты в Haskell, когда есть fmap? - PullRequest
91 голосов
/ 26 июля 2011

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

Ответы [ 3 ]

87 голосов
/ 26 июля 2011

Я хотел бы ответить, чтобы привлечь внимание к комментарию augustss :

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

Haskell 98 рассматривается как шаг назад некоторыми хаскелерами (включая меня), в предыдущих версиях была определена более абстрактная и согласованная библиотека,Ну хорошо.

26 голосов
/ 13 октября 2015

Цитирование из Functor документации на https://wiki.haskell.org/Typeclassopedia#Functor

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

15 голосов
/ 24 июля 2017

Они выглядят одинаково на сайте приложения, но они, конечно, разные.Когда вы применяете любую из этих двух функций, map или fmap, к списку значений, они дают одинаковый результат, но это не значит, что они предназначены для одной и той же цели.

Выполнитьсеанс GHCI (интерактивный компилятор Glasgow Haskell) для запроса информации об этих двух функциях, а затем взгляните на их реализации, и вы обнаружите много различий.

map

Запрос GHCI для получения информациипримерно map

Prelude> :info map
map :: (a -> b) -> [a] -> [b]   -- Defined in ‘GHC.Base’

, и вы увидите, что она определена как функция высокого порядка, применимая к списку значений любого типа a, что дает список значений любого типа b.Хотя полиморфный (a и b в вышеприведенном определении означают любой тип), функция map предназначена для применения к списку значений , который является лишь одним из возможных типов данных среди многихдругие в Хаскеле.Функцию map нельзя применить к чему-то, что не является списком значений.

Как вы можете прочитать из исходного кода GHC.Base , реализована функция mapследующим образом

map _ []     = []
map f (x:xs) = f x : map f xs

, который использует сопоставление с образцом, чтобы вытащить голову (x) из хвоста (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)

и другим возможнымРеализация - это та, которая предоставляется типом данных list (конечно!):

instance  Functor []  where
  fmap f xs = map f xs

, который опирается на функцию map (обратите внимание, что там нет обозначений без точки ... но это выходит за рамкивашего первоначального вопроса).

Заключение

Функция map может быть применена только к списку значений (где значения любого типа), тогда как функция fmap может бытьприменяется гораздо больше типов данных: все те, которые относятся к классу функторов (например, maybes, кортежи, списки и т. д.).Так как тип данных «список значений» также является функтором (поскольку он обеспечивает реализацию для него), то к нему можно применить fmap, что также приведет к тому же результату, что и map.

map  (+3) [1..5]
fmap (+3) (Just 15)
fmap (+3) (5, 7)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...