我正在努力了解类型替换的工作原理。
请考虑以下示例:
*Lib Lib> :t id (*)
id (*) :: Num a => a -> a -> a
让我们看看id
和(*)
的类型签名:
*Lib Lib> :t (*)
(*) :: Num a => a -> a -> a
*Lib Lib> :t id
id :: a -> a
如何在没有前奏曲的情况下替换id (*)
的类型:
id :: a -> a
(*) :: a -> ( a -> a ) "I did parentheses because of currying.
a
的第一个id
,将通过a -> ( a -> a )
替代
id :: |a | -> a
(*) :: |a -> a -> a|
因为a
也是id
的结果类型(标识为-> a
),因此id
的类型变为a -> a -> a
。
现在考虑更复杂的例子,我将如何进行替换:
*Lib Lib> :t (+) . (*)
.
函数的类型签名:
*Lib Lib> :t (.)
(.) :: (b -> c) -> (a -> b) -> a -> c
现在让我们用(+)
代替第一个参数:
(.) :: (+)
(.) :: (b ->|c) -> (a -> b) -> a -> c
(.) :: (a ->|a -> a) -> (a -> b) -> a -> c
让我们用(*)
代替第二个参数:
(.) :: (+) -> (*)
(.) :: (b ->|c) -> (a ->|b) -> a -> c
(.) :: (a ->|a -> a) -> (a ->|a -> a) -> a -> c
然后逐步替换,直到我们得到最终类型:
(.) :: (b ->|c) -> (a ->|b) -> a -> c
(.) :: (a ->|a -> a) -> (a ->|a -> a) -> a -> c
"the b on the first argument becomes to (a -> a), because
"of the substitution of the final type of second argument
(.) :: (b ->|c ) -> (a ->|b) -> a -> c
(.) :: ((a -> a) ->|a -> a) -> (a ->|a -> a) -> a -> c
"the c, the final type becomes (a -> a), because the result
"type of the first argument
(.) :: (b ->|c ) -> (a ->|b) -> a -> c
(.) :: ((a -> a) ->|a -> a) -> (a ->|a -> a) -> a -> a -> a
等等,我上面提到的最终类型是错误的
(+) . (*) :: a -> a -> a
正确的类型是:
*Lib> :t (+) . (*)
(+) . (*) :: (Num (a -> a), Num a) => a -> (a -> a) -> a -> a
我的问题是,为什么我得到(a -> a)
,合成结尾没有类型参数b
?
为了澄清,我的意思是,让我们将最终的类型参数与函数组合的签名进行比较:
(.) :: (b -> c) -> (a -> b) -> a -> -> c
a -> (a -> a) -> a -> a
我可以看到,a
和c
之间存在漏洞,因为(a -> a)
是b
的类型。
为什么类型参数b
突然出现在a
和c
之间?
我希望这个解释是可以理解的。