How can I curry an Expression into another Expression?

I'm not sure if this is strictly currying, but I'm basically wanting to achieve the following. Given an Expression:

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

I want to pass in one of the arguments and produce a corresponding Expression where the value for this parameter is fixed. The resulting expression should be functionally equivalent to expression except that it should contain one less parameter.

This resulting expression would look something like this:

Expression<Func<T2, TResult>> curriedExpression;

I've tried this, but it doesn't work because an Expression doesn't implicitly convert to a lambda expression:

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

Note that curriedExpression shouldn't contain a call to expression; it should contain duplicated logic except with the fixed value.

I hope that makes sense. Let me know if this is ambiguous or not explained well.

Jon Skeet
people
quotationmark

I think you can just derive from the ExpressionVisitor class in a simple way. Here's a proof of concept - it may be overly simplistic, but I think it's what you're after:

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);
    }
}

Output:

Original: (x, y) => (MethodX(x) + MethodY(y))
Partially applied: y => (MethodX(10) + MethodY(y))

people

See more on this question at Stackoverflow