Заставить пролог делать замены в выходных результатах

В процессе изучения Пролога я делаю простую программу, которая при определенных условиях может определять, что находится слева / справа / сверху / снизу от этой вещи. Код такой:

% 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), !.

Теперь, когда я прошу:

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

Я получаю ответ:

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

Хотя это совершенно правильный ответ, я бы хотел, чтобы Prolog произвел полные замены и выдал результат стандартным способом:

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

Есть ли способ заставить Prolog выполнять такие замены в выводе, не загромождая программными фактами и правилами? (эээ ... может быть, в конфигурации SWI-Prolog есть опция форматирования результатов. Если нет - как этого добиться с минимальными изменениями кода?)


person Agnius Vasiliauskas    schedule 06.09.2012    source источник


Ответы (2)


Prolog возвращает в качестве решения самый общий унификатор, когда он его находит. Вот он совершенно стандартный, и я не нашел любой флаг, чтобы изменить это поведение (хотя я мог пропустить один, может быть, toplevel_print_options настраиваемый предикат или что-то в этом роде).

При этом вы можете создать свой собственный предикат печати, если хотите красивую печать. Это позволило бы вам очистить вашу базу данных, кстати, потому что здесь вы представляете лишний материал из исходной проблемы только для того, чтобы иметь возможность вернуть empty, что нехорошо с точки зрения концепции. Мое мнение было бы таким:

% 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] ).

Контрольная работа:

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

Я не могу найти флаг, контролирующий это поведение, и внутренне (см. boot / toplevel.pl) join_same_bindings / 2 вызывается безоговорочно.

Существует недокументированный предикат print_toplevel_variables / 0, но вывод не упорядочен и содержит «исторические» переменные, не связанные с последним запросом:

?- 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.
person CapelliC    schedule 06.09.2012