gpt4 book ai didi

functional-programming - 如何将函数转换为无点形式?

转载 作者:行者123 更新时间:2023-12-01 11:44:14 25 4
gpt4 key购买 nike

假设我有一个JavaScript函数

function f(x) {
return a(b(x), c(x));
}

如何将其转换为无点函数?通过组合功能?还有关于此的更多信息的资源吗?

最佳答案

通常,将函数转换为无点样式时,没有容易遵循的规则。您要么不得不猜测,要么可以将其自动化。在Haskell IRC频道中,我们拥有lambdabot,它非常适合将Haskell函数转换为无点样式。我通常只是咨询一下,然后在我需要了解它如何工作的情况下往回走。

您可以使用几个有用的函数来解决您的特定示例。我将在下面向您展示它的工作原理,但是请注意,它可能需要花很多时间才能理解。如果您真正了解基本的lambda演算,它也会有所帮助,因为JavaScript语法有时会妨碍您的工作。

无论如何,这里是:

基本上,要正确执行此操作,您需要三个功能:fmap(f, g)ap(f, g)curry(f)。有了这些代码后,就可以轻松地将f(x)定义为(并且在Haskell中看起来更整洁)

f = ap(fmap(curry(a), b), c);

有趣的一点在于定义了这三个功能。

咖喱

通常,当您在JavaScript中定义多个参数的函数时,您会像
function f(x, y) {
// body
}

然后通过执行类似于 f(3, 4)的方式来调用它们。在函数编程中,这就是所谓的“非函数”。您也可以想象定义函数,例如
function f(x) {
return function(y) {
//body
}
}

这些功能称为“咖喱函数”。 (顺便说一下,如果您想知道一个奇怪的名字,它们是以一位名叫Curry的数学家的名字命名的。)
f(3)(4)

但是除此之外,这两个函数的行为非常相似。一个区别是,当咖喱化函数时,使用无点样式会更容易。我们的 curry函数只是采用了像第一个这样的非咖喱函数,然后将其变成了像第二个这样的咖喱函数。 curry可以定义为
function curry(f) {
return function(a) {
return function(b) {
return f(a, b);
}
}
}

现在,您可以使用它。您可以执行以下操作,而不是通过 pow(3, 4)获得81
cpow = curry(pow);
cpow(3)(4);
cpowpow的咖喱版本。它不会同时使用两个参数,而是将它们分开。在您的特定情况下,这使我们可以从
function f(x) {
return a(b(x), c(x));
}


function f(x) {
return curry(a)(b(x))(c(x));
}

这是进步! (尽管我承认在JavaScript中看起来很奇怪...)现在,到少辣的牧场上。

fmap

难题的第二部分是 fmap(f, g),它接受两个函数作为参数并组成它们。我的意思是
fmap(f, g)(x) == f(g(x))

这很容易定义,我们只是让
function fmap(f, g) {
return function(x) {
return f(g(x));
}
}

当您要依次执行两件事时,这很有用。假设您要执行无用的操作 log(exp(x))。您可以按照传统方式执行此操作:
function logexp(x) {
return log(exp(x));
}

你可以做
logexp = fmap(log, exp);

这通常称为组成两个函数。要将其连接到您的示例,最后我们将其保留下来,将其重构为
function f(x) {
return curry(a)(b(x))(c(x));
}

现在,我们注意到它与 fmap的函数体在视觉上相似。让我们用 fmap重写它,它变成
function f(x) {
return fmap(curry(a), b)(x)(c(x));
}

(要查看我如何到达那里,请想象 f = curry(a)g = bc(x)的最后一位没有改变。)

ap

我们的最后一个难题是 ap(f, g),它带有两个函数和一个参数,并且做奇怪的事情。我什至不会尝试解释它,所以我只向您展示它的作用:
ap(f, g)(x) == f(x)(g(x))

请记住, f实际上只是两个参数的函数,只是我们写一些稍有不同才能执行魔术。 ap在JavaScript中定义为
function ap(f, g) {
return function(x) {
return f(x)(g(x));
}
}

因此,将其放在一个更实际的上下文中:假设您想将数字提高到其平方根。你可以做
function powsqrt(x) {
return pow(x, sqrt(x));
}

或者,凭借您对 ap的新发现并从关于咖喱的第一部分中记住 cpow,您还可以
powsqrt = ap(cpow, sqrt);

这是有效的,因为 cpowpow的咖喱版本。您可以自己验证扩展 ap的定义是否正确。

现在,要将所有这些与您的示例联系在一起,我们需要转向
function f(x) {
return fmap(curry(a), b)(x)(c(x));
}

进入最终的,完全免费的版本。如果我们查看 ap的定义,我们可以在这里做些什么,将其转换为无点版本!
function f(x) {
return ap(fmap(curry(a), b), c)(x);
}

基本上,最简单的方法是现在“展开”对 ap的调用。用函数体替换对 ap的调用!然后,我们仅通过替换就可以得到
function f(x) {
return function(y) {
return fmap(curry(a), b)(y)(c(y));
}(x);
}

为了避免名称冲突,我已将一个 x重命名为 y。这仍然有些怪异,但是我们可以使其更短一些。毕竟,这与
function f(x) {
return fmap(curry(a), b)(x)(c(x));
}

这就是我们的开始!我们对 ap的调用是正确的。如果愿意,您可以进一步展开此步骤,以了解在说完所有内容后,我们实际上就完成了我们刚开始的工作。我将其保留为练习。

包起来

无论如何,您的代码的最后一次重构使它成为了
function f(x) {
return ap(fmap(curry(a), b), c)(x);
}

哪一个当然是和
f = ap(fmap(curry(a), b), c);

就是这样!

关于functional-programming - 如何将函数转换为无点形式?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16930860/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com