В функциональном программировании функтор — это шаблон проектирования , вдохновленный определением из теории категорий , который позволяет применять функцию к значениям внутри универсального типа , не изменяя структуру универсального типа. В Haskell эта идея может быть отражена в классе типа :
класс Функтор f , где fmap :: ( a -> b ) -> f a -> f b
В этом объявлении говорится, что любой тип Functor должен поддерживать метод fmap
, который сопоставляет функцию с элементом(ами) Functor.
Функторы в Haskell также должны подчиняться законам функторов [1] , которые гласят, что операция отображения сохраняет функцию тождества и композицию функций:
fmap id = id fmap ( g . h ) = ( fmap g ) . ( fmap h )
(где .
обозначает композицию функций ).
В Scala можно использовать трейт :
черта Функтор [ F [ _ ]] { def map [ A , B ]( a : F [ A ])( f : A => B ): F [ B ] }
Функторы формируют основу для более сложных абстракций, таких как Applicative Functor , Monad и Comonad , все из которых строятся поверх канонической структуры функтора. Функторы полезны при моделировании функциональных эффектов с помощью значений параметризованных типов данных. Изменяемые вычисления моделируются путем применения чистой функции к значениям «внутреннего» типа, тем самым создавая новое общее значение, представляющее измененное вычисление (которое, возможно, еще не запущено).
В Haskell списки являются простым примером функтора. Мы можем реализовать fmap
как
fmap f [] = [] fmap f ( x : xs ) = ( f x ) : fmap f xs
Бинарное дерево можно аналогичным образом описать как функтор:
данные Дерево a = Лист | Узел a ( Дерево a ) ( Дерево a ) экземпляр Дерево функторов , где fmap f Лист = Лист fmap f ( Узел x l r ) = Узел ( f x ) ( fmap f l ) ( fmap f r )
Если у нас есть бинарное дерево tr :: Tree a
и функция f :: a -> b
, то функция fmap f tr
будет применяться f
к каждому элементу tr
. Например, если a
есть Int
, добавление 1 к каждому элементу tr
может быть выражено как fmap (+ 1) tr
. [2]