Agnius Vasiliauskas
Agnius Vasiliauskas

Reputation: 11267

Force prolog to make substitutions in output results

In the process of learning Prolog I'm making simple program which given some thing is able to tell what is on the left / right / above / below of that thing. Code is this:

% left_(LeftThing, ToThing)
left_(bicycle, camera).
left_(pencil, clock).
left_(clock, butterfly).
left_(butterfly, fish).

% above_(AboveThing, ToThing)
above_(bicycle, pencil).
above_(camera,  butterfly).

right(X, Y) :-
  left_(Y, X);
  X = (empty).

below(X, Y) :-
  above_(Y, X);
  X = (empty).

left(X, Y) :-
  left_(X, Y);
  X = (empty).

above(X, Y) :-
  above_(X, Y);
  X = (empty).

position(Thing, Left, Right, Above, Below) :-
    left(Left,  Thing),
   right(Right, Thing),
   above(Above, Thing),
   below(Below, Thing), !.

Now when I ask for :

?- position(clock, Left, Right, Above, Below).

I get an answer:

Left = pencil,
Right = butterfly,
Above = Below, Below = empty.

While this is perfectly correct answer, I would like Prolog to make full substitutions and give an output in standard way:

Left = pencil,
Right = butterfly,
Above = empty,
Below = empty.

Is there a way to force Prolog doing such substitutions in output without cluttering a lot with program facts and rules ? (err... maybe there is some results formatting option in SWI-Prolog configuration. If not - how to achieve this with minimal code changes ?)

Upvotes: 2

Views: 157

Answers (2)

CapelliC
CapelliC

Reputation: 60004

I can't find a flag controlling this behaviour, and internally (see boot/toplevel.pl) join_same_bindings/2 is called unconditionally.

There is an undocumented predicate print_toplevel_variables/0, but the output is not ordered, and contains 'historical' variables unrelated to last query:

?- position(clock, Left, Right, Above, Below).
Left = pencil,
Right = butterfly,
Above = Below, Below = empty.

?- print_toplevel_variables.
$Below =    empty
$Above =    empty
$Right =    butterfly
$Left =     pencil
$X =        false
$T =        position(clock,pencil,butterfly,empty,empty)
$Y =        1
false.

Upvotes: 2

m09
m09

Reputation: 7493

Prolog returns a most general unifier as a solution when it finds one. Here it is a perfectly standard one and I didn't find any flag to change this behavior (I might have missed one though, maybe a toplevel_print_options custom predicate or something).

That being said, you could roll your own print predicate if you want a prettyprint. It'd allow you to clean your database btw, because here you represent extra stuff from the original problem only to be able to return empty, which isn't good from a conception point of view. My take would be:

% left(LeftThing, ToThing)
left(  bicycle,   camera).
left(  pencil,    clock).
left(  clock,     butterfly).
left(  butterfly, fish).

% above(AboveThing, ToThing)
above( bicycle,   pencil).
above( camera,    butterfly).

right(X, Y) :-
    left(Y, X).

below(X, Y) :-
    above(Y, X).

print_custom(Y, Pred) :-
    (   call(Pred, X, Y)
     -> true
      ; X = empty),
    format('~w = ~w,~n', [Pred, X]).


position(Thing) :-
    maplist( print_custom(Thing),
             [left, right, above, below] ).

Test:

?- position(clock).
left = pencil,
right = butterfly,
above = empty,
below = empty,
true.

Upvotes: 3

Related Questions