When organizing rules for NRules, is it necessary to only have 1 When/Then group in a file?
I have one rule that looks at 3 conditions (fact matches), is flagA = false, inputA = one of a list of values, and inputB = a single value. When all true, set flagA to true. I got that one working,then wanted to add the second rule.
The second rule is when flagA is false and flagB is true then set flagA to true.
Do these two rules need to be in separate .cs files or can they be together in one.
I looked at the ".Or" option, but I am not good enough with fluent to figure out what it is doing.
Thanks for your help,
Toom
In NRules an instance of a class that inherits from NRules.Fluent.Dsl.Rule is one rule. You can put multiple rule classes in one .cs file or different files, it does not matter - each class is still a separate rule.
In that rule class, you normally would specify When and Then sections only once. If you specify them multiple times, all conditions would still be combined into a single set using and group. Actions would also be merged into a single set.
So:
public class Rule1: Rule
{
public override void Define()
{
When()
.Match<A>();
Then()
.Do(_ => X());
When()
.Match<B>();
Then()
.Do(_ => Y());
}
}
is exactly the same as
public class Rule1: Rule
{
public override void Define()
{
When()
.Match<A>()
.Match<B>();
Then()
.Do(_ => X())
.Do(_ => Y());
}
}
In other words, both examples above create just a single rule that matches both A and B, and if both those facts match, then both X and Y methods are executed.
If you want that to be two independent rules, then put those different When/Then sections into different rule classes.
public class Rule1: Rule
{
public override void Define()
{
When()
.Match<A>();
Then()
.Do(_ => X());
}
}
public class Rule2: Rule
{
public override void Define()
{
When()
.Match<B>();
Then()
.Do(_ => Y());
}
}
UPDATE:
If you wanted to connect conditions A and B with an OR, you could do it like below. Here the rule will fire if ((A OR B) AND C):
public class Rule1: Rule
{
public override void Define()
{
When()
.Or(x => x
.Match<A>()
.Match<B>())
.Match<C>();
Then()
.Do(_ => Z());
}
}
Related
I am migrating my prototype from a listener to a visitor pattern. In the prototype, I have a grammar fragment like this:
thingList: thing+ ;
thing
: A aSpec # aRule
| B bSpec # bRule
;
Moving to a visitor pattern, I am not sure how I write visitThingList. Every visitor returns a specializes subclass of "Node", and I would love somehow when to be able to write something like this, say a "thingList" cares about the first thing in the list some how ...
visitThingList(cx: ThingListContext): ast.ThingList {
...
const firstThing = super.visit(cx.thing(0));
The problem with this is in typing. Each visit returns a specialized type which is a subclass of ast.Node. Because I am using super.visit, the return value will be the base class
of my node tree. However, I know because I am looking at the grammar
and because I wrote both vistARule and visitBRule that the result of the visit will be of type ast.Thing.
So we make visitThingList express it's expectation with cast ...
visitThingList(cx: ThingListContext): ast.ThingList {
const firstThing = super.visit(cx.thing(0));
if (!firstThing instanceof ast.Thing) {
throw "no matching visitor for thing";
}
// firstThing is now known to be of type ast.Thing
...
In much of my translator, type problems with ast Nodes are a compile time issue, I fix them in my editor. In this case, I am producing a more fragile walk, which will only reveal the fragility at runtime and then only with certain inputs.
I think I could change my grammar, to make it possible to encode the
type expectations of vistThingList() by creating a vistThing() entry point
thingList: thing+ ;
thing: aRule | bRule;
aRule: A aSpec;
bRule: B bSpec;
With vistThing() typed to match the expectation:
visitThing(cx: ThingContext): ast.Thing { }
visitThingList(cx: ThingListContext) {
const firstThing: ast.Thing = this.visitThing(cx.thing(0));
Now visitThingList can call this.visitThing() and the type enforcement of making sure all rules that a thing matches return ast.Thing belongs to visitThing(). If I do create a new rule for thing, the compiler will force me to change the return type of visitThing() and if I make it return something which is NOT a thing, visitThingList() will show type errors.
This also seems wrong though, because I don't feel like I should have to change my grammar in order to visit it.
I am new to ANTLR and wondering if there is a better pattern or approach to this.
When I was using the listener pattern, I wrote something like:
enterThing(cx: ThingContext) { }
enterARule(cx : ARuleContext) { }
enterBRule(cx : BRuleContext) { }
Not quite: for a labeled rule like thing, the listener will not contain enterThing(...) and exitThing(...) methods. Only the enter... and exit... methods for the labels aSpec and bSpec will be created.
How would I write the visitor walk without changing the grammar?
I don't understand why you need to change the grammar. When you keep the grammar like you mentioned:
thingList: thing+ ;
thing
: A aSpec # aRule
| B bSpec # bRule
;
then the following visitor could be used (again, there is no visitThing(...) method!):
public class TestVisitor extends TBaseVisitor<Object> {
#Override
public Object visitThingList(TParser.ThingListContext ctx) {
...
}
#Override
public Object visitARule(TParser.ARuleContext ctx) {
...
}
#Override
public Object visitBRule(TParser.BRuleContext ctx) {
...
}
#Override
public Object visitASpec(TParser.ASpecContext ctx) {
...
}
#Override
public Object visitBSpec(TParser.BSpecContext ctx) {
...
}
}
EDIT
I do not know how, as i iterate over that, to call the correct visitor for each element
You don't need to know. You can simply call the visitor's (super) visit(...) method and the correct method will be invoked:
class TestVisitor extends TBaseVisitor<Object> {
#Override
public Object visitThingList(TParser.ThingListContext ctx) {
for (TParser.ThingContext child : ctx.thing()) {
super.visit(child);
}
return null;
}
...
}
And you don't even need to implement all methods. The ones you don't implement, will have a default visitChildren(ctx) in them, causing (as the name suggests) all child nodes under them being traversed.
In your case, the following visitor will already cause the visitASpec and visitBSpec being invoked:
class TestVisitor extends TBaseVisitor<Object> {
#Override
public Object visitASpec(TParser.ASpecContext ctx) {
System.out.println("visitASpec");
return null;
}
#Override
public Object visitBSpec(TParser.BSpecContext ctx) {
System.out.println("visitBSpec");
return null;
}
}
You can test this (in Java) like this:
String source = "... your input here ...";
TLexer lexer = new TLexer(CharStreams.fromString(source));
TParser parser = new TParser(new CommonTokenStream(lexer));
TestVisitor visitor = new TestVisitor();
visitor.visit(parser.thingList());
I am writing a method in which i am using async prog.
var tasks = new List<Task<List<SomeClass>>>();
tasks.Add(this.Method1());
tasks.Add(this.Method2());
var results = await Task.WhenAll(tasks).ConfigureAwait(false);
i want distinct records from this result. How to achieve that.
currently i have written
return results.SelectMany(s => s).GroupBy(x => x.Name).Select(x => x.FirstOrDefault()).ToList();
But i am not sure with SelectMany, will this give correct result.
SelectMany(s => s) is a "flatten" operation. It takes a sequence of sequences and flattens them to a single sequence.
The LINQ "distinct" operator is called Distinct. If your SomeClass overrides equality to be based on Name, then that's all you need:
return results.SelectMany(s => s).Distinct().ToList();
But if SomeClass doesn't define equality that way, you'll need to do another kind of distinct.
One option is to use the Distinct overload that takes an equality comparer. Then you can pass in an equality comparer that determines equality by Name. To do this, first define an equality comparer:
public sealed class NameEqualityComparer: IEqualityComparer<SomeClass>
{
public int GetHashCode(SomeClass obj) => EqualityComparer<string>.Default.GetHashCode(obj.Name);
public bool Equals(SomeClass x, SomeClass y) => EqualityComparer<string>.Default.Equals(x.Name, y.Name);
}
and then you can invoke the correct overload:
return results.SelectMany(s => s).Distinct(new NameEqualityComparer()).ToList();
I have a library that helps define custom comparers (properly handling all edge cases), which I prefer to use for things like this. With the Nito.Comparers library, you don't need to define a custom NameEqualityComparer; instead, you can define comparers in-line like this:
return results.SelectMany(s => s).Distinct(b => b.EquateBy(x => x.Name)).ToList();
or separately, if desired:
var comparer = EqualityComparerBuilder.For<SomeClass>().EquateBy(x => x.Name);
return results.SelectMany(s => s).Distinct(comparer).ToList();
A completely different option is to add a new "Distinct-By" operator that acts the way you want. This is part of MoreLINQ or you can add it yourself:
public static IEnumerable<T> DistinctBy<T, TKey>(this IEnumerable<T> #this, Func<T, TKey> selector)
{
var keys = new HashSet<TKey>();
foreach (var item in #this)
{
if (keys.Add(selector(item)))
yield return item;
}
}
Then you can use the new operator like this:
return results.SelectMany(s => s).DistinctBy(x => x.Name).ToList();
All of these options are more efficient than grouping.
I want to run a rule based on the result of a previous rule. How can I achieve this functionality using forward chaining? I don't want to create a different class object for each rule to achieve forward chaining.
Here in this example an InstantDiscount object is created just for this one rule to achieve forward chaining.
public class PreferredCustomerDiscountRule : Rule
{
public override void Define()
{
Customer customer = null;
IEnumerable<Order> orders = null;
Double total = Double.NaN;
When()
.Match<Customer>(() => customer, c => c.IsPreferred)
.Query(() => orders, x => x
.Match<Order>(
o => o.Customer == customer,
o => o.IsOpen)
.Collect())
.Let(() => total, () => orders.Sum(x => x.Amount))
.Having(() => total > 1000);
Then()
.Yield(_ => new InstantDiscount(customer, total * 0.05));
}
}
public class PrintInstantDiscountRule : Rule
{
public override void Define()
{
InstantDiscount discount = null;
When()
.Match(() => discount);
Then()
.Do(_ => Console.WriteLine("Customer {0} has instant discount of {1}",
discount.Customer.Name, discount.Amount));
}
}
Forward chaining is the process where one rule changes the working memory of the rules engine in such a way as to activate some other rules. This can be achieved by inserting new facts into the rules engine (using Yield or IContext.Insert in NRules), or by changing some of the existing facts (using IContext.Update).
Here is the original example, reformulated to attach the discount to the Customer fact, and then update that fact to achieve forward chaining.
public class PreferredCustomerDiscountRule : Rule
{
public override void Define()
{
Customer customer = null;
IEnumerable<Order> orders = null;
Double total = Double.NaN;
When()
.Match<Customer>(() => customer, c => c.IsPreferred, c => !c.DiscountPercent.HasValue)
.Query(() => orders, x => x
.Match<Order>(
o => o.Customer == customer,
o => o.IsOpen)
.Collect())
.Let(() => total, () => orders.Sum(x => x.Amount))
.Having(() => total > 1000);
Then()
.Do(ctx => ApplyDiscount(customer, 0.05))
.Do(ctx => ctx.Update(customer));
}
private static void ApplyDiscount(Customer customer, double discount)
{
customer.DiscountPercent = discount;
}
}
public class DicsountNotificationRule : Rule
{
public override void Define()
{
Customer customer = null;
When()
.Match(() => customer, c => c.DiscountPercent.HasValue);
Then()
.Do(_ => Console.WriteLine("Customer {0} has instant discount of {1}%",
customer.Name, customer.DiscountPercent));
}
}
When forward chaining by updating existing facts, care must be taken to not re-activate the rule that updated the fact, to avoid undesirable recursion. There are several mechanisms to control recursion in NRules:
Write conditions in such a way that the update invalidates conditions of the rule (this is what we did in the above example; once the discount is set, the rule will no longer match)
Use Repeatability attribute on the rule to prevent re-firing
Use agenda filters to only activate the rule when certain changes occur in the matching facts.
The later two options are described in NRules documentation.
I'm doing some research about EF and came across a function that accepts
Func<IQueryable<Student>, IOrderedQueryable<Student>>
and just wondering how to call that function that accepts that kind of parameter?
imagine function is something like that, and you've got a property Id in Student class.
public static class Helper {
public static void Test(Func<IQueryable<Student>, IOrderedQueryable<Student>> param)
{
var test = 0;
}
}
then you could use it this way
var student = new List<Student>().AsQueryable();//non sense, just for example
Helper.Test(m => student.OrderBy(x => x.Id));
m => student.OrderBy(x => x.Id) is a
Func<IQueryable<Student>, IOrderedQueryable<Student>>
(IQueryable<student> as parameter, returning a IOrderedQueryable<Student>)
or just
Helper.Test(m => m.OrderBy(x => x.Id));
In fact this doesn't make much sense without a "real" function...
define a method.
public IOrderedQueryable<Student> OrderingMethod(IQueryable<Student> query)
{
return query.OrderBy(student => student.Name);
}
Now this assignment is legal:
Func<IQueryable<Student>, IOrderedQueryable<Student>> orderingFunc = this.OrderingMethod;
And now that you have it in a variable, it's easy to pass it to the method.
You could also do it all inline:
Func<IQueryable<Student>, IOrderedQueryable<Student>> orderingFunc =
query => query.OrderBy(student => student.Name);
I am in the middle of a refactoring cycle where I converted some extension methods that used to look like this:
public static IQueryable<Family> FilterOnRoute(this IQueryable<Family> families, WicRoute route)
{
return families.Where(fam => fam.PODs
.Any(pod => pod.Route.RouteID == route.RouteID));
}
to a more fluent implementation like this:
public class SimplifiedFamilyLinqBuilder
{
private IQueryable<Family> _families;
public SimplifiedFamilyLinqBuilder Load(IQueryable<Family> families)
{
_families = families;
return this;
}
public SimplifiedFamilyLinqBuilder OnRoute(WicRoute route)
{
_families = _families.Where(fam => fam.PODs
.Any(pod => pod.Route.RouteID == route.RouteID));
return this;
}
public IQueryable<Family> AsQueryable()
{
return _families;
}
}
which I can call like this: (note this is using Linq-to-Nhibernate)
var families =
new SimplifiedFamilyLinqBuilder()
.Load(session.Query<Family>())
.OnRoute(new WicRoute() {RouteID = 1})
.AsQueryable()
.ToList();
this produces the following SQL which is fine with me at the moment: (of note is that the above Linq is being translated to a SQL Query)
select ... from "Family" family0_
where exists (select pods1_.PODID from "POD" pods1_
inner join Route wicroute2_ on pods1_.RouteID=wicroute2_.RouteID
where family0_.FamilyID=pods1_.FamilyID
and wicroute2_.RouteID=#p0);
#p0 = 1
my next effort in refactoring is to move the query part that deals with the child to another class like this:
public class SimplifiedPODLinqBuilder
{
private IQueryable<POD> _pods;
public SimplifiedPODLinqBuilder Load(IQueryable<POD> pods)
{
_pods = pods;
return this;
}
public SimplifiedPODLinqBuilder OnRoute(WicRoute route)
{
_pods = _pods.Where(pod => pod.Route.RouteID == route.RouteID);
return this;
}
public IQueryable<POD> AsQueryable()
{
return _pods;
}
}
with SimplifiedFamilyLinqBuilder changing to this:
public SimplifiedFamilyLinqBuilder OnRoute(WicRoute route)
{
_families = _families.Where(fam =>
_podLinqBuilder.Load(fam.PODs.AsQueryable())
.OnRoute(route)
.AsQueryable()
.Any()
);
return this;
}
only I now get this error:
Remotion.Linq.Parsing.ParserException : Cannot parse expression 'value(Wic.DataTests.LinqBuilders.SimplifiedPODLinqBuilder)' as it has an unsupported type. Only query sources (that is, expressions that implement IEnumerable) and query operators can be parsed.
I started to implement IQueryable on SimplifiedPODLinqBuilder(as that seemed more logical than implementing IEnumberable) and thought I would be clever by doing this:
public class SimplifiedPODLinqBuilder : IQueryable
{
private IQueryable<POD> _pods;
...
public IEnumerator GetEnumerator()
{
return _pods.GetEnumerator();
}
public Expression Expression
{
get { return _pods.Expression; }
}
public Type ElementType
{
get { return _pods.ElementType; }
}
public IQueryProvider Provider
{
get { return _pods.Provider; }
}
}
only to get this exception (apparently Load is not being called and _pods is null):
System.NullReferenceException : Object reference not set to an instance of an object.
is there a way for me to refactor this code out that will parse properly into an expression that will go to SQL?
The part fam => _podLinqBuilder.Load(fam.PODs.AsQueryable() is never going to work, because the linq provider will try to parse this into SQL and for that it needs mapped members of Family after the =>, or maybe a mapped user-defined function but I don't know if Linq-to-Nhibernate supports that (I never really worked with it, because I still doubt if it is production-ready).
So, what can you do?
To be honest, I like the extension methods much better. You switched to a stateful approach, which doesn't mix well with the stateless paradigm of linq. So you may consider to retrace your steps.
Another option: the expression in .Any(pod => pod.Route.RouteID == route.RouteID)); could be paremeterized (.Any(podExpression), with
OnRoute(WicRoute route, Expression<Func<POD,bool>> podExpression)
(pseudocode).
Hope this makes any sense.
You need to separate methods you intend to call from expressions you intend to translate.
This is great, you want each of those methods to run. They return an instance that implements IQueryable<Family> and operate on that instance.
var families = new SimplifiedFamilyLinqBuilder()
.Load(session.Query<Family>())
.OnRoute(new WicRoute() {RouteID = 1})
.AsQueryable()
.ToList();
This is no good. you don't want Queryable.Where to get called, you want it to be an expression tree which can be translated to SQL. But PodLinqBuilder.Load is a node in that expression tree which can't be translated to SQL!
families = _families
.Where(fam => _podLinqBuilder.Load(fam.PODs.AsQueryable())
.OnRoute(route)
.AsQueryable()
.Any();
You can't call .Load inside the Where expression (it won't translate to sql).
You can't call .Load outside the Where expression (you don't have the fam parameter).
In the name of "separation of concerns", you are mixing query construction methods with query definition expressions. LINQ, by its Integrated nature, encourages you to attempt this thing which will not work.
Consider making expression construction methods instead of query construction methods.
public static Expression<Func<Pod, bool>> GetOnRouteExpr(WicRoute route)
{
int routeId = route.RouteID;
Expression<Func<Pod, bool>> result = pod => pod.Route.RouteID == route.RouteID;
return result;
}
called by:
Expression<Func<Pod, bool>> onRoute = GetOnRouteExpr(route);
families = _families.Where(fam => fam.PODs.Any(onRoute));
With this approach, the question is now - how do I fluidly hang my ornaments from the expression tree?