/// <summary> /// Creates and returns an implication expression P ⇒ Q. /// As per the definition of implication, <code>Implies(model => model.P, model => model.Q)</code> is exactly equivalent to (though hopefully easier to read than) /// <code> /// model => !model.P || model.Q /// </code> /// </summary> /// <param name="p">The antecedent expression.</param> /// <param name="q">The consequent expression.</param> /// <returns>An implication expression.</returns> public static Expression <Predicate <TModel> > Implies(Expression <Predicate <TModel> > p, Expression <Predicate <TModel> > q) { // We essentially want !p.Body || q.Body, but with the parameter expressions in each replaced with a new singular one. // That's what ParameterReplacer does for us. Note that the name of the parameter from the first is used. Should we // complain if the name of the parameter in the second is different? Seems overkill.. var pr = new ParameterReplacer(p.Parameters[0].Name); return(Expression.Lambda <Predicate <TModel> >( Expression.OrElse( Expression.IsFalse(pr.VisitLambdaBody(p)), pr.VisitLambdaBody(q)), pr.NewParameter)); }
/// <summary> /// Creates and returns an equivalence expression. That is, P ⇔ Q. /// </summary> /// <param name="p"></param> /// <param name="q"></param> /// <returns>An equivalence expression.</returns> public static Expression <Predicate <TModel> > Iff(Expression <Predicate <TModel> > p, Expression <Predicate <TModel> > q) { // Note that we do this as (P ⇒ Q) ∧ (Q ⇒ P) rather than anything shorter (like P == Q) because it means that the expression is already // in conjunctive normal form - to make it easier to apply resolution. See Artifical Intelligence: A Modern Approach or an equivalent // learning resource for details. // There's also probably a more direct way to write this instead doing parameter replacement three times - but going for readability rather // than efficiency for the moment.. var pr = new ParameterReplacer(p.Parameters[0].Name); var clause1 = Implies(p, q); var clause2 = Implies(q, p); return(Expression.Lambda <Predicate <TModel> >(Expression.AndAlso(pr.VisitLambdaBody(clause1), pr.VisitLambdaBody(clause2)), pr.NewParameter)); }