19

我试图通过给它一个镜头参数(来自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
4

1 回答 1

14

这里的问题不在于镜头或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编写fg

推断更高等级的类型

较高等级类型的类型推断并非总是可行的。您的问题归结为“GHC 无法推断出这种更高级别的类型”;对此的回答基本上是“GHC 不承诺它可以这样做”。

具体来说,来自GHC 7.8.3 文档的 GHC 关于推理和更高级别类型的一个记录假设是这样的:

对于 lambda-bound 或 case-bound 变量 x,程序员要么为 x 提供显式的多态类型,要么 GHC 的类型推断将假定 x 的类型中没有 foralls。

在我们的示例中,变量l是 lambda-bound,并且它没有显式的多态类型。因此 GHC 假定它的类型(错误消息称为t)没有 foralls。试图将其统一起来forall f. (a0 -> f b0) -> s0 -> f t0违反了这一假设。

关于类型变量f逃逸其范围的位表明f需要对其进行处理。

顺便说一句,真正的最小示例是这样的:

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

f' = \x -> g' x
于 2014-12-04T19:00:21.363 回答