在Haskell中查找组合函数的类型
假设我在 Haskell 中有以下功能:
compose2 = (.) . (.)
我将如何找到这个函数的类型?由于有多种组合,我在试图确定此函数的类型时遇到困难。
我知道我可以:t compose2
用来获取类型。但是,我想知道如何在没有计算机帮助的情况下做到这一点。我应该采取哪些步骤来查找类型?
回答
如果我们给组合函数一个更唯一的标识符可能会有所帮助,例如:
compose2 = (.)2 .1 (.)3
这样更容易引用一些函数。我们还可以将其转换为更规范的形式,例如:
compose2 = ((.)1 (.)2) (.)3
所以现在我们可以开始推导函数类型了。我们知道(.)
有类型(.) :: (b -> c) -> (a -> b) -> a -> c
,或者更规范的(.) :: (b -> c) -> ((a -> b) -> (a -> c))
。由于类型变量不是“全局的”,因此我们可以为类型变量赋予树函数不同的名称:
(.)1 :: (b -> c) -> ((a -> b) -> (a -> c))
(.)2 :: (e -> f) -> ((d -> e) -> (d -> f))
(.)3 :: (h -> i) -> ((g -> h) -> (g -> i))
既然我们已经给了不同的组合函数一个签名,我们就可以开始推导类型了。
我们知道是一个函数应用的参数 with ,所以这意味着参数的类型与类型相同,因此, 和。(.)2
(.)1
(b -> c)
(e -> f) -> ((d -> e) -> (d -> f))
b ~ (e -> f)
c ~ ((d -> e) -> (d -> f))
我们furtermore知道的“第二”参数的类型相同的类型,所以,因此,和,因此“回归型”的,这是因此可以专门用于:(.)1
(.)3
(a -> b) ~ ((h -> i) -> ((g -> h) -> (g -> i)))
a ~ (h -> i)
b ~ ((g -> h) -> (g -> i))
(.)1
(a -> c)
((.)1 (.)2) (.)3 :: a -> c
并且因为a ~ (h -> i)
,并且c ~ (d -> e) -> (d -> f)
:
((.)1 (.)2) (.)3 :: (h -> i) -> ((d -> > e) -> (d > f))
我们知道这b
等同于b ~ (e -> f)
and b ~ ((g -> h) -> (g -> i))
,所以这意味着e ~ (g -> h)
, and f ~ (g -> i)
,因此我们可以进一步将签名特化为:
((.)1 (.)2) (.)3 :: (h -> i) -> ((d -> (g -> h)) -> (d -> (g -> i)))
这是一种更详细的形式:
(.)2 .1 (.)3 :: (h -> i) -> (d -> g -> h) -> d -> g -> i
如果我们自动派生类型,我们将获得:
Prelude> :t (.) . (.)
(.) . (.) :: (b -> c) -> (a1 -> a -> b) -> a1 -> a -> c
如果我们这样替换b
用h
,c
用i
,a1
用d
而a
用g
,我们得到了相同的类型。
- Thank you very much for this comprehensive answer! I am able to get the type myself now 🙂