Переменная типа вышла бы за пределы своей области видимости

Я пытаюсь реорганизовать свою функцию, задав ей аргумент объектива (из пакета xml-lens). Я что-то упустил в квантификаторах типов. Что здесь происходит?

*Main> let z name = listToMaybe $ pom ^.. root ./ ell name . text
*Main> :t z
z :: Text -> Maybe Text
*Main> let z name l = listToMaybe $ pom ^.. l ./ ell name . text

<interactive>:13:38:
    Couldn't match expected type ‘(Element -> f Element)
                                  -> Document -> f Document’
                with actual type ‘t’
      because type variable ‘f’ would escape its scope
    This (rigid, skolem) type variable is bound by
      a type expected by the context:
        Applicative f => (Element -> f Element) -> Document -> f Document
      at <interactive>:13:38-57
    Relevant bindings include
      l :: t (bound at <interactive>:13:12)
      z :: Text -> t -> Maybe Text (bound at <interactive>:13:5)
    In the first argument of ‘(./)’, namely ‘l’
    In the second argument of ‘(^..)’, namely ‘l ./ ell name . text’

Что интересно, эта подпись работает.

textFrom :: Text -> Document -> Lens' Document Element -> Maybe Text
textFrom name pom ln = listToMaybe $ pom ^.. ln ./ ell name . text

person sevo    schedule 02.12.2014    source источник
comment
Какую библиотеку объективов вы используете? Какие бывают типы pom, ell, name…? Вы сами написали ./ или используете xml-lens?   -  person Zeta    schedule 02.12.2014
comment
Объективы, которые я использовал здесь, взяты из упаковки xml-lens.   -  person sevo    schedule 02.12.2014


Ответы (1)


Проблема здесь не в линзах или xml-lens напрямую. Это проблема вывода типа более высокого ранга.

Упрощенный тестовый пример

Сначала давайте сделаем минимальный пример, используя проблемный тип из вашего вопроса. В вашем коде вы передаете l функции (./), которая ожидает Traversable; Я заменяю (./) на g и опускаю остальную часть функции.

g :: Traversal s t a b -> String
g = undefined

-- f :: Traversal s t a b -> String
f l = g l

Ошибка:

Couldn't match expected type `(a0 -> f b0) -> s0 -> f t0'
            with actual type `t'
  because type variable `f' would escape its scope
This (rigid, skolem) type variable is bound by
  a type expected by the context:
    Control.Applicative.Applicative f => (a0 -> f b0) -> s0 -> f t0
  at SO27247620.hs:14:7-9
Relevant bindings include
  l :: t (bound at SO27247620.hs:14:3)
  f :: t -> String (bound at SO27247620.hs:14:1)
In the first argument of `g', namely `l'
In the expression: g l

Раскомментирование подписи типа исправляет это, как и в случае с вашей проблемой.

Давайте расширим сигнатуру типа, чтобы понять, почему.

type Traversal s t a b = forall f. Applicative f => (a -> f b) -> s -> f t

f :: (forall f. Applicative f => (a-> f b) -> s -> f t) -> String

Изюминка здесь просто в том, что f имеет тип более высокого ранга, то есть содержит вложенный forall; вам нужно RankNTypes, чтобы написать либо f, либо g.

Вывод типов более высокого ранга

Вывод типа для типов более высокого ранга не всегда возможен. Ваша проблема сводится к тому, что «GHC не может вывести этот тип более высокого ранга»; ответ на это в основном таков: «GHC не обещает, что сможет это сделать».

В частности, одно задокументированное предположение, которое делает GHC в отношении логического вывода и типов более высокого ранга, это из документы GHC 7.8.3:

Для лямбда-связанной или регистрозависимой переменной x либо программист предоставляет явный полиморфный тип для x, либо вывод типа GHC будет предполагать, что тип x не имеет в себе forall.

В нашем примере переменная l привязана к лямбда-выражению и не имеет явного полиморфного типа. Поэтому GHC предполагает, что его тип (который в сообщении об ошибке называется t) не имеет forall. Попытка унифицировать его с forall f. (a0 -> f b0) -> s0 -> f t0 нарушает это предположение.

Бит о том, что переменная типа f выходит за пределы своей области видимости, указывает, что f должен иметь для нее forall.

Кстати, реальный минимальный пример таков:

g' :: (forall a. a) -> b
g' = undefined

f' = \x -> g' x
person Christian Conkle    schedule 04.12.2014
comment
Я изменил лямбду на обычную функцию, исправил эту ошибку! Спасибо! - person Josh.F; 08.05.2017