18 ms·
chielk's solution is good, but it doesn't have to be as complex. You were on the right track with using @> (the "standard order of terms"), which does the right
by tom_mellior 9y ago
chielk's solution is good, but it doesn't have to be as complex. You were on the right track with using @> (the "standard order of terms"), which does the right thing automatically. Here's your fixed definition:
current_at(Entity, C, Start, End, Current) :-
ticker(Entity, C, Start, End),
Start @< Current,
Current @< End.
What you got wrong was the fact that you need to call ticker/4 in the body of your predicate instead of expecting such a term as an argument.
This works with the database you posted:
?- current_at(entity('TimeWarner'), C, S, E, date(2017-05-29)).
C = 'AOL',
S = date(2014-5-1),
E = date(9999-1-1).
- YeGoblynQueenne 9y agoThat's a nice, short answer but t's a bit unsafe, isn't it? The standard order of terms doesn't know anything about dates. The above works because compounds are compared recursively on their arguments. For those less familiar with Prolog, in Prolog terms, a date in a format like 2014-5-1 is a compound term, a predicate -/2 with the operator "-" as a functor and 2 arguments: 2014-5 and 1. The first of those is, again, a compound, also with functor - and two arguments, 2014 and 5. So the entire date is a recursive term. A comparison predicate, like @>/2, etc, will walk over the arguments of this term and compare them as it goes - but since a "date" is not a Prolog type (only "number" and "atom" really are) it will not treat a term meant as a date in any special manner. Which, in the end, means that the following queries are all true: ?- 2014-5-1 @< 9999-1-1. true. ?- 2014-5-0 @< 9999-1-1. true. ?- 2014-5 @< 9999-1-1. true. ?- 2014-50-1 @< 9999-1-1. true. The third query has some merit, but the rest will need some type-checking somewhere above the comparison line, to make sure you're processing dates and not just arbitrary numbers. In that sense, wrapping up dates in a date/1 term, as the OP did, may not be such a bad idea after all - or at the very least one could write a is_date/1 predicate to handle type checking: ?- is_date(2014-5-0). false. ?- is_date(2014-5-1). true. But er, that's left as an exercise to the reader :)
- tom_mellior 9y agoYou're right about the safety, though without a formal specification I think it was just good enough for an HN comment :-)
- YeGoblynQueenne 9y agoSure. Just had to nitpick :)
- zmonx 9y agoTo reason about dates and times in a purely declarative way with Prolog, the best way I have seen is library(julian) by Michael Hendricks: http://mndrix.github.io/julian/ http://mndrix.github.io/julian/ For example: ?- form_time([2014-5-1], T). T = datetime(56778, _5804), _5804 in 0..86399999999999. This uses CLP(FD) constraints to reason about time in a very general way, usable in all direction. For example, you can express "all times after 2014-5-1" as follows: ?- form_time([after(2014-5-1)], T). T = datetime(_1304, _1306), _1304 in 56778..514671, _1346#=86400000000000*_1304+_1306, _1346 in 4905619200000000001..44467660799999999999, _1416#=<_1346+ -1, _1416 in 4905619200000000000..4905705599999999999, 4905619200000000000+_1484#=_1416, _1484 in 0..86399999999999, _1306 in 0..86399999999999.