Где функтор в естественном преобразовании?

У меня возник этот вопрос в глубине души с тех пор, как я увидел определение естественных преобразований в старом пакете дополнительных категорий Эдварда Кметта:

-- | A natural transformation between functors f and g.
type f :~> g = forall a. f a -> g a

Но теперь, читая сообщение в блоге Стивена Дила о дополнениях, я нахожу следующее:

Естественным преобразованием в нашем контексте будет полиморфная функция, связанная с двумя экземплярами функтора Haskell f и g с сигнатурой типа (Functor f, Functor g) => forall a. ж а -> г а. Что можно было бы записать с помощью следующего синонима типа.

type Nat f g = forall a. f a -> g a

Это было пощечиной моему отношению «я продолжу игнорировать это». Итак, на вопрос: почему можно внезапно отказаться от ограничений функтора?


person user2141650    schedule 18.02.2014    source источник
comment
Когда вы используете Nat, вы будете предоставлять типы. Сам по себе синоним типа не использует того факта, что они являются функторами. Только когда вы его используете, это имеет значение, если в этом есть смысл.   -  person David Young    schedule 18.02.2014
comment
Хмммм. forall сам по себе уменьшает количество неестественных функций преобразования, которые вы можете определить, даже если рассматриваемые функторы изначально не очевидны / не бросаются в глаза.   -  person AndrewC    schedule 18.02.2014
comment
Прочтите превосходный Вы могли бы определить естественные преобразования для лучшего объяснения взаимосвязи между полиморфизмом и естественными преобразованиями.   -  person AndrewC    schedule 18.02.2014
comment
Я не совсем понимаю ваш первый комментарий, даже после прочтения связанной статьи. Конечно, f и g должны быть полиморфными, но это не то же самое, что быть функтором. Что мне не хватает? И спасибо за ссылку; быстрое прочтение не развеяло мои сомнения, но оно действительно кажется очень интересным.   -  person user2141650    schedule 18.02.2014
comment
@ user2141650 На самом деле f и g не обязательно должны быть полиморфными (если вы говорите о конкретном естественном преобразовании). Например, мы можем говорить о естественном преобразовании safeHead :: Nat [] Maybe. a должен быть полиморфным и универсальным, чтобы быть естественным.   -  person David Young    schedule 19.02.2014
comment
Кроме того, не накладывая ограничения Functor на синоним, мы избегаем помещения ограничений Functor там, где они нам не нужны, но мы все еще можем иметь их там, где они нам нужны. Например, у вас может быть функция, которая отображает естественное преобразование как на вход, так и на выход какого-либо процесса (например, другой функции в этом примере) natPromap :: Nat f g -> (g a -> f b) -> (f a -> g b). Таким образом, нам нужно установить ограничение Functor только тогда, когда мы действительно используем fmap.   -  person David Young    schedule 19.02.2014
comment
@DavidYoung Я имел в виду, что функции fg) должны быть полиморфными, т.е. принимать любые a, а не то, что Nat должно быть. Я думаю, мы просто по-другому используем нашу терминологию.   -  person user2141650    schedule 19.02.2014
comment
Я подумал о другой возможной причине: не все функторы Haskell могут быть экземплярами класса типа Functor. Некоторые Contravariant экземпляры, например   -  person David Young    schedule 22.02.2014
comment
@ user2141650 Извините, я не ответил ранее. (Если бы вы поместили @AndrewC, я бы получил уведомление.) Это естественное преобразование iself, которое должно быть полностью полиморфной функцией (таким образом, forall), а не f и g.   -  person AndrewC    schedule 22.02.2014
comment
@ user2141650 Математическое определение естественного преобразования - это функция eta_A из F (A) в G (A) для каждого объекта A категории, так что если мы возьмем любую функцию h: A- ›B, eta_B.F (h ) = G (h) .eta_A. Эквивалент haskell eta_A для каждого объекта - это полиморфная функция eta :: F a -> G a, а условие становится условием для любой функции h::a->b, eta.fmap h = fmap h.eta. С типами это (eta::F b -> G b) . ((fmap h)::F a -> F b) = ((fmap h)::G a -> G b) . (eta::F a -> G a). Это условие any строго ограничивает, какие функции могут представлять преобразования, согласно статье.   -  person AndrewC    schedule 22.02.2014


Ответы (1)


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

person Tarmil    schedule 18.02.2014
comment
Разве это не относится только к data типам, но не к синонимам типов? А как насчет синонимов типа линзы, например? - person David Young; 18.02.2014
comment
На самом деле, теперь, когда я думаю об этом, типы линз немного отличаются, потому что переменные типа Functor универсально количественно определены. Я все еще подозреваю, что устаревание, о котором вы говорите, относится только к data типам (возможно, newtype также). - person David Young; 18.02.2014
comment
У меня это отлично работает, если я включу RankNTypes и TypeOperators: type f :-> g = forall x . (Functor f) => f x -> g x - person Gabriel Gonzalez; 18.02.2014
comment
@Tarmil Я думаю, что вы правы (как и Дэвид Янг в своих комментариях к вопросу, если я правильно его понимаю). Например, test3 natt fn pt = natt $ fmap fn pt, где test3 :: (f :-> g) -> (a -> b) -> f a -> g b и (:->) соответствует определению Габриэля выше, не проверяется типом, потому что по-прежнему требуется ограничение Functor f. Таким образом, ситуация с синонимами типов с ограничениями фактически аналогична ситуации с DatatypeContexts, за исключением того, что похоже, что они не по какой-то причине устарели и даже не требуют расширения! - person user2141650; 19.02.2014