zic*_*liu 5 haskell type-inference
为什么类型(+).(+)IS (Num a, Num (a -> a)) => a -> (a -> a) -> a -> a?
(+) :: Num a => a -> a -> a
(.) :: (b -> c) -> (a -> b) -> a -> c
Run Code Online (Sandbox Code Playgroud)
我曾尝试过,但不知道结果如何(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
Run Code Online (Sandbox Code Playgroud)
有人可以帮忙给我分析步骤吗?
另一种方法:
((+).(+)) x y z
= (+) ((+) x) y z
= ((x +) + y) z
Run Code Online (Sandbox Code Playgroud)
现在注意:
(x +) + y
Run Code Online (Sandbox Code Playgroud)
是两个函数的和,因为自变量之一是一个函数。让我们假设,x :: a因为我们必须从某个地方开始(这个假设不一定意味着a将出现在最终类型中,我们只是想给它起一个名字就可以开始我们的推理过程)
x :: a
Run Code Online (Sandbox Code Playgroud)
然后
(x +) :: a -> a
y :: a -> a -- since the operands of + have to be the same type
Run Code Online (Sandbox Code Playgroud)
此外,我们正在增加x在(x +)这给了我们Num a,我们也加入这给我们的功能Num (a -> a) (在这一点上,这基本上是一个错误,因为没有理智的人定义的一个实例Num的功能-这是可能的,但它是一个坏主意) 。
无论如何,我们刚刚分析的表达式是type的两个事物的总和a -> a,因此结果也必须是type a -> a。
((x +) + y) z -- since the result of + has to have the same type
^^^^^^^^^^^ -- as its operands
a -> a
Run Code Online (Sandbox Code Playgroud)
因此,z :: a。
所以最后整个表达式都被输入了
(+).(+) :: a -> (a -> a) -> a -> a
^ ^^^^^^^^ ^ ^
x y z final result
Run Code Online (Sandbox Code Playgroud)
加上我们在此过程中遇到的限制。
我的解释中倾向于使用更多的单词,而使用的公式则更少-如果这没有帮助,则表示歉意,但是其他答案让我有些不满意,因此我认为我的解释方式会稍有不同。
显然,您已经对各个部分的功能有所了解。特别是(.)需要两个函数,并给出一个函数,该函数首先将其右边的函数应用于参数,然后将其左边的函数应用于结果。
因此,我们将从右侧的功能开始:(+)。它具有类型(Num a) => a -> a -> a-也就是说,它接受两个参数,这些参数必须是相同的类型,并且该类型必须是的实例Num。然后,它返回相同类型的值。
回想一下,由于curring,它等效于(Num a) => a -> (a -> a)。也就是说,它接受的实例Num,然后将相同类型的函数返回给自身。
现在,我们必须使用另一种函数来组合它-该函数以其结果类型作为输入。那其他功能是什么?这是(+)又来了!但是我们知道,为了对组合进行类型检查,我们必须向其提供一个函数类型:(a -> a其中a是的一个实例Num)。正如我们已经看到的那样,这不是问题,因为(+)可以接受作为实例的任何类型Num。a -> a当我们有适当的实例时,可以包括。这就解释了为什么最终类型具有2个约束Num a和Num (a -> a)。
现在很容易将所有内容放在一起。摆脱约束(我们已经处理过),我们示意性地具有:
(+) . (+)
(a -> a) -> ((a -> a) -> (a -> a)) a -> (a -> a)
Run Code Online (Sandbox Code Playgroud)
因此,在(.)我将写为的类型签名中,(c -> d) -> (b -> c) -> (b -> d)我们有aas b,a -> aas c和(a -> a) -> (a -> a)as d。代入这些,我们得到的最终类型(b -> d)为:
a -> ((a -> a) -> (a -> a))
Run Code Online (Sandbox Code Playgroud)
我们可以重写为
a -> (a -> a) -> a -> a
Run Code Online (Sandbox Code Playgroud)
在回忆起功能箭头是右相关的之后,通过删除不必要的括号。