Что такое функтор в функциональном программировании?

Я встречал термин "Functor" несколько раз, читая различные статьи по функциональному программированию, но авторы обычно предполагают, что читатель уже понимает этот термин. Оглядываясь в Интернете, вы предоставляете либо чрезмерно технические описания (см. статью Википедии), либо невероятно смутные описания (см. Раздел о функторах в этом веб-сайт ocaml-tutorial).

Может кто-то любезно определить этот термин, объяснить его использование и, возможно, привести пример того, как создаются и используются функторы?

Изменить. Хотя меня интересует теория, лежащая в основе этого термина, меня меньше интересует теория, чем я в реализации и практическом использовании концепции.

Изменить 2. Похоже, что происходит кросс-терминология: я специально ссылаюсь на Функторы функционального программирования, а не на функциональные объекты С++.

Ответ 1

Слово "функтор" происходит от теории категорий, которая является очень общей, очень абстрактной ветвью математики. Он был заимствован разработчиками функциональных языков по крайней мере двумя разными способами.

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

    В качестве примера реализации и практического использования вы можете определить свою любимую форму сбалансированного дерева двоичного поиска раз и навсегда как функтор, и в качестве параметра будет использоваться модуль, который обеспечивает:

    • Тип ключа, который будет использоваться в двоичном дереве

    • Функция полного упорядочения на клавишах

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

    Другим применением ML-функторов является многоуровневые сетевые протоколы. Ссылка на действительно потрясающую работу группы CMU Fox; он показывает, как использовать функторы для создания более сложных слоев протокола (например, TCP) на типе более простых слоев (например, IP или даже непосредственно через Ethernet). Каждый уровень реализуется как функтор, который принимает в качестве параметра слой под ним. Структура программного обеспечения фактически отражает то, как люди думают о проблеме, в отличие от слоев, существующих только в сознании программиста. В 1994 году, когда эта работа была опубликована, это было большой проблемой.

    Для дикого примера функторов ML в действии вы можете увидеть документ ML Module Mania, который содержит публикацию (то есть страшную) пример функторов на работе. Для блестящего, ясного, прозрачного объяснения системы модулей ML (с сопоставлением с другими типами модулей) прочитайте первые несколько страниц документа POPL 1994 года Xavier Leroy блестяще Типы манифеста, модули и отдельная компиляция.

  • В Haskell и в некотором родственном чистом функциональном языке Functor - это класс типа. Тип относится к типу класса (или более технически, тип "является экземпляром" класса типа "), когда тип предоставляет определенные операции с определенным ожидаемым поведением. Тип T может принадлежать классу Functor, если он имеет определенное поведение, подобное коллекции:

    • Тип T параметризуется над другим типом, который вы должны рассматривать как тип элемента коллекции. Тип полной коллекции тогда похож на T Int, T String, T Bool, если вы содержите целые числа, строки или булевы соответственно. Если тип элемента неизвестен, он записывается как параметр типа a, как в T a.

      Примеры включают списки (ноль или более элементов типа a), тип Maybe (ноль или один элемент типа a), наборы элементов типа a, массивы элементов типа a, все виды деревьев поиска, содержащие значения типа a, и многие другие, о которых вы можете подумать.

    • Другим свойством, которое T должно удовлетворять, является то, что если у вас есть функция типа a -> b (функция на элементах), тогда вы должны иметь возможность использовать эту функцию и продукт для связанной функции по коллекциям. Вы делаете это с помощью оператора fmap, который разделяется каждым типом класса Functor. Оператор фактически перегружен, поэтому, если у вас есть функция even с типом Int -> Bool, то

      fmap even
      

      - перегруженная функция, которая может делать много замечательных вещей:

      • Преобразование списка целых чисел в список логических

      • Преобразование дерева целых чисел в дерево логических

      • Преобразуйте Nothing в Nothing и Just 7 в Just False

      В Haskell это свойство выражается выражением типа fmap:

      fmap :: (Functor t) => (a -> b) -> t a -> t b
      

      где теперь мы имеем небольшой T, что означает "любой тип в классе Functor".

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

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

Ответ 2

Другие ответы здесь полны, но я попробую другое объяснение использования FP функтора. Возьмем это как аналог:

Функтор - это контейнер типа a, который при воздействии функции, которая отображает из a → b, дает контейнер типа b.

В отличие от использования аббревиатуры-указателя-указателя в С++, функтор не является функцией; скорее, это то, что ведет себя последовательно при воздействии функции.

Ответ 3

Существует три разных значения, не связанных друг с другом!

  • В Ocaml это параметризованный модуль. См. manual. Я думаю, что лучший способ проверить их на примере: (быстро написано, может быть, глючит)

    module type Order = sig
        type t
        val compare: t -> t -> bool
    end;;
    
    
    module Integers = struct
        type t = int
        let compare x y = x > y
    end;;
    
    module ReverseOrder = functor (X: Order) -> struct
        type t = X.t
        let compare x y = X.compare y x
    end;;
    
    (* We can order reversely *)
    module K = ReverseOrder (Integers);;
    Integers.compare 3 4;;   (* this is false *)
    K.compare 3 4;;          (* this is true *)
    
    module LexicographicOrder = functor (X: Order) -> 
      functor (Y: Order) -> struct
        type t = X.t * Y.t
        let compare (a,b) (c,d) = if X.compare a c then true
                             else if X.compare c a then false
                             else Y.compare b d
    end;;
    
    (* compare lexicographically *)
    module X = LexicographicOrder (Integers) (Integers);;
    X.compare (2,3) (4,5);;
    
    module LinearSearch = functor (X: Order) -> struct
        type t = X.t array
        let find x k = 0 (* some boring code *)
    end;;
    
    module BinarySearch = functor (X: Order) -> struct
        type t = X.t array
        let find x k = 0 (* some boring code *)
    end;;
    
    (* linear search over arrays of integers *)
    module LS = LinearSearch (Integers);;
    LS.find [|1;2;3] 2;;
    (* binary search over arrays of pairs of integers, 
       sorted lexicographically *)
    module BS = BinarySearch (LexicographicOrder (Integers) (Integers));;
    BS.find [|(2,3);(4,5)|] (2,3);;
    

Теперь вы можете быстро добавить множество возможных заказов, способы формирования новых заказов, легко выполнить двойной или линейный поиск. Общее программирование FTW.

  • В функциональных языках программирования, таких как Haskell, это означает некоторые конструкторы типов (параметризованные типы, такие как списки, наборы), которые можно "отобразить". Если быть точным, функтор f снабжен (a -> b) -> (f a -> f b). Это имеет место в теории категорий. Статья Википедии, с которой вы связаны, - это использование.

    class Functor f where
        fmap :: (a -> b) -> (f a -> f b)
    
    instance Functor [] where      -- lists are a functor
        fmap = map
    
    instance Functor Maybe where   -- Maybe is option in Haskell
        fmap f (Just x) = Just (f x)
        fmap f Nothing = Nothing
    
    fmap (+1) [2,3,4]   -- this is [3,4,5]
    fmap (+1) (Just 5)  -- this is Just 6
    fmap (+1) Nothing   -- this is Nothing
    

Итак, это особый тип конструкторов типов и имеет мало общего с функторами в Ocaml!

  • В императивных языках это указатель на функционирование.

Ответ 4

В OCaml это параметризованный модуль.

Если вы знаете С++, подумайте о функторе OCaml как шаблоне. С++ имеет только шаблоны классов, а функторы работают в масштабе модуля.

Примером функтора является Map.Make; module StringMap = Map.Make (String);; строит модуль карты, который работает со строковыми ключами.

Вы не могли бы добиться чего-то вроде StringMap только с полиморфизмом; вам нужно сделать некоторые предположения на клавишах. Модуль String содержит операции (сравнение и т.д.) На полностью упорядоченном строковом типе, а функтор связывается с операциями, содержащимися в модуле String. Вы могли бы сделать что-то подобное с объектно-ориентированным программированием, но у вас были бы затраты на косвенные методы.

Ответ 5

У вас есть несколько хороших ответов. Я сделаю следующее:

Функтор в математическом смысле является особым видом функции на алгебре. Это минимальная функция, которая отображает алгебру в другую алгебру. "Минимальность" выражается законами функтора.

Есть два способа взглянуть на это. Например, списки являются функторами над некоторым типом. То есть, учитывая алгебру над типом 'a', вы можете создать совместимую алгебру списков, содержащих вещи типа 'a'. (Например: карта, которая берет элемент в одноэлементный список, содержащий его: f (a) = [a]) Опять же, понятие совместимости выражается законами функтора.

С другой стороны, учитывая функтор f "над" типом a (т.е. fa является результатом применения функтора f к алгебре типа a) и функции из g: a → b, мы можем вычислить новый функтор F = (fmap g), который отображает fa в f b. Короче говоря, fmap является частью F, которая отображает "части функтора" на "части функтора", а g - это часть функции, которая отображает "части алгебры" в "части алгебры". Он выполняет функцию, функтор и после завершения, он также является функтором.

Может показаться, что разные языки используют разные понятия функторов, но это не так. Они просто используют функторы над разными алгебрами. OCamls имеет алгебру модулей, а функторы над этой алгеброй позволяют присоединять новые объявления к модулю "совместимым" способом.

Функтор Haskell НЕ является классом типа. Это тип данных со свободной переменной, которая удовлетворяет классу типов. Если вы захотите вникать в кишки типа данных (без свободных переменных), вы можете переосмыслить тип данных как функтора над лежащей в основе алгеброй. Например:

данные F = F Int

изоморфна классу Ints. Таким образом, F, как конструктор значений, является функцией, которая отображает Int в F Int, эквивалентную алгебру. Это функтор. С другой стороны, вы не получаете fmap бесплатно здесь. То, что соответствует шаблону.

Функторы хороши для "прикрепления" вещей к элементам алгебр алгебраически совместимым способом.

Ответ 6

В книге O'Reilly OCaml есть довольно хороший пример, который на веб-сайте Inria (который, к сожалению, отсутствует). Я нашел очень похожий пример в этой книге, используемой caltech: Введение в OCaml (pdf-ссылка). Соответствующий раздел представляет собой главу о функторах (стр. 139 в книге, стр. 149 в PDF).

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

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

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

module SSet = MakeSet(StringCaseEqual);;

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

Тобу сравнивал функторы с шаблонами в С++, которые, как мне кажется, довольно уместны.

Ответ 7

Лучший ответ на этот вопрос можно найти в "Typeclassopedia" Брент Йорги.

В этом выпуске Monad Reader содержится точное определение того, что такое функтор, а также многие определения других понятий, а также диаграмма. (Моноид, Аппликативный, Монад и другое понятие объясняются и рассматриваются относительно функтора).

http://haskell.org/sitewiki/images/8/85/TMR-Issue13.pdf

выдержка из Typeclassopedia for Functor: "Простая интуиция заключается в том, что Functor представляет собой" контейнер "некоторых сортировать, а также возможность равномерно применять функцию к каждому элементу в контейнер "

Но на самом деле все typeclassopedia - это очень рекомендуемое чтение, которое на удивление легко. В какой-то мере вы можете увидеть представленную там типовую форму как параллельный шаблон проектирования в объекте в том смысле, что они дают вам словарь для данного поведения или возможностей.

Приветствия

Ответ 9

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

Для намека на смысл слова "функтор" в Haskell спросите GHCi:

Prelude> :info Functor
class Functor f where
  fmap :: forall a b. (a -> b) -> f a -> f b
  (GHC.Base.<$) :: forall a b. a -> f b -> f a
        -- Defined in GHC.Base
instance Functor Maybe -- Defined in Data.Maybe
instance Functor [] -- Defined in GHC.Base
instance Functor IO -- Defined in GHC.Base

Итак, в принципе, функтор в Haskell - это то, что можно сопоставить. Другой способ сказать, что функтор - это то, что можно рассматривать как контейнер, который можно попросить использовать данную функцию для преобразования содержащегося в ней значения; таким образом, для списков fmap совпадает с map, для Maybe, fmap f (Just x) = Just (f x), fmap f Nothing = Nothing и т.д.

подраздел "Предметный указатель" и раздел Функторы, аппликативные функторы и Моноиды Учите вас Haskell для Great Good дайте несколько примеров того, где эта конкретная концепция полезна. (Резюме: много мест!: -))

