Haskell 如何推断 (+).(+) 的类型 [英] How does Haskell infer the type of (+).(+)
问题描述
为什么(+).(+)
的类型是(Num a, Num (a -> a)) =>->(a -> a) ->->
?
(+) :: Num a => a -> a -> a
(.) :: (b -> c) -> (a -> b) -> a -> c
我试过了,但不知道结果如何 (Num a, Num (a -> a)) =>->(a -> a) ->->一个
.
I tried but didn't know how to turn out (Num a, Num (a -> a)) => a -> (a -> a) -> a -> a
.
(+) :: Num i => i -> i -> i
(.) :: (b -> c) -> (a -> b) -> (a -> c)
(+) :: Num j => j -> j -> j
(+) . (+) :: (i -> (i -> i)) -> ((j -> j) -> i) -> ((j -> j) -> (i -> i))
where:
b = i
c = i -> i
a = j -> j
有人可以帮忙给我分析步骤吗?
Could someone help and give me analysis steps?
推荐答案
我的解释往往有更多的词和更少的公式 - 如果这没有帮助,我很抱歉,但我对其他答案有点不满意,所以我我想我会用稍微不同的方式解释它.
My explanations tend to have more words and fewer formulae - apologies if this isn't helpful, but I'm left a little unsatisfied by the other answers so I thought I'd explain it in a slightly different way.
很明显,您已经对各个部分的作用有了很好的了解.让我们关注函数组合运算符 .
.它接受两个函数,并返回新函数,该函数首先将 .
右侧的函数应用于参数,然后将 .
左侧的函数应用于结果
Clearly you already have a good idea of what the various parts do. Let's focus on the function composition operator .
. It takes two functions, and returns the new function which first applies the function on the right of .
to the argument, then applies the function on the left of .
to the result of that.
所以在(+).(+)
中,我们将从右侧的函数开始.
:(+)
.这具有类型 (Num a) =>->->a
- 也就是说,它需要两个必须是相同类型的参数,并且该类型必须是 Num
的实例.然后它返回一个相同类型的值.
So in (+).(+)
we'll start with the function on the right of .
: (+)
. This has type (Num a) => a -> a -> a
- that is, it takes two arguments which must be the same type, and that type must be an instance of Num
. And then it returns a value of the same type.
回想一下,由于柯里化,这等价于 (Num a) =>->(a -> a)
.也就是说,它接受一个 Num
的实例,并返回一个从相同类型到相同类型的函数.
Recall that, because of currying, this is equivalent to (Num a) => a -> (a -> a)
. That is, it takes an instance of Num
, and returns a function from that same type to that same type.
现在我们必须将它与另一个函数组合起来——一个将其结果类型作为输入的函数.那另一个功能是什么?又是(+)
!但是我们知道,为了对组合进行类型检查,我们必须为其提供函数类型:a ->a
(其中 a
是 Num
的一个实例).正如我们已经看到的,这不是问题,因为 (+)
可以采用 Num
实例的任何类型.这可以包括 a ->a
,当我们有合适的实例时.这解释了为什么最终类型具有 2 个约束 Num a
和 Num (a -> a)
.
Now we must compose it with another function - one that takes its result type as input. What is that other function? It's (+)
again! But we know that, in order for the composition to type-check, we must feed it that function type: a -> a
(where a
is an instance of Num
). As we already saw, this isn't a problem, as (+)
can take any type that is an instance of Num
. That can include a -> a
, when we have the appropriate instance. And this explains why the final type has the 2 constraints Num a
and Num (a -> a)
.
现在很容易把所有东西放在一起.撇开约束(我们已经处理过),我们示意性地有:
Now it's easy to put everything together. Leaving off the constraints (which we've already dealt with), we schematically have:
(+) . (+)
(a -> a) -> ((a -> a) -> (a -> a)) a -> (a -> a)
所以在 (.)
的类型签名中,我将其写为 (c -> d) ->(b -> c) ->(b -> d)
, 我们有 a
作为 b
, a ->a
为 c
,并且 (a -> a) ->(a -> a)
为 d
.将这些代入,我们得到最终类型 (b -> d
) 为:
So in the type signature of (.)
, which I'll write as (c -> d) -> (b -> c) -> (b -> d)
, we have a
as b
, a -> a
as c
, and (a -> a) -> (a -> a)
as d
. Substituting these in, we get the final type (b -> d
) as:
a -> ((a -> a) -> (a -> a))
我们可以重写为
a -> (a -> a) -> a -> a
通过删除不必要的括号,在回忆起函数箭头是右结合的之后.
by removing unnecessary parentheses, after recalling that function arrows are right-associative.
这篇关于Haskell 如何推断 (+).(+) 的类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!