非平凡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)替换连词,

因此,我们可以在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)替换连词,如
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是确定性的,因此代码运行速度会更快。