Обратите внимание, что любую монаду можно рассматривать как функтор, и на самом деле, как указывает Крейг Штунц, наиболее часто используемые функторы имеют тенденцию быть монадами... OTOH, иногда удобно делать тип экземпляром класс Functor, не создавая проблемы с Monad. (Например, в случае ZipList из Control.Applicative, упомянутого на одной из вышеупомянутых страниц.)

Ответ 10

В комментарии к голосу ответ, пользователь Вэй Ху спрашивает:

Я понимаю как ML-функторы, так и Haskell-функторы, но не хватает чтобы связать их вместе. Какая связь между этими два, в категориальном смысле?

Примечание. Я не знаю ML, поэтому, пожалуйста, простите и исправьте любые связанные с этим ошибки.

Предположим сначала, что мы все знакомы с определениями "категории" и "функтора".

Компактный ответ заключался бы в том, что "Haskell-функторы" являются (эндо-) функторами F : Hask -> Hask, а "ML-функторы" являются функторами G : ML -> ML'.

Здесь Hask - это категория, образованная типами и функциями Haskell между ними, а также ML и ML' - это категории, определенные структурами ML.

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

С точки зрения теории категорий это означает, что a Hask -функтор - это отображение F типов Haskell:

data F a = ...

вместе с отображением fmap функций Хаскелла:

