.net 编译器如何使委托实现惰性计算?

8yparm6h  于 2023-01-14  发布在  .NET
关注(0)|答案(2)|浏览(147)

我正在学习惰性计算,由下面的代码给出

public static Func<R> Map<T, R>(this Func<T> f, Func<T, R> g)
{
   return () => g(f());
}

因为f可能是一个计算量很大的函数来生成T,这就是为什么它被 Package 为Func<T>,但是Map返回() => g(f()),这里f()更像是一个闭包,必须先准备好,所以在我看来f()仍然会在() => g(f())中求值,我知道我的理解是错误的,但是我不知道哪里出了问题,那么编译器是如何启动并使代码仍然是惰性计算的呢(即f()将不会在() => g(f())中被调用?

gorkyyrv

gorkyyrv1#

() => g(f())表示匿名函数,仅此而已。
在声明时不会计算该函数中的任何内容。
f()仅在调用匿名函数时被调用,并且在每次调用匿名函数时被调用。

3ks5zfa0

3ks5zfa02#

() => g(f())是一个lambda expression,它创建了一个匿名函数(实际上是编译器翻译的语法糖-参见@sharplab)。
所以在我看来f()仍然会在() => g(f())中求值
是,当() => g(f())表示的匿名函数将被调用/求值时,即(pseudocde):

Func<_> x = () => g(f()); // nothing is evaluated here
x(); // f and g are evaluted here

所以惰性是通过这样一个事实实现的,即计算将不会在Map被调用时执行,而是在它的结果被调用时执行,这很容易检查副作用。

Func<int> returnsInt = () => 1;
Func<string> mapped = returnsInt.Map(i =>
{
    Console.WriteLine("Inside mapping func");
    return $"Int is: {i}";
});
// nothing printed yet
Console.WriteLine("Before the eval");
Console.WriteLine(mapped());

给出下一个输出:
评估前
内部Map函数
整数为:1

相关问题