了解功能降低

发布于 2025-02-10 04:21:58 字数 490 浏览 2 评论 0原文

功能编程书关于不同函数之间的等效性。例如,如果我的理解是正确的,则意味着:

func(param => otherFunc(param))
func(otherFunc)                   // simplified

,如果我能以我的能力表达它,我会说:

一个获取一定数量参数的函数,然后仅 返回将这些参数称为参数的第二个函数 与仅将第二个函数作为单个参数的函数相同。

这是正确的理解吗?有什么例子表明这将如何工作?到目前为止,我唯一能想到自己的人是很琐碎的,所以我想看看是否可以看到更多的例子来加深对此应用的理解。

There are a few examples in this functional programing book about equivalency between different functions. For example, if my understanding is correct it means:

func(param => otherFunc(param))
func(otherFunc)                   // simplified

And, if I can articulate it in words to the best of my ability, I would say:

A function that takes a certain number of parameters and then only
returns a second function called with those parameters as arguments
is the same as a function that just takes the second function as a single parameter.

Is this a correct understanding? What would be some examples that would show how this would work? The only ones I can think of myself so far are quite trivial, so I'd like to see if I can see more examples to deepen my understanding of some applications of this.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

你又不是我 2025-02-17 04:21:58

在Lambda微积分(是许多功能编程概念的基础)中,这称为ETA降低,是系统中为数不多的基本减少操作之一。

η-还原
LC:λx.fx= f
JavaScript:(x => f(x))= f

向自己证明这有效是非常微不足道的。 “包装” lambda中的函数明确地提供了下一个参数,该参数无论如何都会应用。

为了简洁起见,假设我们在教堂编码中有一个增量函数公司和LC编号。
LC:(λx.incx)3 - > Inc 3 - > 4 = inc 3 - > 4
JavaScript:(X => Inc(X))(3) - > Inc(3) - > 4 = inc(3) - > 4

如果您具有多重题目功能,这会分解一点。由于纯lambda微积分仅具有一元函数,因此减少ETA是如此简单,但是在JS中,我们可以使用窍门来捕获任何数量的参数。

JS“ ETA”等效
((... x)=> f(... x))= f

至于应用程序,您可以使用此事实简化表达式。除此之外,实际上没有理由以这种方式扩展表达式,只是为了表现和可读性而减少它们。

是的,这些都是等效的,这实际上是您发现的核心功能编程原理。

In the lambda calculus, which is the foundation for a lot of functional programming concepts, this is called Eta reduction and is one of the few fundamental reduction operations in the system.

η-Reduction
LC: λx.f x = f
Javascript: (x => f(x)) = f

It is quite trivial to prove to yourself that this works. "Wrapping" the function in a lambda just explicitly provides the next argument which is applied anyway.

For the sake of brevity assume we have an increment function INC and LC numbers in the church encoding.
LC: (λx.INC x) 3 -> INC 3 -> 4 = INC 3 -> 4
Javascript: (x => INC(x))(3) -> INC(3) -> 4 = INC(3) -> 4

This breaks down a little bit if you have a multi-argument function. Since pure lambda calculus only has unary functions, eta reduction is this simple, but in JS we can use a trick to capture any number of arguments.

JS "Eta" Equvilancy
((...x) => f(...x)) = f

As for applications, you can use this fact to simplify expressions. Other than that there isn't really a reason to expand expressions this way, only reducing them for sake of performance and readability.

Yes, these are equivalent, and this is actually a core functional programming principle that you have discovered.

眼眸印温柔 2025-02-17 04:21:58

我将尝试逐步做出最好的解释。

步骤1

功能定义

您可以用2种不同的语法定义一个函数

function inc(number) {
  return number + 1
}

,或者

const inc = (number) {
  return number + 1
}

// or simplifed

const inc = (number) => number + 1

这些2个语法或多或少是等效的,但是第二个语法是您拥有一个名为Inc的常数(如此变量),该函数的指向是指向一段记忆的指针包含一个函数。