instance Functor F where
    fmap f = ...

ML почти то же самое, хотя канонической абстракции fmap я не знаю, поэтому давайте определим ее:

signature FUNCTOR = sig
  type 'a f
  val fmap: 'a -> 'b -> 'a f -> 'b f
end

Это F отображает ML -типы и fmap отображает ML -функции, поэтому

functor StructB (StructA : SigA) :> FUNCTOR =
struct
  fmap g = ...
  ...
end

является функтором F: StructA -> StructB.

Ответ 11

"Функтор - это отображение объектов и морфизмов, сохраняющих состав и идентичность категории."

Определяет, что такое категория?

Это куча объектов!

Нарисуйте несколько точек (теперь 2 точки, один - "a" другой - "b" ) внутри круг и имя, которые теперь имеют круг A (категория).

Что относится к категории?

Состав между объектами и функцией Identity для каждого объекта.

Итак, мы должны отобразить объекты и сохранить композицию после применения нашего Functor.

Предположим, что "А" - наша категория, которая имеет объекты ['a', 'b'] и существует морфизм a → b

Теперь нам нужно определить функтор, который может отображать эти объекты и морфизмы в другую категорию "B" .

Допустим, что функтор называется "Может быть"

data Maybe a = Nothing | Just a

Итак, категория "B" выглядит так.

