非平凡Prolog查找和替换
因此,我们可以在Prolog中轻松地找到一个原子并用另一个原子替换它,方法如下:非平凡Prolog查找和替换,prolog,Prolog,因此,我们可以在Prolog中轻松地找到一个原子并用另一个原子替换它,方法如下: replace([],A,B,[]). replace([H|T],A,B,[B|Result]) :- H=A, replace(T,A,B,Result),!. replace([H|T],A,B,[H|Result]) :- replace(T,A,B,Result). 我相信还有其他方法可以做到这一点 然而,我想做一些更复杂的计算逻辑。在逻辑语句中,如何用(x,y)替换连词,
replace([],A,B,[]).
replace([H|T],A,B,[B|Result]) :-
H=A,
replace(T,A,B,Result),!.
replace([H|T],A,B,[H|Result]) :-
replace(T,A,B,Result).
我相信还有其他方法可以做到这一点
然而,我想做一些更复杂的计算逻辑。在逻辑语句中,如何用(x,y)替换连词,如conj(x,y)
?所以它就像是最终的和替换的,但不是原子。所以我们可以有类似于reduce(conj(conj(x,y,z))。
的东西,我想把它简化成((x,y,z)
这是一个只有连接词的简单例子,但这就是我想在连接词的情况下发生的事情。如果有人感兴趣,这都是关于描述性逻辑和tableau方法的
我所困惑的是,当输入实际上不是一个列表时,如何进行查找和替换;这是一个结构。如果不使用递归和列表的标准[H | t]
技巧,我看不出如何解决这个问题。有人有什么想法吗
非常感谢。您可以使用
=…
将通用术语转换为列表,例如
?- conj(conj(x,y),z) =.. List.
List = [conj, conj(x, y), z].
递归地执行此操作,可以将整个项展平
更改输入术语中某些节点的通用谓词如下所示:
change_term(NodeChanger, Term1, Term3) :-
call(NodeChanger, Term1, Term2),
change_term(NodeChanger, Term2, Term3),
!.
change_term(NodeChanger, Term1, Term2) :-
Term1 =.. [Functor | SubTerms1],
change_termlist(NodeChanger, SubTerms1, SubTerms2),
Term2 =.. [Functor | SubTerms2].
change_termlist(_, [], []).
change_termlist(NodeChanger, [Term1 | Terms1], [Term2 | Terms2]) :-
change_term(NodeChanger, Term1, Term2),
change_termlist(NodeChanger, Terms1, Terms2).
如果您现在定义:
conj_changer(conj(X, Y), (X, Y)).
然后,您可以通过以下方式定义reduce谓词:
reduce(Term1, Term2) :-
change_term(conj_changer, Term1, Term2).
用法:
?- reduce(conj(conj(x,y),z), ReducedTerm).
ReducedTerm = ((x, y), z).
您必须注意如何定义
NodeChanger
,某些定义可能导致change\u term/3
循环。也许有人可以改进这一点。这可以通过编写元解释器以简单的方式完成,例如:
replace(V, V) :-
% pass vars through
var(V), !.
replace(A, A) :-
% pass atoms through
atomic(A), !.
replace([], []) :-
% pass empty lists through
!.
replace([X|Xs], [Y|Ys]) :-
% recursively enter non-empty lists
!,
replace(X, Y),
replace(Xs, Ys).
replace(conj(X,Y), (NX,NY)) :-
% CUSTOM replacement clause for conj/2
!,
replace(X, NX),
replace(Y, NY).
replace(T, NT) :-
% finally, recursively enter any as yet unmatched compound term
T =.. [F|AL],
replace(AL, NAL),
NT =.. [F|NAL].
注意最后第二个子句,它用于执行替换conj/2
与连接词,/2
的特定情况的替换。您可以以与此相同的方式添加尽可能多的其他子句来执行术语替换,因为定义的其余部分(这里的所有其他子句(replace/2
)将递归地解构任何序言术语,因为我们已经涵盖了所有类型;变量、原子和复合项(包括显式列表)
在您的案例中执行此操作将为我们提供:
?- replace(conj(conj(x,y),z), NewTerm).
NewTerm = ((x, y), z).
请注意,此定义将正确替换嵌套在另一个术语中任意深度的任何术语。请记住,列表只是某种结构,因此您可以轻松地将代码翻译为与任何其他结构匹配。它可以帮助您对数据使用更清晰的表示:正如您使用conj/2表示连词一样,您可以引入函子var/1来表示变量:
reduce(conj(X0,Y0), (X,Y)) :-
reduce(X0, X),
reduce(Y0, Y).
reduce(var(X), X).
例如:
?- reduce(conj(conj(var(x),var(y)), var(z)), R).
R = ((x, y), z).
谢谢你的邀请。聪明的东西,但是。。。太聪明了,你推荐什么资源来学习元口译员吗?谢谢,太聪明了?作为一名PROLOG程序员,这是一个实用谓词,我经常使用它来进行术语操作,并且会出现在任何专业PROLOG程序员的技巧包中;)有关元解释器的资源,您可以查看Clocksin和Mellish的“Prolog编程”,以及Leon Sterling和Ehud Shapiro的“Prolog的艺术”。所谓“元解释器”,我指的是能够理解/解释PROLOG代码的PROLOG代码,它特别适合您的问题。为什么不将剪切放在第一个H=A之后,而不是替换/4之后?由于Prolog系统可以检测到replace/4是确定性的,因此代码运行速度会更快。