I can't figure out how to write the answer to the question. Any help is appreciated. I understand the logic behind it but can't find the correct syntax.
Define a rule happened_before(X,Y) which defines the relation that event X happened before event Y, and use it to obtain all such pairs of events. You will need to use the system predicate <, less than. For example ?- (5 < 7). succeeds. Suitably instantiated variables can be used either side of < instead of numbers. Start the rule with happened_before(X,Y) :-.
my attempt is as follows:
event(battle_of_hastings, 1066).
event(plague_of_london, 1665).
event(fire_of_london, 1666).
event(man_on_the_moon, 1969).
happened_before(X,Y) :-
(Event1, Y1),
(Event2, Y2).
Y1 < Y2.
You are close.
What you desired is
happened_before(Event1,Event2) :-
event(Event1, Y1),
event(Event2, Y2),
Y1 < Y2.
Prolog is about syntactic unification which can often be thought simply as matching terms.
In this case a line like event(Event1, Y1)
which is in itself is known as a goal needs to match against something to work (succeed). You have facts which you are trying to match.
So
event
(the functor) in event(Event1, Y1)
needs to match with event
in a fact like event(battle_of_hastings, 1066).
.
Then the number of arguments needs to match which in this case they both have 2 arguments.
Now since the goal has two variables (begin with upper case letter) they will match (unify) with the corresponding parts of the facts. Thus
Event1
unifies with battle_of_hastings
and
Y1
unifies with 1066
.
The reason you need to match on the functor is because if you have a fact like
time(battle_of_hastings, 1066).
and a query like you had (Event1,Y1)
with the way you intended it to work without a functor, the match would succeed on unifying when you did not want it too.
Another way to think about unification of terms that reinforces the need to check the functor when unifying is this variation of Prolog terms from days gone by
event(battle_of_hastings, 1066)
in the past would be
(event, battle_of_hastings, 1066)
where the name was the first argument and it was thus apparent that it also needed to be unified.
Here is all the code with test cases.
event(battle_of_hastings, 1066).
event(plague_of_london, 1665).
event(fire_of_london, 1666).
event(man_on_the_moon, 1969).
happened_before(Event1,Event2) :-
event(Event1, Y1),
event(Event2, Y2),
Y1 < Y2.
:- begin_tests(happened_before).
happened_before_test_case_generator(success,plague_of_london,fire_of_london).
happened_before_test_case_generator(success,plague_of_london,man_on_the_moon).
happened_before_test_case_generator(fail,plague_of_london,plague_of_london).
happened_before_test_case_generator(fail,fire_of_london,plague_of_london).
happened_before_test_case_generator(fail,man_on_the_moon,plague_of_london).
test(01,[forall(happened_before_test_case_generator(success,Event1,Event2))]) :-
happened_before(Event1,Event2).
test(02,[fail,forall(happened_before_test_case_generator(fail,Event1,Event2))]) :-
happened_before(Event1,Event2).
:- end_tests(happened_before).
Example run of tests.
?- run_tests.
% PL-Unit: happened_before ..... done
% All 5 tests passed
true.