Haskell 如何推断 (+).(+) 的类型 [英] How does Haskell infer the type of (+).(+)

查看:35
本文介绍了Haskell 如何推断 (+).(+) 的类型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

为什么(+).(+)的类型是(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(其中 aNum 的一个实例).正如我们已经看到的,这不是问题,因为 (+) 可以采用 Num 实例的任何类型.这可以包括 a ->a,当我们有合适的实例时.这解释了为什么最终类型具有 2 个约束 Num aNum (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 ->ac,并且 (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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