2

私はPrologを初めて使用し、リストの2番目から最後の要素を取り出すこの(関数?)で何が起こっているのかを正確に把握しようとしています。

remove([],[]).
remove([X],[X]).
remove([_,X],[X]).
remove([X|Xs], [X|Ys]) :-
   Xs = [_,_|_],
   remove(Xs,Ys).

私は SML で少し仕事をしたので、パターン マッチングに精通しています。最初のケースは明らかに基本的なケースであり、分解すると空のリストが返されます。2 つ目は、変数が 1 つしか残っていない場合に同じ変数を返します。3 番目は、2 番目の要素を無視して、最後の要素を返すように見えますか? 帰納的なケースについては、リストの先頭を新しいリストに追加します ...... (これは私が完全に迷子になるところです)。言語をよりよく理解できるように、この関数で何が起こっているのか誰か説明してもらえますか?

4

4 に答える 4

3

CapelliCの説明について詳しく説明します。

remove([],[]).

空のリストは、最後から 2 番目の要素が削除された空のリストです。

remove([X],[X]).

単一要素リストは、最後から 2 番目の要素が削除されたものです。

remove([_,X],[X]).

最後から 2 番目の要素が削除された 2 要素リストは、2 要素リストの最後の要素で構成される 1 つの要素のリストです。

remove([X|Xs], [X|Ys]) :-
   Xs = [_,_|_],
   remove(Xs,Ys).

2 番目のリストは、2 番目の要素が削除された最初のリストであり、同じ最初の要素 IF を共有します。

  1. 最初のリストの末尾は、少なくとも 2 つの要素、AND で構成されます。
  2. 2 番目のリストの末尾は、最後から 2 番目の要素が削除された最初のリストの末尾です。
于 2013-11-04T11:54:37.663 に答える
2

だから、宣言的に読む方法

remove([X|Xs], [X|Ys]) :-
   Xs = [_,_|_],
   remove(Xs,Ys).

最も重要なことは、:-実際に何を意味するのかを最初に理解することです。

頭身 :- _.

それは次のことを意味します: Bodyが保持されているときはいつでも、 Headも保持されていると結論付けることができます。矢印の方向が直感的でないことに注意してください。右から左に進みます。また、何かを結論付けるときに非公式に書かれることが多いように、左から右ではありません。ただし、エラーは、「そこから」得られるものの方向を示しています。

これをよりよく確認するには、Bodyをクエリとして入力します。

?- Xs = [_,_|_], remove(Xs,Ys).
Xs = [A, B],
Ys = [B] ;
Xs = [A, B, C],
Ys = [A, C] ;
...

Xsしたがって、要素が 2 つ未満の場合を除いて、すべての答えが得られます。

手続き的に、物事はまったく逆の方向に起こることに注意してください - そしてそれは初心者にとって非常に混乱します. さらに言えば、Prolog は 2 つの「非伝統的な」機能、時系列バックトラッキングと変数 (実際の変数、すべての可能な用語を意味します) を使用するため、命令型言語や関数型言語でおなじみのこれらのコンパイル時の構成要素ではありません。これらの言語では、変数はランタイム値のホルダーです。具体的な値。Prolog では、実行時にも変数が存在します。詳細については、論理プログラミングと関数型プログラミングの違いを参照してください。

別の問題もありますが、あなたが理解しているかどうかはわかりません。のことを考える:

?- remove(Xs, [1,2]).
Xs = [1, A, 2] ;
false.

ここで何が削除されますか?何もない!まったく逆に、リストにさらに要素を追加しています。このため、この名前remove/2は Prolog では理想的ではありません。いくつかの引数が与えられ、他の引数が計算されることを強制するコマンド指向プログラミング言語を思い起こさせます。最初は、これは大した問題ではないと思うかもしれません。結局のところ、これはただの名前です。しかし、プログラミングをしていると、すべてを考える時間がないことがよくあることを忘れないでください。したがって、適切なリレーショナル名が望ましい場合があります。

1 つを見つけるには、型だけから始めます: list_list/2、次に絞り込むlist_removed/2or list__without_2nd_last/2

于 2013-11-05T01:16:33.953 に答える
0

注釈付き:

remove( []     , []     ) .  % removing the 2nd last element from the empty list yields the empty list
remove( [X]    , [X]    ) .  % removing the 2nd last element from a 1-element list yields the 1-element list.
remove( [_,X]  , [X]    ) .  % removing the 2nd last element from a 2-element list yields the tail of the 2-element list
remove( [X|Xs] , [X|Ys] ) :- % for any other case...
  Xs = [_,_|_],              % * if the tail contains 2 or more elements, the list is 3 elements or more in length
  remove(Xs,Ys).             % we simply prepend the head of the list to the result and recurse down.

最後の節は、次のようにもう少し明確に (そしてもう少し簡潔に) 書き直すことができることに注意してください。

remove( [X1,X2,X3|Xs] , [X1|Ys] ) :- % for any other case (a list of length 3 or more)
  remove([X2,X3|Xs],Ys).             % we simply prepend the head of the list to the result and recurse down.

またはとして

remove( [X1|[X2,X3|Xs]] , [X1|Ys] ) :- % for any other case (a list of length 3 or more)
  remove([X2,X3|Xs],Ys).               % we simply prepend the head of the list to the result and recurse down.
于 2013-11-05T00:14:40.560 に答える