我正处于学习Prolog的第一周,我想检查布尔谓词是否具有某种形式。具体来说,我想检查第一级是否存在真假。例如,or(P, or(Q, true))
的格式不是这样,因为在最高级别您具有或者,然后是P,或者在第二级别,然后是Q,在第三级别具有true。
我的想法是对每个级别进行计数并对每个术语进行递归(不确定是否要使用正确的单词),并在级别大于1时检查是否存在true或false。
使用here的答案,我写了以下内容来计算等级。
checker(Term) :- getLevel(Term, 0).
getLevel(or(T1, T2), L):- getLevel(T1, L+1), getLevel(T2, L+1).
我如何将其与if语句(如果存在)结合起来,以检查是否存在true和false,并且如果级别> 1,则返回失败?因此or(P, or(Q, true))
会失败。
答案 0 :(得分:1)
解决此特定问题的方法实际上不需要任何涉及级别的实际算术或任何实际的条件逻辑。我会这样处理:
concrete_boolean(X) :- atom(X), (X = true ; X = false).
checker(or(P, Q)) :- \+ concrete_boolean(P), \+ concrete_boolean(Q).
这满足了您所说的要求(“检查第一级中是否存在true或false”),但与您给出的示例(“ or(P,or(Q,true,))不在这种形式”)。因为Prolog谓词成功或失败而不是“返回”,所以我们经常用似乎仅处理成功(真)情况的谓词替换显式布尔逻辑。当模式不匹配时,谓词将失败,这将为我们提供所需的分支行为。
在这里您可能真正想要的是一个帮助谓词,该谓词将术语及其在树中的深度浮出水面,然后可以在其他过程中使用它。例如,使用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.
Prolog还可以使用一些测试,即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)).
这里的问题是您将在or(P,Q)
中出现P或Q,并且
然后将它们绑定为true或false,这将导致其余的
表达失败。 Prolog确实不希望您混淆
特定于领域的变量及其内部变量含义。我们可以使用var/1
和nonvar/1
在这里 摆脱它,以保护我们的统一并确保它们不会针对完全未绑定的变量发生。但是我仍然担心长期的影响,如果我在别人的程序中看到它,会认为它有点代码味道。