このページhttp://www.ic.unicamp.br/~meidanis/courses/mc336/2009s2/prolog/problemas/の演習 09 では、繰り返される要素をサブリストにパックする述語を作成するよう求められます。
簡単な解決策は簡単です
pack([], []).
pack([H|T], [I|U]) :-
split(H, T, I, P),
pack(P, U).
ここで、分割はsplit(Head, Tail, HeadGroup, Rest)
次のように定義されます
split(A, [], [A], []).
split(A, [B|T], [A], [B|T]) :- A \= B.
split(A, [A|T], [A|U], B) :- split(A, T, U, B).
これは問題なく動作し、上記の Web ページで提供されているサンプル ソリューションとほぼ一致しています。
このソリューションが失敗するのは、のようなクエリですpack(X, [[a], [b, b]]).
。2 つの解セット間の対応は全単射 (すべてA
のpack(A, B)
には 1 つしかないB
ため) であるため、より良い解が存在するはずです。
それを解決する1つの方法は、評価の順序を変更することです。これにより、プロローグが次のような引数のタイプに応じて非無限分岐を選択できるようになります
pack([], []).
pack(A, B) :-
( var(A) ->
A = [H|T],
B = [I|U],
pack(P, U),
split(H, T, I, P)
; A = [H|T],
B = [I|U],
split(H, T, I, P),
pack(P, U)
).
これに関して2つの質問。
まず、これは信じられないほど醜いので、引数の型に応じてルールの順序を選択するより良い方法はありますか?
第二に、おそらくもっと複雑な質問ですが、 を使わずvar(A)
にソリューションを書き直す方法はありますか? そうでない場合、その理由は?