对于我的程序,知识库具有原子语句和规则,例如
store(itemName, ProductType)
ex:store(iPhone5,手机)
manufacturer(itemName, Company)
ex:制造商(iPhone5,苹果)
查询是要确定是否有一家公司制造了超过2种不同的产品类型,因此对于苹果来说,将有Macbook,iPad和iPhone
以下是我们的查询:
?- store(ItemID1, ProductType1), manufacturer(ItemID1, Company), store(ItemID2, ProductType2), manufacturer(ItemID2, Company), store(ItemID3, ProductType3), manufacturer(ItemID3, Company), not ProductType1 = ProductType2, not ProductType1 = ProductType3, not ProductType2 = ProductType3.
它给出了正确的答案,列出了3个苹果产品,但是按下更多会一次又一次给出相同的答案。有办法阻止这个吗?
注意:我知道本网站提供的其他问题的其他答案,但由于我对Prolog知之甚少而不确定这些答案是否适用于此问题,因此不知道如何实施这些问题。
注意:对于此问题,我不得使用!
->
和;
运营商
答案 0 :(得分:1)
折扣性能问题,您的核心问题似乎是您寻找不同的产品类型,但产品本身有变量。因此,例如对于假设的不同产品类型T1,T2,T3和T1类型的产品P1a P1b P1c,T2类型的P2和T3类型的P3,您将获得(P1a,P2,P3),(P1b, P2,P3)和(P1C,P2,P3),从你的角度来看都是等价的。
为避免您需要将(类型,产品)对融合为每种类型的一对。
PS:如果你将代码减少到暴露问题的最小值(例如,price
谓词似乎没必要),你会得到更好的答案,并为我们提供你的实际输出。
答案 1 :(得分:1)
我认为除了JB的推荐之外,还有其他一些方法可以解决它。一个俗气的伎俩是通过将其添加到查询的末尾来强制执行ProductTypeN
的排序:
ProductType1 @> ProductType2,
ProductType2 @> ProductType3.
这将为您提供三种产品类型的一种排列,消除您所看到的组合爆炸。
更复杂的技术是使用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
是一个自由变量,所以我们不关心它实例化的内容。这是必不可少的,或者member(Manufacturer, Manufacturers),
本身会为每种类型生成一个解决方案,这不是我们想要的。
这一行重复了新的制造商名单:
setof(Type, Thing^(manufacturer(Thing, Manufacturer), store(Thing, Type)), [_,_,_|_]).
这条复杂的产品系列可以找到制造商生产的所有类型的产品:
(manufacturer(Thing, Manufacturer), store(Thing, Type))
此处的目标表达式是序列Thing
。这就是说,找到这个制造商制作的Type
,然后找到那个东西的Thing^
。同样,Type
语法表示我们并不关心事物是什么,因此请立即获取所有[_,_,_|_]
个解决方案。模板?- [1,2,3] = [_,_,_|_].
true.
?- [1,2] = [_,_,_|_].
false.
?- [1,2,3,4] = [_,_,_|_].
true.
与包含至少三个项目的任何列表统一,而不是将其绑定到我们要处理的列表。我们并不在乎这些物品是什么,所以它们都是空白的。在您的控制台中进行测试并查看它与之结合的内容:
{{1}}
这将产生至少三个解决方案,然后将它们抛弃以取得成功,或者如果它产生的更少则失败。
正如您所看到的,使用Prolog给猫咪涂抹的方法不止一种。 :)