因此,inc是一个包含(值)功能有效负载的变量。

步骤2

此步骤与上一个步骤

无关

,并且我们希望将每个元素递增到可以使用函数映射的新数组中。

地图是一个创建一个新数组的函数,该数组填充了调用调用数组中每个元素的提供的函数的结果。

const result = [1,2,3,4].map((number) => number + 1)
console.log(result)

步骤3

让我们一起制作成分

,我们拥有inc功能,我们想在map中使用该功能。

我们可以做一个非常简单的事情。

const inc = (x) => x + 1

const result = [1,2,3,4].map(number => inc (number))
console.log(result)

步骤4

让我们尝试另一种方法。

暂时暂时尝试使用inc函数,我们在步骤3上所做的事情。我们将尝试另一个批准。

在步骤1,我们已经看到一个函数定义如下。

const inc = (number) => number + 1

平等标志周围的语义非常强大,并且说:

表达式inc

等于

表达式(number)=>数字 + 1

我们可以采用inc功能定义和步骤2代码。

const inc = (number) => number + 1
const result = [1,2,3,4].map((number) => number + 1)

在两行的右侧,我们都有一个重复的表达式:

(number) => number + 1

第一行说等效的表达式为inc。试图采用这种方法的结果是:

const inc = (x) => x + 1
const result = [1,2,3,4].map(inc)
console.log(result)

当您尝试以这种方式读取代码时,您可以想象到Inline inc标签具有自己的表达式。

奖金

让我们用超过1个参数应用该方法

试图将此方法应用于2个参数函数,我们需要另一个用户酶。给定数字数组,我们需要每个数字的总和。

为此,我们将使用标准RELAD功能。

const result = [1,2,3,4].reduce((a, x) => a + x, 0)
console.log(result)

现在,我们可以提取总和函数并用其标签替换表达式。

const sum = (a, b) => a + b
const result = [1,2,3,4].reduce(sum, 0)
console.log(result)

I'll try to do my best explanation by step by step examples.

Step 1

Function definition

In javacript you can define a function with 2 different syntax

function inc(number) {
  return number + 1
}

or

const inc = (number) {
  return number + 1
}

// or simplifed

const inc = (number) => number + 1

Those 2 syntax are more or less equivalent but the second one is stays that you have a constant called inc (so a variable) that have a pointer to a piece of memory that contains a function.

So, inc is a variable that contains (as value) the function payload.

Step 2

This step is not related with the previous one

Supposing that we have an array and we want to increment each element into a new array we can use the function map.

Map is a function that creates a new array populated with the results of calling a provided function on every element in the calling array.

Mozilla Reference

const result = [1,2,3,4].map((number) => number + 1)
console.log(result)

Step 3

Let's make ingredients together

We have have a inc function and we want to use that function in our map.

We can do a very simple things.

const inc = (x) => x + 1

const result = [1,2,3,4].map(number => inc (number))
console.log(result)

Step 4

Let's try another approach.

Forget for a moment what we have done on step 3, trying using our inc function. We will try another approac.

At step 1 we have seen that a function is defined as follows.

const inc = (number) => number + 1

The semantics around the equal sign is quite powerful and is saying:

the expression inc

is equivalent to

the expression (number) => number + 1

We can take our inc function definition and the Step 2 code.

const inc = (number) => number + 1
const result = [1,2,3,4].map((number) => number + 1)

On the right side of both lines we have a duplicated expression:

(number) => number + 1

And first line says that an equivalent expression is inc. Trying to apply this approach the results is:

const inc = (x) => x + 1
const result = [1,2,3,4].map(inc)
console.log(result)

when you are trying to read a code written in this way you can imagine to inline inc label with its own expression.

Bonus

Let's apply the approach with more than 1 parameter

Trying to apply this approach for 2 parameter function we need another usecase. Given an array of numbers we want the sum of each number.

To achieve that we'll use the standard reduce function.

Mozilla Reference

const result = [1,2,3,4].reduce((a, x) => a + x, 0)
console.log(result)

now we can extract a sum function and replace the expression with it's label.

