需要帮助理解lambda(柯里化)

7

我正在阅读《加速学习C#》,但我不太理解以下代码:

public static Func<TArg1, TResult> Bind2nd<TArg1, TArg2, TResult> (
    this Func<TArg1, TArg2, TResult> func,
    TArg2 constant ) 
{
    return (x) => func( x, constant );
}

在最后一行中,x是指什么?还有一个问题:
public static Func<TArg2, Func<TArg1, TResult>> Bind2nd<TArg1, TArg2, TResult>
( this Func<TArg1, TArg2, TResult> func )
{
    return (y) => (x) => func( x, y );
}

我该如何评估这个表达式?(y) => (x) => func( x, y ) 这里传递了什么参数,有些令人困惑。

4个回答

19

首先让我们简化代码:

Func<int, int> B(Func<int, int, int> f, int c)
{
    return x=>f(x, c);
}

这只是与以下语句等同:

class Locals
{
    public int c;
    public Func<int, int, int> f;
    public int Magic(int x) { return f(x, c); }
}
Func<int, int> B(Func<int, int, int> f, int c)
{
    Locals locals = new Locals();
    locals.f = f;
    locals.c = c;
    return locals.Magic;
}

现在你清楚 x 指的是什么了吗?x 是 "Magic" 函数的参数。

现在你可以像这样使用 B:

Func<int, int, int> adder = (a, b)=>a+b;
Func<int, int> addTen = B(adder, 10);
int thirty = addTen(20);

明白吗?你看到这里发生了什么吗?我们将一个有两个参数的函数中的一个参数“固定”为常数,这样它就变成了一个只有一个参数的函数。

第二个例子更进一步。同样地,简化以消除冗杂内容,以便更容易理解:

Func<int, Func<int, int>> B2(Func<int, int, int> f) 
{
    return y=>x=>f(x,y);
}

这和原来的意思一样

class Locals3
{
    public int y;
    public int Magic3(int x)
    {
       return x + this.y;
    }
}
class Locals2
{
    public Func<int, int, int> f;
    public Func<int, int> Magic2(int y)
    {
        Locals3 locals = new Locals3;
        locals.y = y;
        return locals.Magic3;
    }
}

Func<int, Func<int, int>> B2(Func<int, int, int> f) 
{
    Locals2 locals = new Locals2();
    locals.f = f;   
    return locals.Magic2;
}

那么你说

Func<int, int, int> adder = (a, b)=>a+b;
Func<int, Func<int, int>> makeFixedAdder = B2(adder);
Func<int, int> add10 = makeFixedAdder(10);
int thirty = add10(20);

B是一个参数修复工具。B2可以为您创建一个参数修复工具。

然而,这不是B2的关键点。B2的关键点在于:

adder(20, 10);

得到的结果与

B2(adder)(20)(10)

B2将一个带有两个参数的函数转换为每个参数只有一个参数的两个函数。

听懂了吗?


我必须说谢谢你的详细解释。现在我甚至都明白了 :) - Riaan

1
变量x是一个未绑定的变量。它代表从调用Bind2nd返回的函数的参数。
花几个小时学习Scheme会对你有所帮助,但你可以尝试以下方法。
当你调用Bind2nd时,返回的结果是一个函数。该函数定义为:
(x) => func (x, constant)

现在你已经将上述内容分配给一个变量,比如说lambda,你可以通过lambda变量调用该函数。

lambda(x);

Bind2nd 中定义的 x 只是一个变量,它代表将返回给您的函数的参数。


1

x是lambda的参数,其类型为TArg1。

将“=>”发音为“映射到”,可能会有所帮助,就像“x映射到一个新的函数,其中类型为TArg2的常量替换了原始函数委托func。”


1

一个 lambda 表达式是匿名方法的简写。像匿名方法一样,lambda 表达式被分配给委托类型。所有适用于匿名方法的条件也适用于 lambda 表达式。

=> 被称为 lambda 运算符,读作“goes to”。运算符的左侧指定由逗号分隔的输入参数,右侧指定称为 lambda 主体的表达式或语句块。(p1, p2, p3, …pN) => expression 如果您只有一个参数,则可以跳过括号 p1 => expression;

我写了一篇小博客,在这里解释了 lambda 表达式 Lambda Expression


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接