为什么(+).(+)
的类型是(Num a, Num (a -> a)) => a -> (a -> a) -> a -> a
?
(+) :: Num a => a -> a -> a
(.) :: (b -> c) -> (a -> b) -> a -> c
我尝试过,但不知道如何得出(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
有人可以帮我分析一下步骤吗?
答案 0 :(得分:6)
另一种方法:
((+).(+)) x y z
= (+) ((+) x) y z
= ((x +) + y) z
现在注意:
(x +) + y
是两个函数的和,因为参数之一是一个函数。让我们假设x :: a
是因为我们必须从某个地方开始(这个假设并不一定意味着a
会出现在最终类型中,我们只是想给它起一个名字就可以开始我们的推理过程)>
x :: a
然后
(x +) :: a -> a
y :: a -> a -- since the operands of + have to be the same type
此外,我们在x
中添加(x +)
,这给了我们Num a
,并且我们添加了给我们Num (a -> a)
的函数(目前,这实际上是一个错误,因为没有理智的人为函数定义Num
的实例-可能,但这是个坏主意。
无论如何,我们刚才分析的表达式是a -> a
类型的两件事的总和,所以结果也必须是a -> a
类型的。
((x +) + y) z -- since the result of + has to have the same type
^^^^^^^^^^^ -- as its operands
a -> a
因此,z :: a
。
所以最终整个表达式都被键入
(+).(+) :: a -> (a -> a) -> a -> a
^ ^^^^^^^^ ^ ^
x y z final result
加上我们在此过程中遇到的限制。
答案 1 :(得分:6)
我的解释中倾向于使用更多的单词,而使用的公式则更少-如果这没有帮助,则表示歉意,但是其他答案让我有些不满意,因此我认为我的解释方式会有所不同。
很显然,您已经对各个部分的功能有所了解。特别是(.)
接受两个函数,并给出一个函数,该函数首先将其右边的函数应用于参数,然后将其左边的函数应用于结果。
因此,我们将从右侧的功能开始:(+)
。它的类型为(Num a) => a -> a -> a
-也就是说,它接受两个必须为相同类型的参数,并且该类型必须为Num
的实例。然后返回相同类型的值。
回想一下,由于存在咖喱,这等效于(Num a) => a -> (a -> a)
。也就是说,它接受Num
的实例,并从相同类型返回一个函数给它自己。
现在,我们必须用另一个函数来组合它-以其结果类型作为输入的函数。那其他功能是什么?又是(+)
!但是我们知道,为了对组合进行类型检查,我们必须向其提供函数类型:a -> a
(其中a
是Num
的实例)。正如我们已经看到的那样,这不是问题,因为(+)
可以采用 Num
实例的任何类型。当我们拥有适当的实例时,其中可以包括a -> a
。这就解释了为什么最终类型具有两个约束Num a
和Num (a -> a)
。
现在很容易将所有内容放在一起。摆脱约束(我们已经处理过)的约束,我们示意性地具有:
(+) . (+)
(a -> a) -> ((a -> a) -> (a -> a)) a -> (a -> a)
因此,在(.)
的类型签名(我将其写为(c -> d) -> (b -> c) -> (b -> d)
中,我们将a
命名为b
,将a -> a
命名为{{1 }},而c
为(a -> a) -> (a -> a)
。将它们代入后,我们得到的最终类型(d
)为:
b -> d
我们可以改写为
a -> ((a -> a) -> (a -> a))
在回忆起功能箭头是右向关联之后,删除不必要的括号。
答案 2 :(得分:2)
您快到了。
(Num i =>)
b = i
c = i -> i
(Num j =>)
a = j -- this is different, you associated b,c correctly but a wrongly
b = j -> j
=> i = j -> j -- ( by i = b = j -> j )
=> c = (j -> j) -> (j -> j) -- ( by c = i -> i, i = j -> j )
=> (+) . (+) :: a -> c = j -> ((j -> j) -> (j -> j))
= j -> (j -> j) -> j -> j -- ( simplifying brackets )
答案 3 :(得分:2)
(.) :: (b -> c) -> (a -> b) -> a -> c
If you apply two functions to it you get in pseudocode:
(+) . (+) -> a -> c
So what is the type of a? It has the same type as the first argument
of the second function you pass into (.). You can rewrite the type
of (+) with brackets and get
(+) :: a -> (a -> a)
From that we know that
a :: a
b :: (a -> a)
Now that we know what a and b are, let's look at the first argument of (.).
It's (+) applied by an argument b :: (a -> a). So we get
(a -> a) -> ((a -> a) -> (a -> a))
so we found the type of c:
c :: (a -> a) -> (a -> a)
and since we can remove the second pair of brackets
c :: (a -> a) -> a -> a
if we plug our findings into
(+) . (+) -> a -> c
we get
(+) . (+) :: a -> (a -> a) -> a -> a
答案 4 :(得分:1)
类型派生是纯机械过程:
(+) :: Num a => a -> a -> a
(.) :: ( b -> c ) -> ( a -> b ) -> a -> c
(.) ((+) :: t -> (t->t)) ((+) :: s -> (s->s)) :: a -> c
----------------------------------------------------
b ~ t, c ~ t->t, a ~ s, b ~ s->s s -> (t -> t)
Num t Num s s -> (b -> b)
Num b Num s s -> ((s->s) -> (s->s))
Num (s->s) Num s s -> ((s->s) -> (s->s))
(+) . (+)
与(.) (+) (+)
相同。
答案 5 :(得分:0)
(.)
和(+)
的类型如下:
(+) :: Num a => a -> a -> a
(.) :: (b -> c) -> (a -> b) -> a -> c
我们可以重新贴标签以避免混淆:
(+) :: Num i => i -> i -> i -- the first (+)
(.) :: (b -> c) -> (a -> b) -> a -> c
(+) :: Num j => j -> j -> j -- the second (+)
现在,让我们算出(+) (.)
的类型。这是(.)
,并且应用了一个参数,因此结果将是(a -> b) -> a -> c
,并且我们已经将(b -> c)
与第一个(+)
的类型进行了匹配,因此:
(b -> c) = Num i => i -> i -> i
b = i
c = i -> i
(+) (.) :: (a -> b) -> a -> c
= Num i => (a -> i) -> a -> c -- replacing b
= Num i => (a -> i) -> a -> (i -> i) -- replacing c
= Num i => (a -> i) -> a -> i -> i -- simplifying
现在,我们可以对此应用第二个参数。结果将是a -> i -> i
,并且我们已经将(a -> i)
与第二个(+)
的类型进行匹配,因此:
(a -> i) = Num j => j -> j -> j
a = j
i = j -> j
(+) (.) (+) :: Num i => a -> i -> i
= (Num i, Num j) => j -> i -> i -- replacing a
= (Num (j -> j), Num j) => j -> (j -> j) -> (j -> j) -- replacing i
= (Num (j -> j), Num j) => j -> (j -> j) -> j -> j -- simplifying