在编写函数时,通用量化和类型类约束会发生什么?

时间:2017-09-02 03:30:05

标签: haskell lenses rank-n-types

镜头can be composed就像任何普通的功能一样。我们有:

Lens' a b = forall f . Functor f => (b -> f b) -> a -> f a

现在考虑这个例子:

(.) :: Lens' Config Foo -> Lens' Foo String -> Lens' Config String

扩展我们得到:

(.) :: (forall f. Functor f => (Foo -> f Foo) -> Config -> f Config)
    -> (forall f. Functor f => (String -> f String) -> Foo -> f Foo)
    -> (forall f. Functor f => (String -> f String) -> Config -> f Config)

功能组合的类型是:

(.) :: (b -> c) -> (a -> b) -> (a -> c)

缺少任何通用量化和类型类约束。现在我的问题是,编译器/类型检查器如何处理这两个功能,以便功能组合操作符可用于组合镜头?

我的猜测是,可以通过普遍量化的函数和类型类约束,只要它们与正在组合的两个函数匹配。

1 个答案:

答案 0 :(得分:3)

为什么我们不知道会发生什么?请考虑以下值:

(.) :: (b -> c) -> (a -> b) -> a -> c

foo :: Lens' A B

bar :: Lens' B C

foobar的类型将扩展为:

foo :: Functor f => (B -> f B) -> A -> f A

bar :: Functor g => (C -> g C) -> B -> g B

请注意,我遗漏了forall f.部分,因为它是隐含的。另外,我将f的名称更改为g bar,以表明它与f的{​​{1}}不同。

无论如何,我们首先将foo应用于(.)

foo

因此,(.) :: (b -> c) -> (a -> b) -> a -> c | | | | | | -------- -------- | | | | | | | | | | | | foo :: Functor f => (B -> f B) -> A -> f A | -------- | -------- | | | | | | (.) foo :: Functor f => (a -> B -> f B) -> a -> A -> f A 的类型为(.) foo。如您所见,Functor f => (a -> B -> f B) -> a -> A -> f A约束只是按原样复制。

现在,我们将Functor应用于(.) foo

bar

因此,(.) foo :: Functor f => (a -> B -> f B) -> a -> A -> f A | | | | | | | | | | -------- | | | | | | | | | | | | | | | | | bar :: Functor g => (C -> g C) -> B -> g B -------- | | | | | | | | (.) foo bar :: Functor g => (C -> g C) -> A -> g A 的类型为(.) foo bar,这意味着它是Functor g => (C -> g C) -> A -> g A。正如您所看到的,Lens' A CFunctor f相同,这就是为什么一切顺利的原因。