1

对于我的程序,知识库具有原子语句和规则,例如

store(itemName, ProductType)

例如:商店(iPhone5、手机)

manufacturer(itemName, Company)

例如:制造商(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 种苹果产品的正确答案,但按 more 一次又一次给出相同的答案。有没有办法阻止这种情况?

注意:我知道此站点上给出的其他问题的其他答案,但由于我对 Prolog 的了解有限并且不确定这些答案是否适用于这个问题,我不知道如何实施它们。

注意:对于这个问题,我不允许使用! ->;运算符

4

2 回答 2

1

不考虑性能问题,您的核心问题似乎是您寻找不同的产品类型,但产品本身存在变量。因此,例如对于假设的不同产品类型 T1、T2、T3 和产品 P1a P1b P1c 类型 T1、P2 类型 T2 和 P3 类型 T3,您将获得 (P1a,P2,P3), (P1b, P2,P3) 和 (P1C,P2,P3),从您的角度来看,它们都是等价的。

为避免这种情况,您需要将 (type,product) 对融合为每种类型的一个。

PS:如果您将代码缩减到暴露问题的最低限度(例如,该price谓词似乎没有必要)并为我们提供您拥有的实际输出,您会得到更好的答案。

于 2013-09-23T19:04:54.147 回答
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.

这将产生至少三个解决方案,然后将它们丢弃以获得成功,或者如果它产生的更少则失败。

如您所见,使用 Prolog 给猫剥皮的方法不止一种。:)

于 2013-09-24T04:46:32.073 回答