Проведите еще один круг, но на этот раз с 'Maybe a' и 'Maybe b' вместо 'a' и 'b'.

Все кажется хорошим и все объекты сопоставлены

'a' стал 'Maybe a' и 'b' стал 'Maybe b'.

Но проблема в том, что мы должны отобразить морфизм от 'a' до 'b'.

Это означает, что морфизм a → b в 'A' должен отображаться в морфизм 'Maybe a' → 'Maybe b'

морфизм из a → b называется f, то морфизм из "Maybe a" → "Maybe b" называется "fmap f"

Теперь давайте посмотрим, какая функция 'f' делала в 'A' и посмотрим, можем ли мы воспроизвести ее в 'B'

определение функции 'f' в 'A':

f :: a -> b

f принимает a и возвращает b

определение функции 'f' в 'B':

f :: Maybe a -> Maybe b

f принимает Maybe a и return Maybe b

позволяет увидеть, как использовать fmap для сопоставления функции 'f' от 'A' до функции 'fmap f' в 'B'

определение fmap

fmap :: (a -> b) -> (Maybe a -> Maybe b)
fmap f Nothing = Nothing
fmap f (Just x) = Just(f x)

Итак, что мы здесь делаем?

Мы применяем функцию 'f' к 'x', которая имеет тип 'a'. Специальное сопоставление шаблонов "Nothing" происходит из определения Functor Maybe.

