我有一个简单的多态数据类型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)’
消失,但我不明白为什么。
为什么这不能编译,我该怎么做才能让这样的东西工作?
答案 0 :(得分:2)
您希望[bar]
具有[forall c . Lens' (Foo c) c]
类型,但它实际上具有forall f c . Functor f => [(c -> f c) -> Foo c -> f (Foo c)]
类型。编译器推断后一种类型的签名,因为它是谓词。您可以在(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
,它声明所有常见镜头类型的新类型,以便您可以在容器中安装镜头。这实际上不会在这个特定的用例中帮助你,因为你也希望c
中的Lens' (Foo c) c
绑定在列表构造函数中,但它通常很有用。