Решение этой конкретной проблемы на самом деле не требует какой-либо реальной арифметики с участием уровня или какой-либо реальной условной логики.Я бы обработал это так:
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
, чтобы защитить наши объединения и гарантировать, что они не происходят от полностью несвязанной переменной.Но я по-прежнему беспокоюсь о долгосрочных последствиях и расценил бы это как запах кода, если бы увидел его в чужой программе.