Итак, мы отобразили наши объекты [a, b] и морфизмы [f] из категории "A" в категорию "B" .

Thats Functor!

введите описание изображения здесь

Ответ 12

Не противоречить предыдущим теоретическим или математическим ответам, но Functor также является объектом (на объектно-ориентированном языке программирования), который имеет только один метод и эффективно используется как функция.

Примером является интерфейс Runnable в Java, который имеет только один метод: run.

Рассмотрим этот пример, сначала в Javascript, который имеет первоклассные функции:

[1, 2, 5, 10].map(function(x) { return x*x; });

Вывод: [1, 4, 25, 100]

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

Чтобы сделать то же самое, это Java, используя Functor, вам сначала нужно определить интерфейс, скажем:

public interface IntMapFunction {
  public int f(int x);
}

Затем, если вы добавите класс коллекции, который имеет функцию карты, вы можете сделать:

myCollection.map(new IntMapFunction() { public int f(int x) { return x * x; } });

Это использует встроенный подкласс IntMapFunction для создания Functor, который является эквивалентом OO функции из предыдущего примера JavaScript.

Использование Functors позволяет применять функциональные методы на языке OO. Конечно, некоторые языки OO также поддерживают функции напрямую, поэтому это не требуется.

Ссылка: http://en.wikipedia.org/wiki/Function_object

Ответ 13

Краткий обзор

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

