あるリストが別のリストの順列であるかどうかを判断するプロローグ プログラムを作成しようとしています。入力は の形式で、 listが list の順列であるperm(L,M)
場合にのみ true になります。L
M
これは私の AI クラスのためのものなのでpermutation
、gprolog が既に提供している気の利いた小さな述語をそのまま使用することはできません。私たちの教授は、member
述語が役立つかもしれないと指摘しましたが、述語を含む私が持っているアイデアは、非常にトリッキーで、それほど宣言的ではないものを必要とするようです (そして、あまり高度にならずにこれを解決する方法があると思います.クラスはプロローグにとって新しいものです。)
とにかく、確認する方法の 1 つは、L
とM
が同じサイズであること、各L
要素が にM
あり、各M
要素が にあることを確認することですL
(! の使用がありmember
ます)。[2,2,4]
ただし、これはや などの場合には十分ではありません[4,4,2]
。
別の方法としては、各要素の同じカウントが反対側のリストにあることを確認することもできますが、プロローグに関する私の印象では、あらゆる種類の変数「メモリ」はかなり難しいビジネスです (実際、私が見たサンプル プログラムはソートの実行などは、実際にはまったくデータを操作しているわけではありません。それらは単に「仮説的に」物事を再配置し、イエスかノーかを伝えているだけです...?)
精神的には、リストとチェック要素の両方を並べてソートすることもできますが、それは、他の多くの考え方の中で、オブジェクト指向すぎるように思えます...
ヒントはありますか?私の最大の問題は、(前述のように)「操作」を行うことは、それらについて尋ね、目的の場所に到達するのに十分長く物事が真実であり続けることを望んでいるように見えるという事実のようです.
**更新: gprolog はdelete
機能を提供しますが、次のような試みを行うと、予想していた宣言関連の問題が発生します。
perm([LH|LT], R) :- member(LH,R), delete([LH|LT],LH,R), perm(LT,R).
マニュアルでは、delete は次のように定義されています。
実行:
{trace}
| ?- perm([1,2,3],[3,1,2]).
1 1 Call: perm([1,2,3],[3,1,2]) ?
2 2 Call: member(1,[3,1,2]) ?
2 2 Exit: member(1,[3,1,2]) ?
3 2 Call: delete([1,2,3],1,[3,1,2]) ?
3 2 Fail: delete([1,2,3],1,[3,1,2]) ?
2 2 Redo: member(1,[3,1,2]) ?
2 2 Fail: member(1,[3,1,2]) ?
1 1 Fail: perm([1,2,3],[3,1,2]) ?
(1 ms) no
**更新 2: 私はそれを理解したかもしれないと思います! ちょっと冗長ですが、かなりの数のケースでテストしましたが、まだ悪いケースは見つかりませんでした。誰かが大きな問題を見つけたら、指摘してください:
perm([],[]).
perm([LH|LT],R) :- length([LH|LT],A), length(R,B), A == B, member(LH,R), select(LH,[LH|LT],X), select(LH,R,Y), perm_recurse(X, Y), !.
perm_recurse([],X). %If we get here, all elements successfully matched
perm_recurse([LH|LT],R) :- member(LH,R), select(LH,[LH|LT],X), select(LH,R,Y), perm_recurse(X, Y), !.
私はカットオペレーターが好きです..