如何推理部分应用的方法链
How to reason about partially applied method chaining
我正在尝试了解如何推理部分应用方法链接的类型。
我不明白为什么:
:t (+)(+2)
是 (a->a)->a->a
或者为什么:
:t (+)(+)
是 (a->a->a)->a->a->a
我是说第一个例子
我不明白,在查看 (+)
时,我是否需要查看它需要什么 a->a->a
或它之前的方法 (+2)
(需要 a
)。
在第二个示例中,我知道第一个 (+)
需要 a->a->a
,但是一旦我完成了第一个方法,为什么第二个方法再次需要相同的参数?
您实际上有点误报了类型。那里有一些非常重要的类型类约束:
(+)(+2) :: (Num a, Num (a -> a)) => (a -> a) -> a -> a
那么这是从哪里来的呢?其实很简单。首先,(+)
的类型签名是
(+) :: Num a => a -> a -> a
或者,重写以明确柯里化:
(+) :: Num a => a -> (a -> a)
与此同时,(+2)
的类型(正是执行该部分应用的结果)是:
(+2) :: Num a => a -> a
现在,当您执行 (+)(+2)
时,您所做的是(部分)将 (+)
函数应用于函数 (+2)
。也就是说,我们将 (+2)
视为 (+)
的第一个参数。为了让它工作,它的类型 - Num a => a -> a
- 必须是 Num
的实例。所以这就是为什么我们有进一步的类型约束,即 a -> a
必须是 Num
的实例。 (默认情况下永远不会出现这种情况,但您可以为数值函数定义自己的实例 - 通常它将两个函数都应用于输入并添加结果。)
因此,让我们将 (+)
的类型签名专门用于将其应用于函数 (a -> a)
的情况(正如我刚才所说,它本身必须是 [=25= 的实例) ],以及 a
本身)。我们得到:
(+) :: (Num a, Num (a -> a)) => (a -> a) -> (a -> a) -> (a -> a)
或使用明确的柯里化:
(+) :: (Num a, Num (a -> a)) => (a -> a) -> ((a -> a) -> (a -> a))
也就是说,它需要一个 a -> a
函数和 returns 一个 (a -> a) -> (a -> a)
类型的 "higher-order function"。因此,当我们将其应用于 (+2)
时,我们得到的正是这样一个高阶函数:
(+)(+2) :: (Num a, Num (a -> a)) => (a -> a) -> (a -> a)
这正是报道的内容,因为最后一对括号是不必要的。 (这是由于再次柯里化。)
第二种情况完全类似,只是您要应用的函数是 a -> a -> a
而不是 a -> a
。
我正在尝试了解如何推理部分应用方法链接的类型。
我不明白为什么:
:t (+)(+2)
是 (a->a)->a->a
或者为什么:
:t (+)(+)
是 (a->a->a)->a->a->a
我是说第一个例子
我不明白,在查看 (+)
时,我是否需要查看它需要什么 a->a->a
或它之前的方法 (+2)
(需要 a
)。
在第二个示例中,我知道第一个 (+)
需要 a->a->a
,但是一旦我完成了第一个方法,为什么第二个方法再次需要相同的参数?
您实际上有点误报了类型。那里有一些非常重要的类型类约束:
(+)(+2) :: (Num a, Num (a -> a)) => (a -> a) -> a -> a
那么这是从哪里来的呢?其实很简单。首先,(+)
的类型签名是
(+) :: Num a => a -> a -> a
或者,重写以明确柯里化:
(+) :: Num a => a -> (a -> a)
与此同时,(+2)
的类型(正是执行该部分应用的结果)是:
(+2) :: Num a => a -> a
现在,当您执行 (+)(+2)
时,您所做的是(部分)将 (+)
函数应用于函数 (+2)
。也就是说,我们将 (+2)
视为 (+)
的第一个参数。为了让它工作,它的类型 - Num a => a -> a
- 必须是 Num
的实例。所以这就是为什么我们有进一步的类型约束,即 a -> a
必须是 Num
的实例。 (默认情况下永远不会出现这种情况,但您可以为数值函数定义自己的实例 - 通常它将两个函数都应用于输入并添加结果。)
因此,让我们将 (+)
的类型签名专门用于将其应用于函数 (a -> a)
的情况(正如我刚才所说,它本身必须是 [=25= 的实例) ],以及 a
本身)。我们得到:
(+) :: (Num a, Num (a -> a)) => (a -> a) -> (a -> a) -> (a -> a)
或使用明确的柯里化:
(+) :: (Num a, Num (a -> a)) => (a -> a) -> ((a -> a) -> (a -> a))
也就是说,它需要一个 a -> a
函数和 returns 一个 (a -> a) -> (a -> a)
类型的 "higher-order function"。因此,当我们将其应用于 (+2)
时,我们得到的正是这样一个高阶函数:
(+)(+2) :: (Num a, Num (a -> a)) => (a -> a) -> (a -> a)
这正是报道的内容,因为最后一对括号是不必要的。 (这是由于再次柯里化。)
第二种情况完全类似,只是您要应用的函数是 a -> a -> a
而不是 a -> a
。