JBさんのお勧め以外にも解決方法はいくつかあると思います。ProductTypeN
安っぽいトリックの 1 つは、これをクエリの最後に追加して順序付けを強制することです。
ProductType1 @> ProductType2,
ProductType2 @> ProductType3.
これにより、3 つの製品タイプの 1 つの順列が得られ、見ている組み合わせの爆発がなくなります。
より洗練された手法は、setof/3
ソリューションを列挙するために使用することです。すべての回答をセットとして生成するため、値をソートする必要があります。これにより、安っぽいトリックと基本的に同じ方法で重複が削除されます。
more_than_two_product_types(Manufacturer) :-
setof(Manufacturer, T^manufacturer(T,Manufacturer), Manufacturers),
member(Manufacturer, Manufacturers),
setof(Type, Thing^(manufacturer(Thing, Manufacturer), store(Thing, Type)), [_,_,_|_]).
これはかなり複雑なので、分解してみましょう。まず、この条件はメーカーのリストを生成します。
setof(Manufacturer, T^manufacturer(T,Manufacturer), Manufacturers),
メタsetof/3
述語は、コンストラクター式、テンプレート式を受け取り、結果のリストを返します。これは、すべてのソリューションをmanufacturer(T, Manufacturer)
まとめてリストにまとめます。関心があるのは製造元の名前だけなので、テンプレートの引数はManufacturer
. T^
構文はがsetof/3
自由T
変数でmanufacturer(T, Manufacturer)
あることを示しているので、それが何にインスタンス化されるかは気にしません。これは不可欠setof/3
です。そうしないと、タイプごとに 1 つのソリューションが生成されますが、これは私たちが望んでいるものではありません。
この行は、製造元の新しいリストを繰り返します。
member(Manufacturer, Manufacturers),
この複雑な行は、メーカーが製造したすべてのタイプの製品を見つけます。
setof(Type, Thing^(manufacturer(Thing, Manufacturer), store(Thing, Type)), [_,_,_|_]).
ここでのゴール式は sequence(manufacturer(Thing, Manufacturer), store(Thing, Type))
です。これは、Thing
このメーカーの製品を見つけてType
、その製品の製品を見つけることを意味します。繰り返しになりますが、Thing^
構文は、物事が何であるかはあまり気にしないことを示しているため、すべてのType
ソリューションを一度に取得します。これを処理するためにリストにバインドする代わりに、テンプレート[_,_,_|_]
は少なくとも 3 つの項目を持つ任意のリストと統合します。それらのアイテムが何であるかはあまり気にしないので、それらはすべて空白です。コンソールでテストして、何が統合されるかを確認します。
?- [1,2,3] = [_,_,_|_].
true.
?- [1,2] = [_,_,_|_].
false.
?- [1,2,3,4] = [_,_,_|_].
true.
これは、少なくとも 3 つのソリューションを生成し、それらを破棄して成功するか、それより少ない場合は失敗します。
ご覧のとおり、Prolog で猫の皮を剥ぐ方法は複数あります。:)