user3414510
user3414510

Reputation: 55

Why is my Prolog code printing in reverse?

My code in prolog is appearing in the reverse expected order. Here is the code:

room(homermargeroom, donuts).
room(homermargeroom, tv).
room(ensuite, nothing).
room(lisaroom, beer).
room(bartroom, donuts).
room(hallway, nothing).
room(bathroom, nothing).
room(maggieroom, nothing).


/* These are the locations where Bart, Lisa and Maggie are hiding */
hiding(bart, cupboard).
hiding(lisa, ensuite).
hiding(maggie, bathroom).

canHomerGet(Start, End, Item) :- 
    homermove(Start, End),
    canTravelThrough(Start, Item),
    canTravelThrough(End, Item),
    write('Homer moves from '), write(Start), write(' to '), write(End), nl.

canHomerGet(Start, End, Item) :- 
    homermove(Start, Somewhere),
    canTravelThrough(Somewhere, Item),
    canHomerGet(Somewhere, End, Item),
    write('Homer moves from '), write(Start), write(' to '), write(Somewhere), nl.


canTravelThrough(Somewhere, _Item) :-
    room(Somewhere, nothing).

canTravelThrough(Somewhere, Item) :-
    room(Somewhere, tv),
    Item == portableTV.

canTravelThrough(Somewhere, Item) :-
    room(Somewhere, donuts),
    Item == nachos.

canTravelThrough(Somewhere, Item) :-
    room(Somewhere, sistersinlaw),
    Item == blindfold.

canTravelThrough(Somewhere, Item) :-
    room(Somewhere, beer),
    Item == margarita.


canHomerFind(Child, Item) :-
    hiding(Child, Destination),
    canHomerGet(garage, Destination, Item).

Here is the output:

Homer moves from foyer to cupboard
Homer moves from diningroom to foyer
Homer moves from kitchen to diningroom
Homer moves from sidehall to kitchen
Homer moves from garage to sidehall

The way I have written this, I would expect this to print out 'Homer moves from garage to sidehall' fist, and then print that list in the reverse order that it is. Any suggestions on how to fix this?

Upvotes: 1

Views: 272

Answers (1)

Paulo Moura
Paulo Moura

Reputation: 18663

Your definition of the predicate canHomerGet/3 only writes the move output at the end. In the second clause, the recursive call precedes the writing of the move. This makes this predicate non tail-recursive. I.e. the writing of the moves is saving on the implicit recursive stack and then popped from the stack when the call to the predicate succeeds. Thus, the first movement printed is the last one and the last movement printed is the first one.

You could be tempted to solve this problem by modifying the second clause to:

canHomerGet(Start, End, Item) :- 
    homermove(Start, Somewhere),
    canTravelThrough(Somewhere, Item),
    write('Homer moves from '), write(Start), write(' to '), write(Somewhere), nl,
    canHomerGet(Somewhere, End, Item).

This would make the predicate tail-recursive, thus running in constant stack space, but rises a new problem: movements leading nowhere would also be printed as backtracking to find a successful route will not undo the printing of the movements. The usual solution is to build a list of steps (using an additional argument) and then to print the list (after reversing it) at the end. I will leave that to you as exercise.

Upvotes: 2

Related Questions