我是函数式编程的学生,对不起,如果我的问题听起来很奇怪 - 我试图围绕函数的给定类型签名以及如何实现它们。
查看ap
(替换)的签名
https://gist.github.com/Avaq/1f0636ec5c8d6aed2e45
(a → b → c) → (a → b) → a → c
在这里给出
const S = f => g => x => f(x)(g(x));
我认为我理解。 f
是一个函数,它使用两个参数a
和b
并返回c
。 g
是一个需要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))
类型签名
(f (a -> b), f a) -> f b
似乎与
相似(a → b → c) → (a → b) → a → c
使用a = f重写第二个,b = a,c = b我得到
(f -> a -> b) -> (f -> a) -> f -> b
假设ap
有两个参数,第一个f
可能是包含函数a -> b
的一些仿函数,而第二个f
包含a
的仿函数{1}}返回一个仿函数,用第一个仿函数函数替换结束点b
,然后给出包含a
的仿函数。
好的,退一步说,这两件事看起来大不相同,我无法理解他们是如何以某种方式说同样的事情。
const S = f => g => x => f(x)(g(x))
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))
的关系如何,因为我可以看到它们如何表达相同的签名,但我不认为它们是同样的事情。
任何能够在这里提供认知帮助的人,我都会非常感激
答案 0 :(得分:5)
ap
是转换的名称,它在大量容器类型(称为Applicative Functors)上的行为方式相同。一个这样的容器类型是Function:它可以被视为其返回值的容器。
你在我的要点中找到的S
组合来自无类型的Lambda微积分,并且是一个函数的转换。它恰好也是函数Applicative Functor的有效实现,它恰好是Ramda和Sanctuary的首选实现。这就是您可以将ap
用作S
。
要了解ap
S
的方式,让我们看一下ap
的签名:
Apply f => (f (a -> b), f a) -> f b
让我们通过调整函数来摆脱逗号。这应该使接下来的步骤更容易理解:
Apply f => f (a -> b) -> f a -> f b
Apply f
部分显示,我们在哪里看到f a
,我们可以使用包含a
的Applicative Functor容器。让我们通过将f
替换为(Function x)
来专门为Function容器设置此签名。 x
是函数的输入,接下来是输出。
(Function x) (a -> b) -> (Function x) a -> (Function x) b
其内容如下:给出x
到a
到b
的函数的函数,以及从x
到a
的函数,将函数从x
返回到b
。
由于构造函数关联的工作方式,我们可以删除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
答案 1 :(得分:2)
首先,我认为没有简单的解释为什么无类型lambda演算中函数类型的applicative functor被称为替换。 AFAIK,Schönfinkel最初称这种组合器融合或融合功能。
为了专门化一般的applicative functor类型(f (a -> b), f a) -> f b
(uncurried form),我们需要知道参数化类型变量f
在函数类型的上下文中的确切表示。
因为每个仿函数applicative仿函数都在一个类型上进行参数化。但是,函数类型构造函数需要两种类型 - 一种用于参数,另一种用于返回值。要使函数成为(applicative)仿函数的实例,我们必须忽略返回值的类型。因此,f
代表(a -> )
,即。函数类型本身及其参数的类型。部分应用的函数类型构造函数的正确表示法实际上是前缀(->) a
,所以让我们坚持这一点。
接下来,我将以咖喱形式重写常规应用类型,并将f
替换为(->) r
。我使用另一个字母来分隔来自其他类型变量的applicative的类型参数:
(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
组合子的类型。