非平凡的Prolog找到并替换

时间:2010-11-07 18:21:44

标签: 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)替换逻辑语句中的conj(x,y)之类的连词?所以它就像是最终的,取而代之的是原子。所以我们可以将reduce(conj(conj(x,y),z)).这样的内容减少到((x,y),z)

这是一个只有连词的简单例子,但这是我想在连词的情况下发生的事情。如果有人感兴趣,这就是描述性逻辑和画面方法。

当输入实际上不是列表时,我对如何进行查找和替换感到困惑;这是一个结构。我没有看到如何在不使用递归和列表的标准[H|T]技巧的情况下解决这个问题。有没有人有任何想法?

非常感谢。

3 个答案:

答案 0 :(得分:5)

这是通过编写元解释器以直截了当的方式完成的,例如:

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的所有其他子句)将递归解构任何 PROLOG这个术语,因为我们已经涵盖了所有类型;变量,原子和复合词(包括明确的列表)。

在您的案例中执行此操作会给我们:

?- replace(conj(conj(x,y),z), NewTerm).
NewTerm = ((x, y), z).

请注意,此定义将执行在另一个术语中嵌套到任意深度的任何术语的正确替换。

答案 1 :(得分:3)

回想一下,列表只是某种结构,因此您可以轻松地翻译代码以匹配任何其他结构。它可以帮助您为数据使用更清晰的表示:就像使用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).

答案 2 :(得分:1)

您可以使用=..将一般术语转换为列表,例如

?- 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-predicate:

reduce(Term1, Term2) :-
    change_term(conj_changer, Term1, Term2).

用法:

?- reduce(conj(conj(x,y),z), ReducedTerm).
ReducedTerm = ((x, y), z).

您必须小心定义NodeChanger的方式,某些定义可以使change_term/3循环。也许有人可以改进。