Mathematical Equality for Func

2019-07-22 20:54发布

问题:

I have a Sequence type that implements ISequence. ISequence implements IEnumerable<Element> where Element is another custom type. Currently, my Sequence type stores the instructions for generating the N-th term of a sequence as a Func<int, int>. This is convenient because it allows me to call NTerm(int n) with a simple call to the Func and to create Sequences with a lambda. I would like to avoid changing that approach.

I would like to check equality of two Sequence objects based on equality of the two Funcs. I began browsing around, and there are a few posts that use Expressions to break down lambdas and Funcs for equality, but I'm talking about mathematical equality.

In other words, x => 2 * x should equal c => c * 2, along with any variations of mathematical expressions, such as Math.Pow or more involved operators. If I can get that to work, I can compare Sequences for mathematical equality.

I tried to write my own extension method:

public static bool MathEquals(this Expression<Func<int, int>> f,
     Expression<Func<int, int>> g)

I'm not sure how to go from there. I have some basic defaults written:

if (ReferenceEquals (f, g)) return true;
if (f == null || g == null) return false;
if (f.NodeType != g.NodeType || f.Type != g.Type) return false;

but I need to check the mathematical equality of the two lambda expressions, i.e. the two Func<int, int>s. Can this be done? Does anyone have a solution? Do I need to change my approach for storing the N-th term formula? I'm against checking the output because sequences can be equal for some output and not all.

If I need to post any of the Sequence code, I will.

UPDATE: I've decided to mark Scott's answer as accepted. However, the work is not complete. Check out part two here.

回答1:

There are two parts to your question, "How do I break apart a expression and evaulate it", and "How do I check that two expressions mean the same logical operation".

I don't know how to do the 2nd part, but I do know the first.

What you will need to do is create a ExpressionVisitor and have it walk through each BinaryExpression by overriding VisitBinary and building up a list of all operations.

public class OperationParser : ExpressionVisitor
{
    public OperationParser()
    {
        Expressions = new List<BinaryExpression>();
    }

    public List<BinaryExpression> Expressions { get; private set; }  

    protected override Expression VisitBinary(BinaryExpression b)
    {
        Expressions.Add(b);

        return base.VisitBinary(b);
    }
}

Then you would do

    Expression<Func<int, int>> expression1 = (x) => x + 2;
    Expression<Func<int, int>> expression2 = (y) => 2 + y;

    var parser1 = new OperationParser();
    parser1.Visit(expression1);

    var parser2 = new OperationParser();
    parser2.Visit(expression2);

    //TODO: write a way to compare parser1.Expressions to parser2.Expressions to see if they "mean the same thig"

You just need to fill in the TODO with "your second question"