组合函数时,通用量化和类型类约束会发生什么情况?
What happens with universal quantifications and typeclass constraints when composing functions?
镜头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)
缺少任何通用量化和类型类约束。现在我的问题是,compiler/type-checker 如何处理这两个特征,以便函数组合运算符可以用于组合镜头?
我的猜测是,具有通用量化的函数和类型类约束是可以的,只要它们与正在组合的两个函数相匹配。
为什么我们看不到会发生什么?考虑以下值:
(.) :: (b -> c) -> (a -> b) -> a -> c
foo :: Lens' A B
bar :: Lens' B C
foo
和bar
的类型将扩展为:
foo :: Functor f => (B -> f B) -> A -> f A
bar :: Functor g => (C -> g C) -> B -> g B
请注意,我省略了 forall f.
部分,因为它是隐含的。此外,我将 f
的名称更改为 bar
的 g
,以表明它与 foo
的 f
不同。
无论如何,我们首先将 (.)
应用到 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 C
。如您所见,Functor f
与 Functor g
相同,这就是一切正常的原因。
镜头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)
缺少任何通用量化和类型类约束。现在我的问题是,compiler/type-checker 如何处理这两个特征,以便函数组合运算符可以用于组合镜头?
我的猜测是,具有通用量化的函数和类型类约束是可以的,只要它们与正在组合的两个函数相匹配。
为什么我们看不到会发生什么?考虑以下值:
(.) :: (b -> c) -> (a -> b) -> a -> c
foo :: Lens' A B
bar :: Lens' B C
foo
和bar
的类型将扩展为:
foo :: Functor f => (B -> f B) -> A -> f A
bar :: Functor g => (C -> g C) -> B -> g B
请注意,我省略了 forall f.
部分,因为它是隐含的。此外,我将 f
的名称更改为 bar
的 g
,以表明它与 foo
的 f
不同。
无论如何,我们首先将 (.)
应用到 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 C
。如您所见,Functor f
与 Functor g
相同,这就是一切正常的原因。