Из Википедии, бесплатной энциклопедии
Перейти к навигации Перейти к поиску

Во многих языках программирования , карта является именем функции высшего порядка , которая применяет данную функцию к каждому элементу функтора , например , в списке , возвращая список результатов в том же порядке. Если рассматривать его в функциональной форме, его часто называют « применимым ко всем» .

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

Примеры: отображение списка [ править ]

Предположим, у нас есть список целых чисел, [1, 2, 3, 4, 5]и мы хотим вычислить квадрат каждого целого числа. Для этого мы сначала определяем функцию для squareодного числа (показано здесь в Haskell ):

квадрат  x  =  x  *  x

Впоследствии мы можем позвонить

>>>  квадрат карты  [ 1 , 2 , 3 , 4 , 5 ]     

который дает результат [1, 4, 9, 16, 25], демонстрируя, что mapпрошел через весь список и применил функцию squareк каждому элементу.

Наглядный пример [ править ]

Ниже вы можете увидеть представление каждого шага процесса сопоставления для списка целых чисел, X = [0, 5, 8, 3, 2, 1]которые мы хотим отобразить в новый список в X'соответствии с функцией  :

применение шагов обработки функции карты
Просмотр этапов обработки при применении функции карты в списке

mapПредоставляются как часть Хаскеля базовой прелюдии (т.е. «стандартная библиотека») и реализуются в виде:

map  ::  ( a  ->  b )  ->  [ a ]  ->  [ b ] map  _  []  =  [] map  f  ( x  :  xs )  =  f  x  :  map  f  xs

Обобщение [ править ]

В Haskell полиморфная функция map :: (a -> b) -> [a] -> [b] обобщена до политипической функции fmap :: Functor f => (a -> b) -> f a -> f b , которая применяется к любому типу, принадлежащему классу типов .Functor

Конструктор типов списков []может быть определен как экземпляр Functorкласса типа с помощью mapфункции из предыдущего примера:

instance  Functor  []  где  fmap  =  map

Другие примеры Functorэкземпляров включают деревья:

- простое двоичное дерево данных  Tree  a  =  Leaf  a  |  Вилка  ( Дерево  а )  ( Дерево  а )экземпляр  Functor  Tree,  где  fmap  f  ( Leaf  x )  =  Leaf  ( f  x )  fmap  f  ( Fork  l  r )  =  Fork  ( fmap  f  l )  ( fmap  f  r )

Нанесение карты на дерево дает:

>>>  fmap  square  ( Fork  ( Fork  ( Leaf  1 )  ( Leaf  2 ))  ( Fork  ( Leaf  3 )  ( Leaf  4 ))) Fork  ( Fork  ( Leaf  1 )  ( Leaf  4 ))  ( Fork  ( Leaf  9 )  ( Leaf  16 ))

Для каждого экземпляра Functorтипа class fmapпо контракту обязан подчиняться законам функторов:

fmap  id   id  - закон тождества fmap  ( f  .  g )   fmap  f  .  fmap  g  - закон композиции

где .обозначает композицию функций в Haskell.

Помимо прочего, это позволяет определять поэлементные операции для различных типов коллекций .

Более того, если F и G - два функтора, естественное преобразование - это функция полиморфного типа, которая уважает fmap :

для любой функции .

Если функция h определяется параметрическим полиморфизмом, как в приведенном выше определении типа, эта спецификация всегда выполняется.

Оптимизация [ править ]

Математическая основа карт допускает ряд оптимизаций . Закон композиции гарантирует, что оба

  • (map f . map g) list и
  • map (f . g) list

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

Функции карты могут быть и часто определяются в терминах сгиба, например foldr, что означает, что можно выполнить слияние сгиба карты : foldr f z . map gэквивалентно foldr (f . g) z.

Реализация карты выше в односвязных списках не является хвостовой рекурсивной , поэтому при вызове с большим списком она может создавать много кадров в стеке. Многие языки поочередно предоставляют функцию «обратного сопоставления», которая эквивалентна переворачиванию сопоставленного списка, но является хвостовой рекурсией. Вот реализация, в которой используется функция складывания влево.

