I have the following rules looking for facts in a database with certain dates:
preceding(ID,Date,Category,Preceding) :-
setof([ID,D,Category,Amount], row(ID,D,Category,Amount), Preceding),
D @< Date.
after(ID,After,Category,Rows) :-
setof([ID,D,Category,Amount], row(ID,D,Category,Amount), Rows),
D @> After.
preceding works just fine:
?- preceding(ID,'2020-01-01',Category,Preceding).
Preceding = [[100002, '2018-11-05', 'CEM', 500.0], [100007, '2018-11-01', 'Consulting Package', 100000.0], [100011, '2017-10-25', 'CEM', 500.0], [100012, '2017-10-15', 'CEM', 500.0], [100012, '2017-10-25', 'Tuition Package', 5543.37], [100013, '2017-10-15', 'CEM'|...], [100013, '2017-11-08'|...], [100014|...], [...|...]|...].
But after doesn't work:
?- after(ID,'2000-01-01',Category,Rows).
false.
Note that the only difference between these two rules is the @< vs. @> operator. I've tried changing the order of the operands around, and changing the order of the statements in the rule, but it doesn't work.
I've also tried reversing the logic:
after(ID,After,Category,Rows) :-
setof([ID,D,Category,Amount], row(ID,D,Category,Amount), Rows),
After @< D.
This doesn't work either.
I even wrote a separate rule to check whether I could make the operator work:
isafter(A,B) :- A @> B.
This works. But replacing D @> After with isafter(D,After) in my after rule doesn't work.
Why is it that making a "before" condition works, but an "after" condition doesn't? And can you make my after rule work please? :)
(I actually want to write a between function that uses both "before" and "after" conditions, but I realised that the exact problem with my between function was @>.)
Does it? You call it with variables
IDandCategorythat do not get bound by the query. This is already an indication that it doesn't do exactly what you may have had in mind. Let's look inside.Using this database:
let's just look at the
setofgoal inside your definitions:The
Precedinglist is computed as we expect it to, but what aboutDand the other variables? They don't get bound. We can make this even more explicit:Something of the form
_5070is SWI-Prolog's notation for "unbound variable". SoDis a variable after thesetofcall. Did you expect it to be bound to one of the dates in thePrecedinglist? Which one?So now we can get closer to the issue of
@>vs.@<. What you are doing is comparing an atom like'2020-01-01'to a variable.@>and@<implement what is called the "standard order of terms". In this order, variables are always considered smaller than atoms:And this is why your
@<always succeeds and your@>always fails. To fix this you need to go back and think again about what exactly you want yoursetofcall to do.