Линзы могут быть составлены как любая обычная функция. У нас есть:
Lens' a b = forall f . Functor f => (b -> f b) -> a -> f a
Теперь рассмотрим этот пример:
(.) :: Lens' Config Foo -> Lens' Foo String -> Lens' Config String
Расширяя получаем:
(.) :: (forall f. Functor f => (Foo -> f Foo) -> Config -> f Config)
-> (forall f. Functor f => (String -> f String) -> Foo -> f Foo)
-> (forall f. Functor f => (String -> f String) -> Config -> f Config)
И тип функциональной композиции:
(.) :: (b -> c) -> (a -> b) -> (a -> c)
В котором отсутствуют какие-либо универсальные ограничения количественной оценки и класса типов. Теперь мой вопрос: как эти две функции обрабатываются компилятором/проверщиком типов, чтобы оператор композиции функций можно было использовать для составления линз?
Я предполагаю, что нормально иметь функции с универсальной количественной оценкой и ограничениями класса типов, если они соответствуют двум составляемым функциям.
a -> forall x. b
=forall x. a -> b
(еслиx
не упоминается вa
и, возможно, упоминается вb
) иa -> c => b
=c => a -> b
(гдеc
— ограничение). Обратите внимание, что(forall x. a) -> b
, тип ранга 2, нельзя переписать таким образом, потому чтоforall
-квантованный тип появляется в «отрицательной позиции» (слева от функциональной стрелки). - person Jon Purdy   schedule 02.09.2017Lens' X Y -> Lens' Y Z -> Lens' X Z
никогда не будет выведен для(.)
. Этот тип является непредикативным, а GHC нет. поддержка непредикативного полиморфизма. У вас есть ответ, показывающий, что происходит на самом деле; короткая версия заключается в том, что каждый политип преобразуется в монотип при применении функции, если только эта функция явно не принимает политип в качестве аргумента (например, сRankNTypes
). - person user2407038   schedule 03.09.2017