6


2

自明ではないプロローグの検索と置換

したがって、次のような操作を行うことで、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).

これを行う方法は他にもあると思います。

しかし、コンピューティングのロジックでもっと複雑なことをしたいと思っています。 論理文の `conj(x、y)`のような接続詞をちょうど(x、y)に置き換えるようなことをどのように行うのでしょうか? つまり、finalとreplaceに似ていますが、atomsではありません。 したがって、「(reduce(conj(conj(x、y)、z))」のようなものを作成できますが、これを「((x、y)、z)」に減らしたいと思います。

これは、接続詞のみを使用した単純な例ですが、これは接続詞の場合に発生することです。 誰もが興味を持っているのであれば、これは記述論理とタブロー法に関するものです。

入力が実際にリストではないときに、検索と置換をどのように行うかについて私が混乱しているのは、それは構造です。 標準の `[H | T]`トリックを再帰とリストを使用せずにこれを解決する方法はわかりません。 誰かが何かアイデアを持っていますか?

どうもありがとう。

3 回答


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].

最後の2番目の節に注意してください。これは、 conj / 2`を接続詞、/ 2`に置き換える特定のケースの置き換えを実行するのに役立ちます。 ここで定義した残りの部分( `replace / 2`の他のすべての句)は再帰的に_any_ PROLOG用語を分解するため、これと同じ方法で他の句を追加して一般に用語置換を実行できます。すべてのタイプ。 vars、atoms、および複合語(リストを明示的に含む)。

あなたのケースでこれを実行すると、次のことがわかります。

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

この定義は、別の用語内の任意の深さにネストされた用語の正しい置換を実行することに注意してください。


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).


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」ループが発生する場合があります。 誰かがそれを改善できるかもしれません。