C# 中 Lambda/LINQ 表达式的高级函数混淆
本文关键字:高级 函数 表达式 Lambda LINQ | 更新日期: 2023-09-27 18:06:39
不确定如何描述这个问题,所以标题可能是错误的。
正在阅读一些代码示例,并对以下返回函数感到困惑:
Func<Func<int , bool>, Func<int , int>, Func<int , int>> Loop = null ;
Loop = (c , f ) => n => c(n) ? Loop(c , f ) ( f (n)): n;
Func<int , int> w = Loop(n => n < 10 , n => n + 2);
var r = w(2);
var s = w(3);
Console . WriteLine ("{0} {1}" , r , s );
我知道当 c(n( 计算结果为 true 时,这个函数会返回循环,但我不明白 Loop(c,f( (f(n(( 是如何计算的 - 它们都被传递回 Loop 了吗?我尝试过在 Linqpad 中运行转储,但我只是不明白该位是如何运行的。
任何帮助将不胜感激,明白这可能是一个愚蠢的问题!
尝试理解它的一种方法是从小处着手:以+1为增量的基本循环1-10。
Func<int,int> basicLoop = null;
basicLoop = n => n < 10 ? basicLoop(n+1) : n;
这很简单 - basicLoop
是基于参数n
返回n
(对于 n>= 10(或使用递增参数调用自身的函数。因此,basicLoop(8)
计算公式为:
-
basicLoop(8)
8 <10,因此调用basicLoop(8+1)
以获得结果 -
basicLoop(9)
9 <10,因此调用basicLoop(9+1)
以获得结果 -
basicLoop(10)
10 == 10,因此返回n
即 10。 -
basicLoop(9)
得到结果 10(来自basicLoop(10)
(并返回它 -
basicLoop(8)
得到结果 10(来自basicLoop(9)
(并返回它
现在我们要将条件作为参数传递给循环。这意味着我们的"循环"Func
需要在每次迭代时传递该条件:
该条件的类型显然是(类似于n<10
(-Func<int, bool>
。所以现在我们有一些东西,它以Func<int,bool>
作为参数并返回与我们的原始basicLoop
相同的值。因此,它将是一个参数和一个结果Func
:
Func<Func<int, bool>, Func<int,int>> condLoop = null;
condLoop
是一个参数的函数 - 所以在定义时我们采用参数:condLoop = (condition) => ...
。
我们需要替换原始basicLoop
中的条件:n => n < 10 ? ...
变得n => condition(n) ? ...
。
最后一部分是替换basicLoop(n+1)
- 我们有condLoop
函数,当您将条件传递给它时,它会返回相当于basicLoop
的函数。幸运的是,我们的条件在迭代之间不会改变,我们已经有了它 - condLoop(condition)
相当于 basicLoop
.将一切整合在一起:
condLoop = (condition) =>
n => condition(n) ?
condLoop(condition) (n + 1) :
n;
通过呼叫condLoop(x => x < 5)(4)
进行跟踪
- 所以当
condition(4)
被调用时 x = 4, 4 <5 为真 - 调用具有相同条件并增加 n 的condLoop
-condLoop(x => x < 5)(4 + 1)
得到结果 -
condLoop(x => x < 5)(5)
- 条件为x => x < 5
, n = 5 所以当condition(5)
被称为 x = 5 时,5 <5 是假的 - 返回n
即 5 - 返回
condLoop(x => x < 5)(4)
- 返回 5 作为condLoop(x => x < 5)(5)
的结果
condLoop(x => x < 5)(4)
- 条件为 x => x < 5
, n = 4 使用类似的逻辑添加函数来增加值 - 现在在每次迭代中,您都需要传递condition
和increment
函数(在原始帖子中c
和f
(。
匿名委托声明语法会导致混淆,因此我将用 F# 的函数类型语法重写它。
(int -> bool) -> (int -> int) -> (int -> int)
所以这是一个接受两个函数并返回一个函数的函数。它接受的第一个函数是谓词,第二个可能是映射,最后它返回一个接受 int 以返回 int 的函数。
Loop = (c , f ) => n => c(n) ? Loop(c , f ) ( f (n)): n;
上述签名的实现。正如预期的那样,它需要两个参数,即 c 和 f。我们希望它返回一个函数,这里是:
n => c(n) ? Loop(c,f) (f (n)) : n;
我可以想象Loop(c,f((f (n((部分最让你失望。调用 Loop 的结果是一个接受整数并返回整数的函数。n 是一个整数,f 是一个接受整数并返回整数的函数。就w
而言,它将该整数增加 2。因此,给定 n 为 2,如第一个示例所示,您将 f(n(, 2 + 2 的结果作为新的 n 传递。只要 c(n( 解析为 true,你就会继续迭代,n 每次增加 2,直到大于或等于 10。
"我知道当 c(n( 计算结果为 true 时,此函数返回循环,但我不明白 Loop(c,f( (f(n(( 如何计算" - 该函数不返回Loop
.该函数Loop
,它返回一个Func<int, int>
。
因此,Loop
是一个将两个函数作为输入并返回第三个函数的函数。它具有显示这一点的签名Func<Func<int , bool>, Func<int , int>, Func<int , int>>
。
现在,Loop = null
第一行,以便 when Loop
实际上是在第二行定义的,它可以递归调用自己。
然后,Loop
基本上是一个返回函数n => c(n) ? Loop(c, f)(f(n)) : n
的函数。也就是说,Loop
将返回一个函数,该函数在将来给定n
时将返回Loop(c, f)(f(n))
,当c(n)
true
时返回n
,在false
时返回;
然后w
是参数 n => n < 10
& n => n + 2
时从 Loop
返回函数。
因此,将它们替换为Loop
您可以像这样定义w
:
Func<int, int> w = null;
w = n => n < 10 ? w(n + 2) : n;
现在可以重写为:
int w(int n)
{
while (n < 10)
{
n += 2;
}
return n;
}
希望这种进展很容易看到。