【发布时间】:2014-03-21 16:58:13
【问题描述】:
我研究了 Y Combinator(使用 c# 5.0),当这个方法时我感到很惊讶:
public static Func<T1, Func<T2, TOut>> Curry<T1, T2, TOut> ( this Func<T1, T2, TOut> f)
{
return a => b => f(a, b);
}
...被编译器翻译成这样:
public static Func<T1, Func<T2, TOut>> Curry<T1, T2, TOut>(this Func<T1, T2, TOut> f)
{
first<T1, T2, TOut> local = new first<T1, T2, TOut>();
local.function = f;
return new Func<T1, Func<T2, TOut>>(local.Curry);
}
private sealed class first<T1, T2, TOut>
{
private sealed class second
{
public first<T1, T2, TOut> ancestor;
public T1 firstParameter;
public TOut Curry(T2 secondParameter)
{
return ancestor.function(firstParameter, secondParameter);
}
}
public Func<T1, T2, TOut> function;
public Func<T2, TOut> Curry(T1 firstParameter)
{
second local = new second();
local.ancestor = this;
local.firstParameter = firstParameter;
return new Func<T2, TOut>(local.Curry);
}
}
因此,当我们使用引用 second.Curry 的委托时,第二类是嵌套的,第一类不可用于垃圾收集。同时,我们在头等舱中所需要的只是功能。也许我们可以将它(委托)复制到第二类,然后可以收集第一类?是的,我们也应该做二等非嵌套,但似乎没关系。据我所知,代表是“按值”复制的,所以我可以建议它很慢,但同时我们复制 firstParameter?!那么,可能有人可以解释一下,为什么编译器会做所有这些事情?) 我谈论这样的事情:
private sealed class first<T1, T2, TOut>
{
public Func<T1, T2, TOut> function;
public Func<T2, TOut> Curry(T1 firstParameter)
{
second<T1, T2, TOut> local = new second<T1, T2, TOut>();
local.function = function;
local.firstParameter = firstParameter;
return new Func<T2, TOut>(local.Curry);
}
}
public sealed class second<T1, T2, TOut>
{
public T1 firstParameter;
public Func<T1, T2, TOut> function;
public TOut Curry(T2 secondParameter)
{
return function(firstParameter, secondParameter);
}
}
【问题讨论】:
-
你需要的不仅仅是函数,你正在关闭参数
a,所以你需要存储它。 -
@SergeyBerezovskiy:Currying 允许您将两个参数的函数转换为一个参数的函数,该函数返回一个参数的函数。例如,假设您有一个函数
add,即(a,b)=>a+b。通过柯里化你有一个函数makeAdder,它接受一个数字并返回一个将这个数字加到一个数字上的函数。 -
@SergeyBerezovskiy 看起来像 en.wikipedia.org/wiki/Currying 的标准实现代码可能看起来像
var add5 = Add.Curry(5)。 -
Alexei,第二个类有祖先字段,所以我们的第一个类在第二个存在和第二个存在之前不能被收集,因为我们的代表在 second.Curry 上有引用
-
@AlexeiLevenkov:我认为 OP 指出
second只使用ancestor来获取function,那么为什么不让second坚持function而不是坚持转到ancestor?他的想法是,ancestor可以更早收集。
标签: c# performance compiler-construction lambda