与 C# 中的 Lambda/LINQ 表达式混淆的高级函数
High Level Function Confusion with Lambda/LINQ expressions in C#
不确定如何描述这个问题,所以标题可能有误。
正在阅读一些代码示例并对以下 return 函数感到困惑:
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) 的计算结果为真时,这个函数 return 循环,但我不明白 Loop(c,f) (f(n)) 是如何计算的 - 是他们都被传回循环?我已经在 Linqpad 中尝试了 运行 转储,但我只是不明白那位是如何 运行。
任何帮助将不胜感激,明白这可能是一个愚蠢的问题!
C#的匿名委托声明语法容易混淆,所以我打算用F#的函数类型语法重写。
(int -> bool) -> (int -> int) -> (int -> int)
所以这是一个有两个函数的函数,return是一个函数。它接受的第一个函数是一个谓词,第二个可能是一个映射,最后它 return 是一个接受 int 到 return int 的函数。
Loop = (c , f ) => n => c(n) ? Loop(c , f ) ( f (n)): n;
上面签名的实现。正如预期的那样,它有两个参数,即 c 和 f。我们希望它是 return 一个函数,这里是:
n => c(n) ? Loop(c,f) (f (n)) : n;
我可以想象 Loop(c,f) (f (n)) 部分最让您失望。调用 Loop 的结果是一个接受整数和 returns 整数的函数。 n 是一个整数,f 是一个接受整数和 returns 整数的函数。在 w
的术语中,它将该整数递增 2。因此,给定 n 为 2,如在第一个示例中一样,您将传递 f(n) 的结果 2 + 2 作为新的 n。只要c(n)为真,就继续迭代,n每次递增2,直到大于等于10。
尝试理解它的一种方法是从小处着手:基本循环 1-10 和 +1 增量。
Func<int,int> basicLoop = null;
basicLoop = n => n < 10 ? basicLoop(n+1) : n;
这很简单 - basicLoop
是基于参数 n
returns n
(对于 n >= 10)或使用递增参数调用自身的函数。所以 basicLoop(8)
计算为:
basicLoop(8)
8 < 10,所以调用 basicLoop(8+1)
得到结果
basicLoop(9)
9 < 10,所以调用 basicLoop(9+1)
得到结果
basicLoop(10)
10 == 10,所以 returns n
即 10.
basicLoop(9)
得到结果 10(来自 basicLoop(10)
)并且 returns 它
basicLoop(8)
得到结果 10(来自 basicLoop(9)
)并且 returns 它
现在我们要将条件作为参数传递给循环。这意味着我们的 "loop" Func
将需要在每次迭代中传递该条件:
该条件的类型显然是(类似于 n<10
)- Func<int, bool>
。所以现在我们有了一些东西,它以 Func<int,bool>
作为参数并且 returns 与我们原来的 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
函数,当您将条件传递给它时,returns 相当于 basicLoop
。幸运的是,我们的条件在迭代之间不会改变,我们已经有了它——condLoop(condition)
等价于 basicLoop
。把它们放在一起:
condLoop = (condition) =>
n => condition(n) ?
condLoop(condition) (n + 1) :
n;
通过调用进行跟踪 condLoop(x => x < 5)(4)
condLoop(x => x < 5)(4)
- 条件为 x => x < 5
,n = 4 所以当调用 condition(4)
时 x = 4,4 < 5 为真 - 以相同条件调用 condLoop
并增加 n - condLoop(x => x < 5)(4 + 1)
得到结果
condLoop(x => x < 5)(5)
- 条件是 x => x < 5
, n = 5 所以当 condition(5)
被调用时 x = 5, 5 < 5 是 false - 返回 n
即 5
- 返回
condLoop(x => x < 5)(4)
- 作为 condLoop(x => x < 5)(5)
的结果返回 5
使用类似的逻辑添加函数来增加值 - 在每次迭代中,现在您需要传递 condition
和 increment
函数(c
和 f
在原始 post).
"I understand that this function is returning the Loop when c(n) evaluates to true, but I don't understand how Loop(c,f) (f(n)) evaluates" - 该函数没有 return Loop
。函数 是 Loop
而它 return 是 Func<int, int>
.
因此,Loop
是一个将两个函数作为输入的函数,return 是第三个函数。它的签名 Func<Func<int , bool>, Func<int , int>, Func<int , int>>
表明了这一点。
现在,Loop = null
在第一行,这样当 Loop
实际上在第二行定义时,它可以递归地调用自己。
那么,Loop
基本上就是return函数n => c(n) ? Loop(c, f)(f(n)) : n
的一个函数。也就是说,Loop
将 return 一个函数,如果将来给定一个 n
,当 c(n)
是 [=25= 时,它将 return Loop(c, f)(f(n))
] 和 n
当它是 false
;
w
是来自 Loop
的 return 函数,当参数为 n => n < 10
& n => n + 2
.
因此,将 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;
}
希望这种进步是显而易见的。
不确定如何描述这个问题,所以标题可能有误。
正在阅读一些代码示例并对以下 return 函数感到困惑:
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) 的计算结果为真时,这个函数 return 循环,但我不明白 Loop(c,f) (f(n)) 是如何计算的 - 是他们都被传回循环?我已经在 Linqpad 中尝试了 运行 转储,但我只是不明白那位是如何 运行。
任何帮助将不胜感激,明白这可能是一个愚蠢的问题!
C#的匿名委托声明语法容易混淆,所以我打算用F#的函数类型语法重写。
(int -> bool) -> (int -> int) -> (int -> int)
所以这是一个有两个函数的函数,return是一个函数。它接受的第一个函数是一个谓词,第二个可能是一个映射,最后它 return 是一个接受 int 到 return int 的函数。
Loop = (c , f ) => n => c(n) ? Loop(c , f ) ( f (n)): n;
上面签名的实现。正如预期的那样,它有两个参数,即 c 和 f。我们希望它是 return 一个函数,这里是:
n => c(n) ? Loop(c,f) (f (n)) : n;
我可以想象 Loop(c,f) (f (n)) 部分最让您失望。调用 Loop 的结果是一个接受整数和 returns 整数的函数。 n 是一个整数,f 是一个接受整数和 returns 整数的函数。在 w
的术语中,它将该整数递增 2。因此,给定 n 为 2,如在第一个示例中一样,您将传递 f(n) 的结果 2 + 2 作为新的 n。只要c(n)为真,就继续迭代,n每次递增2,直到大于等于10。
尝试理解它的一种方法是从小处着手:基本循环 1-10 和 +1 增量。
Func<int,int> basicLoop = null;
basicLoop = n => n < 10 ? basicLoop(n+1) : n;
这很简单 - basicLoop
是基于参数 n
returns n
(对于 n >= 10)或使用递增参数调用自身的函数。所以 basicLoop(8)
计算为:
basicLoop(8)
8 < 10,所以调用basicLoop(8+1)
得到结果basicLoop(9)
9 < 10,所以调用basicLoop(9+1)
得到结果basicLoop(10)
10 == 10,所以 returnsn
即 10.basicLoop(9)
得到结果 10(来自basicLoop(10)
)并且 returns 它basicLoop(8)
得到结果 10(来自basicLoop(9)
)并且 returns 它
现在我们要将条件作为参数传递给循环。这意味着我们的 "loop" Func
将需要在每次迭代中传递该条件:
该条件的类型显然是(类似于 n<10
)- Func<int, bool>
。所以现在我们有了一些东西,它以 Func<int,bool>
作为参数并且 returns 与我们原来的 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
函数,当您将条件传递给它时,returns 相当于 basicLoop
。幸运的是,我们的条件在迭代之间不会改变,我们已经有了它——condLoop(condition)
等价于 basicLoop
。把它们放在一起:
condLoop = (condition) =>
n => condition(n) ?
condLoop(condition) (n + 1) :
n;
通过调用进行跟踪 condLoop(x => x < 5)(4)
condLoop(x => x < 5)(4)
- 条件为x => x < 5
,n = 4 所以当调用condition(4)
时 x = 4,4 < 5 为真 - 以相同条件调用condLoop
并增加 n -condLoop(x => x < 5)(4 + 1)
得到结果condLoop(x => x < 5)(5)
- 条件是x => x < 5
, n = 5 所以当condition(5)
被调用时 x = 5, 5 < 5 是 false - 返回n
即 5- 返回
condLoop(x => x < 5)(4)
- 作为condLoop(x => x < 5)(5)
的结果返回 5
使用类似的逻辑添加函数来增加值 - 在每次迭代中,现在您需要传递 condition
和 increment
函数(c
和 f
在原始 post).
"I understand that this function is returning the Loop when c(n) evaluates to true, but I don't understand how Loop(c,f) (f(n)) evaluates" - 该函数没有 return Loop
。函数 是 Loop
而它 return 是 Func<int, int>
.
因此,Loop
是一个将两个函数作为输入的函数,return 是第三个函数。它的签名 Func<Func<int , bool>, Func<int , int>, Func<int , int>>
表明了这一点。
现在,Loop = null
在第一行,这样当 Loop
实际上在第二行定义时,它可以递归地调用自己。
那么,Loop
基本上就是return函数n => c(n) ? Loop(c, f)(f(n)) : n
的一个函数。也就是说,Loop
将 return 一个函数,如果将来给定一个 n
,当 c(n)
是 [=25= 时,它将 return Loop(c, f)(f(n))
] 和 n
当它是 false
;
w
是来自 Loop
的 return 函数,当参数为 n => n < 10
& n => n + 2
.
因此,将 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;
}
希望这种进步是显而易见的。