Пролог: проверьте, что логический предикат имеет определенную форму - PullRequest
0 голосов
/ 23 февраля 2019

Я на первой неделе изучения Пролога и хочу проверить, что логический предикат имеет определенную форму.В частности, я хочу проверить, присутствует ли true или false на первом уровне или нет вообще.Например, or(P, or(Q, true)) не в этой форме, так как на верхнем уровне у вас есть или, затем P, или на втором, затем Q, true на третьем уровне.

У меня есть идея подсчитать каждый уровень и выполнить рекурсию для каждого термина (не уверен, правильно ли это слово использовать) и проверить, присутствует ли значение true или false, если уровень больше 1.

Используя ответ из здесь , я написал следующее для подсчета уровней.

checker(Term) :- getLevel(Term, 0).
getLevel(or(T1, T2), L):- getLevel(T1, L+1), getLevel(T2, L+1).

Как бы я совместил это с оператором if (если он существует), чтобы проверить, есть ли истина и ложь, и вернуть ошибку, если уровень> 1?Так что or(P, or(Q, true)) потерпит неудачу.

1 Ответ

0 голосов
/ 23 февраля 2019

Решение этой конкретной проблемы на самом деле не требует какой-либо реальной арифметики с участием уровня или какой-либо реальной условной логики.Я бы обработал это так:

concrete_boolean(X) :- atom(X), (X = true ; X = false).

checker(or(P, Q)) :- \+ concrete_boolean(P), \+ concrete_boolean(Q).

Это удовлетворяет заявленному вами требованию («проверьте, что true или false отсутствуют на первом уровне»), но это противоречит приведенному вами примеру («или(P или (Q, верно)) не в этой форме ").Поскольку предикаты Пролога преуспевают или терпят неудачу, а не «возвращают», мы часто заменяем явную логическую логику предикатами, которые, кажется, обрабатывают только успешный (истинный) случай.Когда шаблон не совпадает, предикат потерпит неудачу, и это даст нам поведение разветвления, которое мы хотели.

То, что вы, вероятно, на самом деле ищете после этого, это вспомогательный предикат, который отображает термины вместе с их глубиной в дереве,который вы можете затем использовать в другой процедуре.Например, с getLevel/3 вы могли бы легко написать предикат, который проверяет явные логические значения только на нечетных или четных уровнях иерархии.

Для этого вы кажетесь довольно близкими, но вы объединяете вещи, имеяchecker/1 укажите базовый вариант для getLevel/2.Я думаю, что вы на самом деле хотите что-то вроде этого:

getLevel(Term, Part, Level) :- getLevel1(Term, 0, Part, Level).
getLevel1(Term, L0, Term, L0).
getLevel1(or(Left, _), L0, LeftChild, LN) :- 
   succ(L0, L1), 
   getLevel1(Left, L1, LeftChild, LN).
getLevel1(or(_, Right), L0, RightChild, LN) :- 
   succ(L0, L1), 
   getLevel1(Right, L1, RightChild, LN).

Мне очень понравилось это тестирование с атомами, потому что оно, кажется, делает правильные вещи:

?- getLevel(or(p, or(q, true)), Term, Level).
Term = or(p, or(q, true)),
Level = 0 ;
Term = p,
Level = 1 ;
Term = or(q, true),
Level = 1 ;
Term = q,
Level = 2 ;
Term = true,
Level = 2.

Однако, когда вы пробуете это с переменными, все становится немного странным:

?- getLevel(or(P,Q), Term, Level).
Term = or(P, Q),
Level = 0 ;
P = Term,
Level = 1 ;
P = or(Term, _2390),
Level = 2 ;
P = or(or(Term, _2396), _2390),
Level = 3 ;
P = or(or(or(Term, _2402), _2396), _2390),
Level = 4 .

Это происходит, когда несвязанная переменная объединяется с одной из глав нашего предложения.То, что начиналось как P, объединяется с or(Left, _), а не просто не привязывается к нему.

Самый простой и лучший способ решить эту проблему - решить, действительно ли вам нужны дыры в вашей структуре данных, как эта, иесли вы делаете, аннотируйте их.В качестве примера:

?- getLevel(or(var(P),var(Q)), Term, Level).
Term = or(var(P), var(Q)),
Level = 0 ;
Term = var(P),
Level = 1 ;
Term = var(Q),
Level = 1.

В Прологе также есть несколько тестов, которые вы можете использовать, а именно var/1 и nonvar/1 и ground/1, но по моему опыту их использование обычно создает тонкие проблемы (часто с обратной правильностью)или структуры данных с дырами), поэтому я просто упомяну это здесь, так как я почти уверен, что не найду правильного решения, которое помогает и обрабатывает все странные случаи.

Редактировать : Давайте поговорим о явной обработке переменных.

Мы можем изменить то, что у меня есть в ответе, для обработки этого состояния var / nonvar:

getLevel(Term, Part, Level) :- getLevel1(Term, 0, Part, Level).
getLevel1(Term, L0, Term, L0).
getLevel1(T, L0, LeftChild, LN) :-
    nonvar(T), T = or(Left, _),
    succ(L0, L1), 
    getLevel1(Left, L1, LeftChild, LN).
getLevel1(T, L0, RightChild, LN) :-
    nonvar(T), T = or(_, Right),
    succ(L0, L1), 
    getLevel1(Right, L1, RightChild, LN).

Реализация checker/1 довольно проста с этим:

checker(Term) :-
    \+ (getLevel(Term, Boolean, 1), 
        nonvar(Boolean), 
        (Boolean = true ; Boolean = false)).

Заманчиво сделать это вместо этого:

checker(Term) :-
    \+ (getLevel(Term, Boolean, 1), 
        (Boolean = true ; Boolean = false)).

Проблема здесь в том, что вы вызовете P или Q в or(P,Q), а затем свяжете их с истинным или ложным,что приведет к сбою остальной части выражения.Пролог действительно не хочет, чтобы вы связывали предметную идею переменной с ее внутренним смыслом переменной.Мы можем своего рода здесь сойти с рук, используя var/1 и nonvar/1, чтобы защитить наши объединения и гарантировать, что они не происходят от полностью несвязанной переменной.Но я по-прежнему беспокоюсь о долгосрочных последствиях и расценил бы это как запах кода, если бы увидел его в чужой программе.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...