在命题公式中返回原子的Prolog程序
我是prolog的新手,正在尝试编写一个程序,以一个格式良好的命题公式返回原子。例如,查询在命题公式中返回原子的Prolog程序,prolog,Prolog,我是prolog的新手,正在尝试编写一个程序,以一个格式良好的命题公式返回原子。例如,查询ats(and(q,imp(or(p,q),neg(p)))As.应该返回[p,q]作为As。下面是我的代码,它将公式返回为as。我不知道如何将中的单个F拆分为ats中的F1和wff中的F2,因此永远不会调用wff/2。请帮我从这里开始。谢谢 代码 logical_atom( A ) :- atom( A ), atom_codes( A, [AH|_] ),
ats(and(q,imp(or(p,q),neg(p)))As.
应该返回[p,q]
作为As。下面是我的代码,它将公式返回为as
。我不知道如何将中的单个F
拆分为ats
中的F1
和wff
中的F2
,因此永远不会调用wff/2
。请帮我从这里开始。谢谢
代码
logical_atom( A ) :-
atom( A ),
atom_codes( A, [AH|_] ),
AH >= 97,
AH =< 122.
wff(A):- ground(A),
logical_atom(A).
wff(neg(A)) :- ground(A),wff(A).
wff(or(F1,F2)) :-
wff(F1),
wff(F2).
wff(and(F1,F2)) :-
wff(F1),
wff(F2).
wff(imp(F1,F2)) :-
wff(F1),
wff(F2).
ats(F, As):- wff(F), setof(F, logical_atom(F), As).
逻辑原子(A):-
原子(A),
原子|u码(A[AH|u]),
啊>=97,
啊=<122。
wff(A):-接地(A),
逻辑_原子(A)。
wff(负(A)):-接地(A),wff(A)。
wff(或(F1,F2)):-
wff(F1),
wff(F2)。
wff(和(F1,F2)):-
wff(F1),
wff(F2)。
wff(imp(F1,F2)):-
wff(F1),
wff(F2)。
ats(F,As):-wff(F),集合(F,逻辑_原子(F,As)。
>P>首先,考虑使用一个更干净的表示:目前,你不能用一个普通的函子来区分原子。例如,将它们包装在a(Atom)
中
其次,使用DCG来描述格式良好的公式与其原子列表之间的关系,如:
wff_atoms(a(A)) --> [A].
wff_atoms(neg(F)) --> wff_atoms(F).
wff_atoms(or(F1,F2)) --> wff_atoms(F1), wff_atoms(F2).
wff_atoms(and(F1,F2)) --> wff_atoms(F1), wff_atoms(F2).
wff_atoms(imp(F1,F2)) --> wff_atoms(F1), wff_atoms(F2).
示例查询及其结果:
?- phrase(wff_atoms(and(a(q), imp(or(a(p), a(q)), neg(a(p))))), As).
As = [q, p, q, p].
我将使用“univ”操作符=../2
和显式递归来解决这个问题。请注意,此解决方案不会生成,并且“逻辑上不正确”,因为它不会大量处理带有孔的结构,因此如果条件重新排序,它将产生不同的结果。请参见下文@mat的评论
为了个人美学,我使用了剪切而不是if语句;使用大型显式条件树肯定会获得更好的性能。我不确定您是否希望首先生成这样的谓词
Univ很方便,因为它可以让你像对待Lisp中复杂的s表达式一样对待Prolog术语:它将术语转换为原子列表。这使您能够以列表的形式遍历Prolog术语,如果您不确定将要处理什么,这将非常方便。这样我就不用显式地查找布尔运算符了
atoms_of_prop(Prop, Atoms) :-
% discard the head of the term ('and', 'imp', etc.)
Prop =.. [_|PropItems],
collect_atoms(PropItems, AtomsUnsorted),
% sorting makes the list unique in Prolog
sort(AtomsUnsorted, Atoms).
辅助谓词collect_atoms/2
处理术语列表(univ仅拆卸最外层),并在查找术语时与_prop/2的atoms_
相互递归。如果它找到了原子,它只是将它们添加到结果中
% base case
collect_atoms([], []).
% handle atoms
collect_atoms([A|Ps], [A|Rest]) :-
% you could replace the next test with logical_atom/1
atom(A), !,
collect_atoms(Ps, Rest).
% handle terms
collect_atoms([P|Ps], Rest) :-
compound(P), !, % compound/1 tests for terms
atoms_of_prop(P, PAtoms),
collect_atoms(Ps, PsAtoms),
append(PAtoms, PsAtoms, Rest).
% ignore everything else
collect_atoms([_|Ps], Rest) :- atoms_of_prop(Ps, Rest).
这适用于您的示例,如下所示:
?- atoms_of_prop(ats(and(q, imp(or(p, q), neg(p))), As), Atoms).
Atoms = [p, q].
这应该是你想要的。它提取在任意序言项中发现的唯一原子集
不过,我将把它留给您来决定什么构成“格式良好的命题公式”,正如您在问题陈述中所说的那样(您可能想看看DCG的解析和验证)
大部分工作是由这个“工作者谓词”完成的。它只是通过回溯一次提取解析树中找到的任何原子,并丢弃任何其他原子:
expression_atom( [T|_] , T ) :- % Case #1: head of list is an ordinary atom
atom(T) , % - verify that the head of the list is an atom.
T \= [] % - and not an empty list
. %
expression_atom( [T|_] , A ) :- % Case #2: head of listl is a compound term
compound(T) , % - verify that the head of the list is a compound term
T =.. [_|Ts] , % - decompose it, discarding the functor and keeping the arguments
expression_atom(Ts,A) % - recurse down on the term's arguments
. %
expression_atom( [_|Ts] , A ) :- % Finally, on backtracking,
expression_atom(Ts,A) % - we simply discard the head and recurse down on the tail
. %
然后,在顶层,我们有一个简单的谓词,它接受任何[component]prolog术语,并通过setof/3
提取工作谓词在其中找到的唯一原子集:
expression_atoms( T , As ) :- % To get the set of unique atoms in an arbitrary term,
compound(T) , % - ensure that's its a compound term,
T =.. [_|Ts] , % - decompose it, discarding the functor and keeping the arguments
setof(A,expression_atom(Ts,A),As) % - invoke the worker predicate via setof/3
. % Easy!
谢谢你的回答,但我需要的问题,如?wff(和(q,imp(或(p,q),neg(p))),As)。直接给我一个唯一的原子列表。我已经在上面的代码片段中定义了我的atom。你可以简单地将它添加为谓词:wff(F,as):-phrase(wff_atoms(F),As0),sort(As0,as)。
再次感谢,但请理解我是一个新手,我真的不理解prolog程序,我真的想保留我的逻辑原子谓词和我对格式良好的命题公式的定义。我只想知道F何时从ats变为F1和F2,以及如何填充原子集。我希望我的话听起来不会让人困惑。尤其是作为一个新手,目标是清晰的表示:它们让你通过它们的函子来区分不同的实体,这样你就可以使用模式匹配,你的谓词自然地在各个方向上工作,即使它们的参数是变量。例如,您最初发布的代码没有为查询?-wff(a)。
找到单一的解决方案,尽管它可以选择无限多个原子来提供解决方案!如果你得到了一个不干净的表示,首先要把它转换成一个干净的表示!写代码<代码> WFFCHILL/2 ,然后在干净的表示上使用<代码> WFFEXORION//< 1 /代码>。不幸的是,这会产生错误的结果:例如,考虑代码< > -AfthsIOFOPROP(和(x,a),Ls),x= b,ls=[a,b] .<代码>,失败了。然而,当你简单地通过连接的交换性来交换前两个目标时,它是成功的。@mat我很感激你指出了缺点,但这取决于OP来决定它是否是错误的。在我看来,他们在做自己的变量替换过程,所以这可能是解析树的结果,虽然是一个Prolog新手,但它不太可能包含holes.OP,也很可能知道连词应该是一个交换谓词。@mat Prolog新手通常更了解这样一个事实,即程序是在机器上执行的,而不是由逻辑学家假设的。我相信,即使你比我更了解Prolog,我比OP更了解他们的问题,OP也比我们更了解他们的问题,更愿意看到几种方法,权衡利弊,做出明智的决定,解决方案一是错误的,因为边缘案例可能根本不属于它们的问题领域。@mat我编辑了答案,以使您的评论在前面的细节中明确。如果您看到一个明显的解决方案(如果不是太狭隘或太宽泛,可能是atom(X);var(X)
),或者如果您不喜欢我的小册子,请告诉我,我会更新答案。