Арифметические операции в начале предложения

Я пишу предикат Пролога, который сравнивает некоторую точку (myPosition(2,2)) в декартовой системе координат с какой-то другой точкой по соседству. В результате он должен показать направление (север, восток, юг, запад), которое мы должны выбрать, чтобы попасть из myPosition(2,2) в эту точку. Вот код моего файла .pl:

myPosition(2,2).

turn_to_east(X+1,Y) :-
    myPosition(X,Y),
    write('East.').

turn_to_west(X-1,Y) :-
    myPosition(X,Y),
    write('West.').

turn_to_north(X,Y+1) :-
    myPosition(X,Y),
    write('North.').

turn_to_south(X,Y-1) :-
    myPosition(X,Y),
    write('South.').

turn_to_the_point(X,Y) :- turn_to_east(X,Y).
turn_to_the_point(X,Y) :- turn_to_west(X,Y).
turn_to_the_point(X,Y) :- turn_to_north(X,Y).
turn_to_the_point(X,Y) :- turn_to_south(X,Y).

Затем, когда я загружаю файл в SWI-Prolog и пишу:

turn_to_the_point(1,2).

Я получаю только:

false.

Почему я не могу получить ответ «Запад». или любой другой?


person Zaslon    schedule 12.12.2015    source источник
comment
Пролог не похож на другие языки. У него нет функций, которые возвращают значения. У него есть предикаты, которые либо преуспевают, либо терпят неудачу, либо не завершаются (плохо). И он не выполняет оценку выражений in-line. Так что turn_to_west(X-1,Y), например, не уменьшает X на 1.   -  person lurker    schedule 12.12.2015
comment
Прежде всего немного терминологии: в Прологе нет функций, это предикаты.   -  person Willem Van Onsem    schedule 12.12.2015


Ответы (1)


Причина в том, что по умолчанию Пролог не интерпретирует +, - и другие арифметические операторы. 1+1 — это просто 1+1 (это синтаксический сахар для +(1,1)), а не 2. Это может быть полезно, если вы, например, хотите определить свой собственный вычислитель выражений и видите + как логическую сумму или что-то совершенно другое.

Однако существует один способ свернуть такое выражение, чтобы оно производило 2 из 1+1, используя (is)/2 предикат. Например:

turn_to_east(NX,Y) :-
    myPosition(X,Y),
    NX is X+1,
    write('East.').

Учитывая, что вы запрашиваете turn_to_east/2 с turn_to_east(1,2), NX = 1. Теперь вы получаете данные myPosition/2: X = 2 и Y = 2. Тем временем Пролог выполняет проверку на эквивалентность и видит, что координата Y turn_to_east/2 такая же, как координата myPosition. Затем он сворачивает 2+1 в 3 и видит, что это не эквивалентно NX = 1, поэтому этот предикат не работает. Но если бы вы запросили turn_to_east(3,1), это было бы успешно, и поэтому напишите East..

Если вы измените всю свою теорию с помощью обсуждаемой выше концепции, например:

myPosition(2,2).

turn_to_east(NX,Y) :-
    myPosition(X,Y),
    NX is X+1,
    write('East.').

turn_to_west(NX,Y) :-
    myPosition(X,Y),
    NX is X-1,
    write('West.').

turn_to_north(X,NY) :-
    myPosition(X,Y),
    NY is Y+1,
    write('North.').

turn_to_south(X,NY) :-
    myPosition(X,Y),
    NY is Y-1,
    write('South.').

turn_to_the_point(X,Y) :- turn_to_east(X,Y).
turn_to_the_point(X,Y) :- turn_to_west(X,Y).
turn_to_the_point(X,Y) :- turn_to_north(X,Y).
turn_to_the_point(X,Y) :- turn_to_south(X,Y).

Он правильно отвечает на запрос:

?- turn_to_the_point(1,2).
West.
true ;
false.

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

myPosition(2,2).

turn_to_point(NX,Y,east) :-
    myPosition(X,Y),
    NX is X+1.
turn_to_point(NX,Y,west) :-
    myPosition(X,Y),
    NX is X-1.

turn_to_point(X,NY,north) :-
    myPosition(X,Y),
    NY is Y+1.

turn_to_point(X,NY,south) :-
    myPosition(X,Y),
    NY is Y-1.

turn_to_the_point(X,Y) :-
    turn_to_point(X,Y,D),
    write(D).

В этом случае предикат turn_to_the_point/2 явно является предикатом взаимодействия, тогда как его вариант turn_to_the_point/3 выполняет вычисления.

person Willem Van Onsem    schedule 12.12.2015