Почему "pure" требуется только для Applicative, а не для Functor?
Читая этот Wikibook об основах теории Хаскелла и теории категорий, я узнаю о функторах:
Функтор по сути является преобразованием между категориями, поэтому для заданных категорий C и D функтор F: C -> D
сопоставляет любой объект A в C с F(A) в D.
отображает морфизмы f: A -> B в C на F(f): F(A) -> F(B) в D.
... что звучит все хорошо. Позже приведен пример:
Давайте также рассмотрим пример:
instance Functor Maybe where
fmap f (Just x) = Just (f x)
fmap _ Nothing = Nothing
Вот ключевая часть: конструктор типов Maybe переносит любой тип T в новый тип, Maybe T. Кроме того, fmap, ограниченный типом Maybe, переводит функцию a -> b в функцию Maybe a -> Maybe b. Но это все! Мы определили две части: что-то, что переводит объекты в Hask в объекты в другой категории (в типах Maybe и функциях, определенных в типах Maybe), и то, что переводит морфизмы в Hask в морфизмы в этой категории. Так что, возможно, это функтор.
Я понимаю, как определение fmap
это ключ. Я запутался в том, как "конструктор типов Maybe" предоставляет первую часть. Я бы предпочел что-то вроде pure
,
Если я правильно понял, Maybe
скорее карты C
в D
, (Таким образом, это морфизм на уровне категории, который может быть требованием для Функтора)
Я думаю, вы могли бы перефразировать мой вопрос следующим образом: есть ли Functor, который не имеет очевидной реализации pure
?
4 ответа
Я думаю, что вы путаетесь между типами и значениями. Вот определение функтора:
Пусть C и D категории. Функтор F от C до D - это отображение, которое:
- сопоставляет каждому объекту X ∈ C объект F (X) ∈ D.
сопоставляет каждому морфизму f: X → Y ∈ C морфизм F(f): F(X) → F(Y) ∈ D, так что выполняются следующие условия:
- F (id: X → X) = id: F (X) → F (X) для каждого объекта X ∈ C.
- F (g ∘ f) = F (g) ∘ F (f) для всех морфизмов f: X → Y и g: Y → Z.
Категория состоит из объектов и морфизмов между объектами.
Весь код в Haskell является частью Hask, категории Haskell. В Hask:
- Типы являются объектами.
- Функции - это морфизмы между типами.
Следовательно, все Functor
экземпляры в Haskell являются функторами от Hask до Hask (то есть они являются эндофункторами).
Говоря более строго, для всех случаев Functor
в Хаскеле:
C = Hask
,D = Hask
,
Теперь каждый функтор F является отображением, которое связывает с каждым объектом X ∈ C объект F (X) ∈ D.
- Обратите внимание, что X и F (X) являются объектами C и D соответственно.
- Поскольку C и D являются Hask, X и F (X) являются типами, а не значениями.
- Таким образом, F: Тип → Тип или в Хаскеле
f : * -> *
,
Действительно, именно так Functor
Тип класса определен в Haskell:
class Functor (f : * -> *) where
fmap :: (x -> y) -> (f x -> f y)
Вот, fmap
это вторая часть функтора. Это функция от значений к значениям. Тем не менее Functor
сам по себе является конструктором типов (то есть отображением типов в типы). Это причина Maybe
является функтором и []
это функтор, но Maybe Int
а также [Int]
не функторы.
Обратите внимание, что pure
не формирует первую часть определения функтора, потому что это отображение из экземпляра X в экземпляр F (X) (то есть это функция от значений к значениям). Однако нам нужно отображение из X в F (X) (то есть отображение из типов в типы).
Если я правильно понял,
Maybe
скорее картыC
вD
, (Таким образом, это морфизм на уровне категории, который может быть требованием для Функтора)
Не совсем, как C
а также D
Есть категории, а не типы Haskell. Functor
(то есть экземпляр класса типа, в отличие от функтора в целом) представляет собой отображение из категории Hask (категория типов и функций Haskell) на сам Hask; то есть, C
а также D
оба Хаск в этом случае. В главе Wikibook упоминается, что в разделе Функторы на Hask. В вашем примере Maybe
Конструктор типов обеспечивает первую часть отображения, принимая некоторый тип a
(объект в Hask) к типу Maybe a
(еще один объект в Hask).
Я думаю, вы могли бы перефразировать мой вопрос следующим образом: есть ли
Functor
что не имеет очевидной реализацииpure
?
Одним из примеров является пара Functor
, (,) a
, fmap
легко написать - \f (x, y) -> (x, f y)
-- но pure
а также (<*>)
требовать Monoid
ограничение на a
, так как не было бы никакого способа справиться с дополнительным a
значения в противном случае. Для более подробного обсуждения и других примеров см. Хорошие примеры Не Функтор / Функтор /Applicative/Monad?
Я бы сказал, что Applicative
Экземпляр рода становится отрезком для Either
(что я был бы прекрасно с просто иметь экземпляр для Bifunctor
, но с другой стороны использовать его как монаду удобно), и (ИМХО) было бы неуместно для чего-то вроде:
data ABC a = A a | B a | C a
Где все A,B,C "одинаково хорошо". Поскольку нет очевидного выбора, для которого следует использовать pure
, это не должно быть предоставлено вообще. имеющий fmap
все еще отлично, хотя.
Категория Hask имеет типы в качестве объектов и функции в виде стрелок, поэтому сопоставление объектов, предоставляемое экземпляром Functor, должно сопоставлять типы с типами.
fmap
отображает стрелки, т.е. отображает функции a -> b
к функциям f a -> f b
для функтора ф. Конструктор типа Functor - это отображение объектов, то есть между типами.
Например, Maybe
конструктор типа отображает тип t
к типу Maybe t
например String
в Maybe String
,
По сравнению, pure
отображает значения некоторого базового типа на значение соответствующего аппликативного типа, например, "abc" и (Just "abc") оба являются значениями String
а также Maybe String
соответственно.