fmap
на самом деле семейство морфизмов.Морфизм в Hask всегда от конкретного типа к другому конкретному типу.Вы можете думать о функции как о морфизме, если функция имеет конкретный тип аргумента и конкретный тип возвращаемого значения.Функция типа Int -> Int
представляет морфизм (действительно, эндоморфизм) от Int
до Int
в Hask .fmap
, однако имеет тип Functor f => (a -> b) -> f a -> f b
.Не конкретный вид в поле зрения!У нас просто есть переменные типа и квазиоператор =>
для работы.
Рассмотрим следующий набор конкретных типов функций.
Int -> Int
Char -> Int
Int -> Char
Char -> Char
Далее рассмотрим следующие конструкторы типов
[]
Maybe
[]
, примененный к Int
, возвращает тип, который мы можем назвать List-of-Ints
, но мы обычно просто вызываем [Int]
.(Одна из самых запутанных вещей в функторах, когда я начинал, заключалась в том, что у нас просто нет отдельных имен для ссылки на типы, которые создают различные конструкторы типов; вывод просто именуется выражением, которое его оценивает.) Maybe Int
возвращает тип, который мы только что назвали, ну, Maybe Int
.
Теперь мы можем определить набор функций, подобных следующему
fmap_int_int_list :: (Int -> Int) -> [Int] -> [Int]
fmap_int_char_list :: (Int -> Char) -> [Int] -> [Char]
fmap_char_int_list :: (Char -> Int) -> [Char] -> [Int]
fmap_char_char_list :: (Char -> Char) -> [Char] -> [Char]
fmap_int_int_maybe :: (Int -> Int) -> Maybe Int -> Maybe Int
fmap_int_char_maybe :: (Int -> Char) -> Maybe Int -> Maybe Char
fmap_char_int_maybe:: (Char -> Int) -> Maybe Char -> Maybe Int
fmap_char_char_maybe :: (Char -> Char) -> Maybe Char -> Maybe Char
Каждая из них представляет собой отдельный морфизм в Hask , но когда мы определяем их в Haskell, много повторений.
fmap_int_int_list f xs = map f xs
fmap_int_char_list f xs = map f xs
fmap_char_int_list f xs = map f xs
fmap_char_char_list f xs = map f xs
fmap_int_int_maybe f x = case x of Nothing -> Nothing; Just y -> Just (f y)
fmap_int_char_maybe f x = case x of Nothing -> Nothing; Just y -> Just (f y)
fmap_char_int_maybe f x = case x of Nothing -> Nothing; Just y -> Just (f y)
fmap_char_char_maybe f x = case x of Nothing -> Nothing; Just y -> Just (f y)
Определения не отличаются, когда тип f
отличается, только когда типx
/ xs
отличается.Это означает, что мы можем определить следующие полиморфные функции
fmap_a_b_list f xs = map f xs
fmap_a_b_maybe f x = case x of Nothing -> Nothing; Just y -> Just (f y)
, каждая из которых представляет набор морфизмов в Hask .
fmap
сам по себе является общим термином, который мы используем для обозначения специфических для конструктора морфизмов, на которые ссылаются все полиморфные функции.
С этим путем мы можем лучше понять fmap :: Functor f => (a -> b) -> f a -> f b
.
Учитываяfmap f
, мы сначала посмотрим на тип f
.Например, мы можем узнать, что f :: Int -> Int
, что означает, что fmap f
должен вернуть один из fmap_int_int_list
или fmap_int_int_maybe
, но мы еще не уверены, какой именно.Поэтому вместо этого он возвращает ограниченную функцию типа Functor f => (Int -> Int) -> f Int -> f Int
.Как только эта функция будет применена к значению типа [Int]
или Maybe Int
, у нас, наконец, будет достаточно информации, чтобы узнать, какой морфизм на самом деле имеется в виду.