const sum = (a, b) => a + b
const result = [1,2,3,4].reduce(sum, 0)
console.log(result)

似狗非友 2025-02-17 04:21:58

这两个

func(param => otherFunc(param))
func(otherFunc)

并不完全相同,原因是这些的两个并不完全相同,

f1 = param => otherFunc(param)
f2 = otherFunc

确实看到了这个示例:

// silly function taking two args and producing a string
function f(x,y) {
    return "<" + x + ',' + y + ">";
}

f1 = f;
f2 = x => f(x);

console.log(f1(2,3)); // ok
console.log(f2(2,3)); // not ok!

它们与众不同的原因是x =&gt; f(x)是一个仅采用1个参数的函数,即使函数f期望2,因此,当您将f2用2个参数馈送时,它会添加INGNORES第二个参数,然后仅使用1个参数调用f,该参数导致第二个参数(f)为undefined

显然,您可以将f2作为(x,y)=&gt; f(x,y),但是如果f是ternary,则会遇到麻烦。

因此,如果您不想阐明包装器函数的所有参数以使其与f一致,则必须像这样编写包装器函数

f2correct = (...x) => f(...x);

,以表达f2Correct的想法可以采用任何数量的参数,并且将它们全部转发到f。实际上,f2Correct等效于f

关于您对此的理解,我认为您接近了,但可能会错误地介绍它。

占有一定数量的参数,然后仅返回带有这些参数的第二个函数,因为参数与 仅将第二个功能作为单个参数

These two

func(param => otherFunc(param))
func(otherFunc)

are not exactly the same, the reason being that these two are not exactly the same

f1 = param => otherFunc(param)
f2 = otherFunc

Indeed look at this example:

// silly function taking two args and producing a string
function f(x,y) {
    return "<" + x + ',' + y + ">";
}

f1 = f;
f2 = x => f(x);

console.log(f1(2,3)); // ok
console.log(f2(2,3)); // not ok!

The reason they are not the same is that x => f(x) is a function that only takes 1 argument, even though the function f expects 2, so when you feed f2 with 2 arguments, it ingnores the second argument, and then calls f with 1 argument only, which results in the second argument (of f) being undefined.

Clearly, you could have written f2 as (x, y) => f(x, y), but then you'd be in trouble if f was ternary.

So, if you don't want to spell out all the arguments of the wrapper function to make it agree with f, you have to write the wrapper function like this

f2correct = (...x) => f(...x);

which expresses the idea that f2correct can take any number of arguments, and it forwards them all to f. In fact, f2correct is equivalent to f.

As regards your understanding of that, I think you got close, but probably misworded it.

A function that takes a certain number of parameters and then only returns a second function called with those parameters as arguments is the same as a function that just takes the second function as a single parameter the second function.

允世 2025-02-17 04:21:58

当您评估表达式时,可能会“容易”(YMMV)。

让我们从简单的东西开始:

42 === (40 + 1 + 1); // true
42 === (40 + 2);     // true
42 === (42);         // true
42 === 42;           // true

让我们定义inc并对其进行评估:

const inc = x => x + 1;

inc === (inc); // true
inc === inc;   // true

因此:

inc(41) === (inc)(41); // true
inc(41) === inc(41);   // true

重要位在这里:(inc)

该表达式评估该函数并简单地返回它。因此,当您做(INC)(41)时,您最终会进行inc(41)

让我们在右操作数中内联inc

inc(41) === (x => x + 1)(41); // true
//           ^^^^^^^^^^
//           i.e. inc

现在,让我们添加一个不必要的包装器:

   inc(41) === (n => (x => x + 1)(n))(41); // true
//              ^     ^           ^   ^^
//              |     |           |   |
//              |     +<<<<<<<<<<<+   |
//              |                 |   |
//              +>>>>>>>>>>>>>>>>>+   |
//              |                     |
//              +<<<<<<<<<<<<<<<<<<<<<+

让我们简化一点:

   inc(41) === (n => inc(n))(41); // true