Примеры функторов включают в себя массивы, "возможно" и "либо" функторы, фьючерсы (см., например, https://github.com/Avaq/Fluture) и многие другие.

Иллюстрация

Рассмотрим функцию, строящую полное имя человека от имени и фамилии. Мы могли бы определить его как fullName(firstName, lastName) как функцию двух аргументов, которые, однако, не подходят для функторов, которые имеют дело только с функциями одного аргумента. Чтобы исправить, мы собираем все аргументы в одном объекте name, который теперь становится единственным аргументом функции:

// In JavaScript notation
fullName = name => name.firstName + ' ' + name.lastName

Теперь, если у нас много людей в массиве? Вместо того, чтобы вручную перебирать список, мы можем просто повторно использовать нашу функцию fullName с помощью метода map, предоставляемого для массивов с короткой отдельной строкой кода:

fullNameList = nameList => nameList.map(fullName)

и используйте его как

nameList = [
    {firstName: 'Steve', lastName: 'Jobs'},
    {firstName: 'Bill', lastName: 'Gates'}
]

fullNames = fullNameList(nameList) 
// => ['Steve Jobs', 'Bill Gates']

Это будет работать, всякий раз, когда каждая запись в нашем nameList является объектом, предоставляющим как свойства firstName, так и lastName. Но что, если некоторые объекты не (или даже не являются объектами вообще)? Чтобы избежать ошибок и сделать код более безопасным, мы можем обернуть наши объекты в тип Maybe (например, https://sanctuary.js.org/#maybe-type):

// function to test name for validity
isValidName = name => 
    (typeof name === 'object') 
    && (typeof name.firstName === 'string')
    && (typeof name.lastName === 'string')

// wrap into the Maybe type
maybeName = name => 
    isValidName(name) ? Just(name) : Nothing()

где Just(name) - контейнер, содержащий только допустимые имена, и Nothing() - это особое значение, используемое для всего остального. Теперь вместо того, чтобы прерывать (или забывать) проверку правильности наших аргументов, мы можем просто повторно использовать (поднять) нашу оригинальную функцию fullName с другой отдельной строкой кода, основанной снова на методе map, на этот раз для Возможно, введите:

// Maybe Object -> Maybe String
maybeFullName = maybeName => maybeName.map(fullName)

и используйте его как

justSteve = maybeName(
    {firstName: 'Steve', lastName: 'Jobs'}
) // => Just({firstName: 'Steve', lastName: 'Jobs'})

notSteve = maybeName(
    {lastName: 'SomeJobs'}
) // => Nothing()

steveFN = maybeFullName(justSteve)
// => Just('Steve Jobs')

notSteveFN = maybeFullName(notSteve)
// => Nothing()

Теория категорий

A Функтор в категории Теория - это карта между двумя категориями, относящимися к составу их морфизмов. На компьютерном языке основной категории интересов является та, чьи объекты являются типами (некоторые наборы значений) и чьи морфизмы являются функциями f:a->b из одного типа a другому типу b.

Например, возьмите a как тип String, b тип Number, а f - это функция, отображающая строку в ее длину:

// f :: String -> Number
f = str => str.length

Здесь a = String представляет собой набор всех строк и b = Number набор всех чисел. В этом смысле, как a, так и b представляют объекты в Set Category (которые тесно связаны с категорией типов, причем разница здесь несущественна). В категории "Set" морфизмы между двумя наборами - это точно все функции из первого набора во второй. Поэтому наша функция длины f здесь является морфизмом из множества строк в множество чисел.

Поскольку мы рассматриваем только заданную категорию, соответствующие Функторы из нее в себя являются картами, отправляющими объекты в объекты и морфизмы в морфизмы, которые удовлетворяют некоторым алгебраическим законам.

Пример: Array

Array может означать много вещей, но только одно - это Functor - конструктор типа, отображающий тип a в тип [a] всех массивов типа a. Например, функтор Array отображает тип String в тип [String] (набор всех массивов строк произвольной длины) и задает тип Number в соответствующий тип [Number] (набор все массивы чисел).

Важно не путать карту Functor

Array :: a => [a]

с морфизмом a -> [a]. Функтор просто сопоставляет (ассоциирует) тип a с типом [a] как одно для другого. То, что каждый тип на самом деле представляет собой набор элементов, здесь не имеет никакого отношения. Напротив, морфизм является фактической функцией между этими наборами. Например, существует естественный морфизм (функция)

pure :: a -> [a]
pure = x => [x]

который отправляет значение в массив из 1 элемента с этим значением в виде отдельной записи. Эта функция не является частью Array Functor! С точки зрения этого функтора pure является просто функцией, подобной любой другой, ничего особенной.

С другой стороны, функтор Array имеет вторую часть - часть морфизма. Что отображает морфизм f :: a -> b в морфизм [f] :: [a] -> [b]:

// a -> [a]
Array.map(f) = arr => arr.map(f)

Здесь arr - любой массив произвольной длины со значениями типа a, а arr.map(f) - это массив той же длины со значениями типа b, чьи записи являются результатами применения f to записи arr. Чтобы сделать его функтором, должны выполняться математические законы отображения тождества с идентичностью и композициями в композиции, которые легко проверить в этом примере Array.

Ответ 14

KISS: Функтор - это объект, который имеет метод карты.

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

src: https://www.youtube.com/watch?v=DisD9ftUyCk&feature=youtu.be&t=76

Ответ 15

На практике функтор означает объект, реализующий оператор вызова в С++. В ocaml я думаю, что функтор ссылается на то, что принимает модуль как входной и выводит другой модуль.

Ответ 16

Проще говоря, функтор или объект функции - это объект класса, который может быть вызван как функция.

В С++:

Вот как вы пишете функцию

void foo()
{
    cout << "Hello, world! I'm a function!";
}

Вот как вы пишете функтор

class FunctorClass
{
    public:
    void operator ()
    {
        cout << "Hello, world! I'm a functor!";
    }
};

Теперь вы можете сделать это:

foo(); //result: Hello, World! I'm a function!

FunctorClass bar;
bar(); //result: Hello, World! I'm a functor!

Что делает их настолько прекрасными, так это то, что вы можете сохранить состояние в классе - представьте, хотите ли вы спросить функцию, сколько раз она была вызвана. Нет никакого способа сделать это аккуратным, инкапсулированным способом. С объектом функции он точно так же, как и любой другой класс: у вас будет какая-то переменная экземпляра, которую вы увеличиваете в operator (), и некоторый метод для проверки этой переменной и все, что вам нужно.

Ответ 17

Функтор не связан конкретно с функциональным программированием. Это просто "указатель" на функцию или какой-то объект, который может быть вызван как функция.