2

これが厳密にカリー化されているかどうかはわかりませんが、基本的には次のことを達成したいと考えています。与えられたExpression:

Expression<Func<T1, T2, TResult>> expression

引数の1 つExpressionを渡し、このパラメーターの値が固定されている対応するものを生成したいと考えています。expression結果の式は、パラメーターが 1 つ少ないことを除いて、 と機能的に同等である必要があります。

この結果の式は次のようになります。

Expression<Func<T2, TResult>> curriedExpression;

私はこれを試しましたがExpression、ラムダ式に暗黙的に変換されないため、機能しません:

curriedExpression = b => expression(fixedValueForT1, b);

curriedExpressionへの呼び出しを含めないでくださいexpression。固定値を除いて、重複したロジックを含める必要があります。

それが理にかなっていることを願っています。これがあいまいであるか、よく説明されていない場合はお知らせください。

4

3 に答える 3

3

ExpressionVisitor簡単な方法でクラスから派生できると思います。ここに概念実証があります - それは過度に単純化されているかもしれませんが、私はそれがあなたが求めているものだと思います:

using System;
using System.Linq.Expressions;

class Test
{
    static void Main()
    {
        Expression<Func<int, int, int>> original = (x, y) => MethodX(x) + MethodY(y);
        Console.WriteLine("Original: {0}", original);
        var partiallyApplied = ApplyPartial(original, 10);
        Console.WriteLine("Partially applied: {0}", partiallyApplied);
    }

    static int MethodX(int x)
    {
        return x + 1;
    }

    static int MethodY(int x)
    {
        return -x;
    }

    static Expression<Func<T2, TResult>> ApplyPartial<T1, T2, TResult>
        (Expression<Func<T1, T2, TResult>> expression, T1 value)
    {
        var parameter = expression.Parameters[0];
        var constant = Expression.Constant(value, parameter.Type);
        var visitor = new ReplacementVisitor(parameter, constant);
        var newBody = visitor.Visit(expression.Body);
        return Expression.Lambda<Func<T2, TResult>>(newBody, expression.Parameters[1]);
    }
}

class ReplacementVisitor : ExpressionVisitor
{
    private readonly Expression original, replacement;

    public ReplacementVisitor(Expression original, Expression replacement)
    {
        this.original = original;
        this.replacement = replacement;
    }

    public override Expression Visit(Expression node)
    {
        return node == original ? replacement : base.Visit(node);
    }
}

出力:

Original: (x, y) => (MethodX(x) + MethodY(y))
Partially applied: y => (MethodX(10) + MethodY(y))
于 2013-10-03T06:11:54.917 に答える
0

これは @jon-skeet 実装の代替であり、次の長所/短所があります。

長所:

  • 入力式には、任意の型の 0..n 引数を含めることができます。
  • 置き換えられたもののインデックスを指定することにより、これらのパラメーターのいずれかをカリー化できます。

短所:

  • コンパイル時の型の安全性が失われます (入力式にジェネリック パラメーターがなく、インデックスが範囲外である可能性があり、置換は ですobject)。
  • 返されるラムダ式の型を指定する必要があります。
private Expression<TLambda> Curry<TLambda>(
    LambdaExpression searchExpression, 
    int replacedParameterIndex, 
    object replacement)
{
    var parameter = searchExpression.Parameters[replacedParameterIndex];
    var constant = Expression.Constant(replacement, parameter.Type);
    var visitor = new ReplacementVisitor(parameter, constant);
    var newBody = visitor.Visit(searchExpression.Body);
    var lambda = Expression.Lambda<TLambda>(newBody, searchExpression.Parameters.Except(new[] { parameter }));

    return lambda;
}

@jon-skeet の例では、次のように使用します。

var partiallyApplied = Curry<int, int>(original, 0, 10);
于 2014-03-10T09:12:06.710 に答える