Почему "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:

  1. Типы являются объектами.
  2. Функции - это морфизмы между типами.

Следовательно, все Functor экземпляры в Haskell являются функторами от Hask до Hask (то есть они являются эндофункторами).

Говоря более строго, для всех случаев Functor в Хаскеле:

  1. C = Hask,
  2. D = Hask,

Теперь каждый функтор F является отображением, которое связывает с каждым объектом X ∈ C объект F (X) ∈ D.

  1. Обратите внимание, что X и F (X) являются объектами C и D соответственно.
  2. Поскольку C и D являются Hask, X и F (X) являются типами, а не значениями.
  3. Таким образом, 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 соответственно.

Другие вопросы по тегам