//              ^        ^   ^^
//              |        |   |
//              |        |   |
//              +>>>>>>>>+   |
//              |            |
//              +<<<<<<<<<<<<+

或仅仅:

inc(41) === (inc)(41); // true

也有助于知道如何读取内容:

(n => inc(n))(41)

expression n =&gt; Inc(n)(这是一个函数)被应用于 41。 (此时,n等于41。)然后,inc将其应用于n

因此,您不妨直接将inc直接应用于 41 ,然后跳过第一个表达式,即:

(n => inc(n))(41) === inc(41); // true

It is probably "easier" (YMMV) to see when you evaluate expressions.

Let's start with something simple:

42 === (40 + 1 + 1); // true
42 === (40 + 2);     // true
42 === (42);         // true
42 === 42;           // true

Let's define inc and evaluate it:

const inc = x => x + 1;

inc === (inc); // true
inc === inc;   // true

And so:

inc(41) === (inc)(41); // true
inc(41) === inc(41);   // true

Important bit is here: (inc).

The expression evaluates the function and simply returns it. So when you do (inc)(41) you end up doing inc(41).

Let's inline inc in the right operand:

inc(41) === (x => x + 1)(41); // true
//           ^^^^^^^^^^
//           i.e. inc

Now let's add an unnecessary wrapper:

   inc(41) === (n => (x => x + 1)(n))(41); // true
//              ^     ^           ^   ^^
//              |     |           |   |
//              |     +<<<<<<<<<<<+   |
//              |                 |   |
//              +>>>>>>>>>>>>>>>>>+   |
//              |                     |
//              +<<<<<<<<<<<<<<<<<<<<<+

Let's simplify a little bit:

   inc(41) === (n => inc(n))(41); // true
//              ^        ^   ^^
//              |        |   |
//              |        |   |
//              +>>>>>>>>+   |
//              |            |
//              +<<<<<<<<<<<<+

Or just:

inc(41) === (inc)(41); // true

It also helps to know how to read things:

(n => inc(n))(41)

The expression n => inc(n) (which is a function) is applied to 41. (At this point n is equal to 41.) Then inc is applied to n.

So you might as well just apply inc to 41 directly and skip the first expression, i.e.:

(n => inc(n))(41) === inc(41); // true
鸵鸟症 2025-02-17 04:21:58

在JavaScript中,如果您不使用括号,则只需恢复一个函数(指针)即可。

看看之间的区别。

var a = func(x);
var b = func;

第一个调用执行函数func并返回结果并将其保存到a中。

第二个呼叫(无括号)返回AS-IS的函数,并将其绑定到b。之后,做一个。

var c = b(x)

只要没有副作用,就应该与a相同。

现在看一下lambda功能。

var d = param => func(param);

在这里,您只需创建一个函数d调用func,然后将其参数传递到func

你顺便说一句。也可以这样写。

var d = function(param) { return func(param) }

并且可以重新编写此代码。

function d(param) {
    return func(param);
}

就像您现在看到的那样。 dfunc相同。再次可以重新编写此代码。

var d = func;

两个功能都是相同的。

这就是为什么您可以在示例中直接传递其他func。您只需传递函数,而无需创建另一个新功能。

In JavaScript if you don't use parenthesis, you just get back a function (pointer).

Look at the difference between.

var a = func(x);
var b = func;

The first call executes the function func and returns the result and saves it into a.

The second call (without the parenthesis) returns the function as-is, and just binds it to b. After this, doing a.

var c = b(x)

should be the same as a, as long there are no side-effects.

Now look at the lambda-function.

var d = param => func(param);

Here you just create a function d that calls func and passes it arguments along to func.

You btw. also can write it this way.

var d = function(param) { return func(param) }

and this piece of code can be re-written.

function d(param) {
    return func(param);
}

as you now maybe see. d is the same as func. And again to the loop, this piece of code can be re-written.

var d = func;

Both function are the same.

That's why you can pass otherFunc in your example directly. You just pass the function as-is, without the need to create another new function.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文