2

我是函数式编程的学生,如果我的问题听起来很奇怪,很抱歉——我正试图围绕给定的函数类型签名以及它们是如何实现的。

查看ap(替换)的签名

https://gist.github.com/Avaq/1f0636ec5c8d6aed2e45

(a → b → c) → (a → b) → a → c

在这里给出为

const S = f => g => x => f(x)(g(x));

我想我明白了。f是一个接受两个参数,ab返回的函数cg是一个接受a和返回的函数b。所以g(a)返回b,因此f(a)(b)可以写成f(a)(g(a)),返回c

g(a)是替代品b吗?

好的,现在我正在研究一个仍然有意义的不同实现:

https://github.com/sanctuary-js/sanctuary-type-classes/tree/v7.1.1#ap--applyf--fa-bfa---fb

ap(Identity(Math.sqrt), Identity(64))

类型签名

  1. (f (a -> b), f a) -> f b

看起来类似于

  1. (a → b → c) → (a → b) → a → c

使用 a = f、b = a 和 c = b 重写第二个我得到

  1. (f -> a -> b) -> (f -> a) -> f -> b

假设它ap接受两个参数,其中第一个f可能是一些包含函数a -> b的函子,第二个可能是一些函f子,其中包含a返回一个函子,该函子将第一个函子的函数替换为给定的终点b,然后函子包含a.

好吧,退后一步,这两件事看起来有很大的不同,我无法理解他们如何以某种方式说同样的事情。

  1. const S = f => g => x => f(x)(g(x))

  2. ap(Identity(Math.sqrt), Identity(64))

根据我的理解,ap(F(g),F(a))可以表达为F(a).map(g),我仍然很难等同于const S = f => g => x => f(x)(g(x))。也许我误解了什么。

...也许我的误解与 的表达ap以及它的相关性有关,f => g => x => f(x)(g(x))因为我可以看到它们如何表达相同的签名,但我不认为它们是同一件事。

任何可以在这里提供一些认知帮助的人,我将不胜感激

4

2 回答 2

5

ap是在称为 Applicative Functor 的大量容器类型上行为相同的转换的名称。一种这样的容器类型是 Function:它可以被视为返回值的容器

您在我的 gist 中找到的S组合子来自无类型的 Lambda 演算,并且专门是对 Function 的转换。它恰好也是 Applicative Functor for Function 的有效实现,并且它恰好是 Ramda 和 Sanctuary 的首选实现。这就是您可以使用apas的原因S

为了了解如何apS,让我们看一下签名ap

Apply f => (f (a -> b), f a) -> f b

让我们通过对函数进行柯里化来去掉逗号。这应该使接下来的步骤更容易遵循:

Apply f => f (a -> b) -> f a -> f b

Apply f部分表明,无论我们在哪里看到f a,我们都可以使用包含 的 Applicative Functor 容器a。让我们将这个签名专门用于 Function 容器,f(Function x). x是函数的输入,接下来是输出

(Function x) (a -> b) -> (Function x) a -> (Function x) b

这读作:给定一个函数 from xto 一个 Function from atob和一个 Function from xto a,返回一个 Function from xtob

Function x由于构造函数关联性的工作方式,我们可以删除 周围的括号:

Function x (a -> b) -> Function x a -> Function x b

另一种写法Function a b是使用箭头符号:(a -> b),所以在下一步中我们这样做:

(x -> (a -> b)) -> (x -> a) -> (x -> b)

最后我们可以再次去掉额外的括号,发现它是我们的 S 组合子:

(x -> a -> b) -> (x -> a) -> x -> b
(a -> b -> c) -> (a -> b) -> a -> c
于 2018-02-11T20:32:03.550 回答
2

首先,我认为没有简单的解释来解释为什么无类型 lambda 演算中函数类型的应用函子被称为替换。AFAIK,Schönfinkel 最初将此组合子称为融合或合并功能。

为了特化通用的应用函子类型(f (a -> b), f a) -> f b(非柯里化形式),我们需要知道参数化类型变量f在函数类型的上下文中究竟代表什么。

由于每个函子应用函子都在单一类型上参数化。然而,函数类型构造函数需要两种类型——一种用于参数,另一种用于返回值。对于要成为(应用)函子的实例的函数,我们必须因此忽略返回值的类型。因此,f表示(a -> ),即。函数类型本身及其参数的类型。部分应用的函数类型构造函数的正确表示法实际上是 prefix (->) a,所以让我们坚持这一点。

接下来,我将用柯里化形式重写通用应用类型并替换f(->) r. 我使用另一个字母将应用程序的类型参数与其他类型变量分隔:

(f (a -> b), f a) -> f b
f (a -> b) -> f a -> f b // curried form

// substitution
(->) r (a -> b) -> (->) r a -> (->) r b // prefix notation
(r -> a -> b) -> (r -> a) -> (r -> b) // infix notation

// omit unnecessary parenthesis
(r -> a -> b) -> (r -> a) -> r -> b

这正是S组合器的类型。

于 2018-02-11T21:31:20.797 回答