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]
使用前一种类型,只需指定该类型签名并启用 ImpredicativeTypes
。 map 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
绑定在列表构造函数内,但它通常很有用。
我有一个简单的多态数据类型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]
使用前一种类型,只需指定该类型签名并启用 ImpredicativeTypes
。 map 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
绑定在列表构造函数内,但它通常很有用。