reverseMap  f  =  foldl  ( \ ys  x  ->  f  x  :  ys )  []

Поскольку реверсирование односвязного списка также является хвостовой рекурсией, обратное и обратное отображение может быть составлено для выполнения карты нормалей хвостовым рекурсивным способом, хотя для этого требуется выполнить два прохода по списку.

Сравнение языков [ править ]

Функция карты возникла в языках функционального программирования .

В языке Lisp в 1959 г. была введена функция отображения maplist[2] , а в 1958 г. появились несколько иные версии. [3] Это исходное определение maplistотображения функции на последовательные списки остатков:

maplist [x; f] = [null [x] -> NIL; T -> cons [f [x]; maplist [cdr [x]; f]]]

Функция maplistпо - прежнему доступна в новых Лиспах как Common Lisp , [4] , хотя такие функции , как mapcarи более общие mapбы предпочтительнее.

Возведение элементов списка в квадрат с использованием maplistбудет записано в нотации S-выражения следующим образом:

( maplist  ( лямбда  ( l )  ( sqr  ( car  l )))  ' ( 1  2  3  4  5 ))

Используя функцию mapcar, приведенный выше пример будет записан так:

( mapcar  ( функция  sqr )  ' ( 1  2  3  4  5 ))

Сегодня функция отображения поддерживается (или может быть определена) во многих процедурных , объектно-ориентированной и мульти-парадигме языках , а также: В C ++ «s Стандартная библиотека шаблонов , он называется std::transform, в C # (3.0)» ы библиотеки LINQ, его предоставляется как вызываемый метод расширения Select. Карта также является часто используемой операцией в языках высокого уровня, таких как язык разметки ColdFusion (CFML), Perl , Python и Ruby ; операция вызывается mapна всех четырех языках. collectПсевдоним mapтакже предоставляется в Рубине (от Smalltalk). Common Lisp предоставляет семейство функций, подобных карте; вызывается тот, который соответствует описанному здесь поведению mapcar-carуказанием доступа с помощью операции CAR ). Существуют также языки с синтаксическими конструкциями, обеспечивающими ту же функциональность, что и функция карты.

Карта иногда обобщается, чтобы принимать двоичные (2-аргументные) функции, которые могут применять пользовательскую функцию к соответствующим элементам из двух списков. В некоторых языках для этого используются специальные имена, например map2 или zipWith . Языки, использующие явные вариативные функции, могут иметь версии карты с переменной арностью для поддержки переменной арности.функции. Карта с 2 или более списками сталкивается с проблемой обработки, когда списки имеют разную длину. На этом разные языки различаются. Некоторые вызывают исключение. Некоторые останавливаются после длины самого короткого списка и игнорируют лишние элементы в других списках. Некоторые продолжают до длины самого длинного списка, а для списков, которые уже закончились, передают в функцию какое-то значение-заполнитель, указывающее на отсутствие значения.

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

См. Также [ править ]

  • Функтор (функциональное программирование)
  • Свертка (информатика) , также называемая conv или zip
  • Фильтр (функция высшего порядка)
  • Сложить (функция высшего порядка)
  • для каждого
  • Бесплатный моноид
  • Функциональное программирование
  • Функция высшего порядка
  • Понимание списка
  • Карта (параллельный узор)

Ссылки [ править ]

  1. ^ «Слияние карт: ускорение Haskell на 225%»
  2. ^ Дж. Маккарти, К. Мэлинг, С. Рассел, Н. Рочестер, С. Голдберг, Дж. Слэгл. Руководство программиста LISP. Март-апрель 1959 г.
  3. ^ Дж. Маккарти: Символ манипулирования языком - пересмотры языка. Записка AI № 4, октябрь 1958 г.
  4. ^ Функция MAPC, MAPCAR, MAPCAN, MAPL, MAPLIST, MAPCON в ANSI Common Lisp