rank-n 类型和镜头的类型错误

Type error with rank-n types and lenses

我有一个简单的多态数据类型Foo

{-# LANGUAGE TemplateHaskell #-}
import Control.Lens

data Foo c = 
    Foo {
        _bar :: c,
        _baz :: c,
        _quux :: c
    }   

makeLenses ''Foo

生成的镜头当然在 c 中是多态的。 GHCi 的类型是:

*Main> :t bar
bar :: Functor f => (c0 -> f c0) -> Foo c0 -> f (Foo c0)

我制作了一个数据类型 Blah 来环绕镜头。这在简单的情况下效果很好(当然,使用 RankNTypes 扩展名):

data Blah = Blah (forall c . Lens' (Foo c) c)

orange :: Blah
orange = Blah bar

但是稍微复杂一点的都行不通,例如

cheese :: [Blah]
cheese = map Blah [bar]

最后一段代码给出了来自 GHC 的错误:

    Couldn't match type ‘(c0 -> f0 c0) -> Foo c0 -> f0 (Foo c0)’
                  with ‘forall c (f :: * -> *).
                        Functor f =>
                        (c -> f c) -> Foo c -> f (Foo c)’
    Expected type: ((c0 -> f0 c0) -> Foo c0 -> f0 (Foo c0)) -> Blah
      Actual type: (forall c. Lens' (Foo c) c) -> Blah
    In the first argument of ‘map’, namely ‘Blah’
    In the expression: map Blah [bar]

forall c f . 似乎从 ‘(c0 -> f0 c0) -> Foo c0 -> f0 (Foo c0)’ 中消失了,但我不明白为什么。

为什么这不能编译,我该怎么做才能让这样的东西工作?

您希望 [bar] 具有类型 [forall c . Lens' (Foo c) c],但它实际上具有类型 forall f c . Functor f => [(c -> f c) -> Foo c -> f (Foo c)]。编译器推断后一种类型签名,因为它是 predicative。您可以在 (im) 预测类型的技术细节上找到 resources。简而言之,在存在不可预测类型的情况下,类型推断是不可判定的——所以类型签名成为强制性的——所以默认情况下它们是不允许的。预测类型是 forall 出现在类型构造函数中的类型(如 [])。

您可以强制 [bar] 使用前一种类型,只需指定该类型签名并启用 ImpredicativeTypesmap Blah 也是如此 - 它也有一个不可预测的类型,因此您还需要手动指定它。

bar' :: [forall c . Lens' (Foo c) c]
bar' = [bar] 

mapBlah :: [forall c . Lens' (Foo c) c] -> [Blah]
mapBlah = map Blah 

然后进行以下类型检查:

> mapBlah bar'

甚至

> (map Blah :: [forall c . Lens' (Foo c) c] -> [Blah]) 
    ([bar] :: [forall c . Lens' (Foo c) c])

事实上,处理不可预测类型的问题,lens 包含模块 Control.Lens.Reified,它为所有常见镜头类型声明新类型,以便您可以在容器中放置镜头。在这个特定的用例中,这实际上对您没有帮助,因为您还希望 Lens' (Foo c) c 中的 c 绑定在列表构造函数内,但它通常很有用。