Prolog Predicate findall / 3和member / 2 Issue

时间:2016-03-08 06:54:16

标签: prolog

基本上,我的知识库中有关于PopStars及其最成功年份的一系列事实(见下文)。

popStar('Jackson',1987,1991).
popStar('Jackson',1992,1996).
popStar('Michaels',1996,2000).
popStar('Newcastle',2000,2007).
popStar('Bowie',2008,2010).

如果识别出popStar的名称,我需要创建一个带有单个参数的谓词,如果使用变量,它将产生回溯,没有任何重复。最初我开始时非常简单(见下文)。

  ispopStar ().
  ispopStar (H) :-  popStar (H,_,_).

但后来发现任何回溯都会包括重复(杰克逊'提到过两次)。因此,希望使用findall / 3创建一个列表,然后使用member来检查popStar是否是有效的。

但是,每当我尝试使用我从事实中创建的列表中的成员谓词时,它总会导致一个不停止的,不断扩展的列表。我认为这很可能是一个菜鸟错误,因为我才开始学习prolog。如果有人可以查看我下面的代码并且可以看到我做错了什么,真的很感激。

感谢。

的FindAll / 3

   findall(V,popStar(V,B,N),X)

结果

   X = ['Jackson', 'Jackson', 'Michaels', 'Newcastle', 'Bowie']

成员/ 2

   member('Newcastle',X).

结果

   339 ?- member('Newcastle',X).
   X = ['Newcastle'|_G2881] ;
   X = [_G2880, 'Newcastle'|_G2884] ;
   X = [_G2880, _G2883, 'Newcastle'|_G2887] ;
   X = [_G2880, _G2883, _G2886, 'Newcastle'|_G2890] ;
   X = [_G2880, _G2883, _G2886, _G2889, 'Newcastle'|_G2893]

更新

我玩过一次但仍然很困难。我使用下面的以下谓词来创建唯一条目列表;

  setof(Name,X^Y^popStar(Name),Names)

然后使用以下谓词表示元素的存在(下面的例子)。

 setof(Name,popStar(Name),Names), member('Jackson',Names). 

从上面的谓词中,它返回一个值;

 Names = ['Jackson'].

但实际上,我希望它能够恢复正常,因为'会员'证明特定元素是否在列表中。此外,当我尝试将变量插入成员(以便它回溯所有可用的popStars时,我收到以下消息)。

setof(Name,popStar(Name),Names), member(X,Names).

Names = ['$VAR'('X')].

通过向我展示在这个例子中做什么,真的很感激一些帮助。我真的被卡住了所以非常感激。

1 个答案:

答案 0 :(得分:3)

您的方法还有其他更微妙的问题,但首先是明显的问题。

顶级的查询彼此之间不共享变量。每个新查询都有新变量,即使它们使用相同的名称!

?- X = foo.
X = foo.

?- X = bar.
X = bar.

?- X = 3.
X = 3.

?- X == 3.
false.

你需要制作一个连接的子目标!

?- L = [a,b,c,b], member(a, L).
L = [a, b, c, b] ;
false.

?- L = [a,b,c,b], member(b, L).
L = [a, b, c, b] ;
L = [a, b, c, b].

正如你所看到的,这仍然不是你所追求的....如果一个列表有一个元素出现两次,member/2成功两次,这正是你不想要的。

您可以考虑使用memberchk/2代替。如果您比较member/2memberchk/2上的文档,您应该看到它们在语义和预期用途上的区别。简而言之,如果您已经有一个不包含任何变量的列表,并且您只想检查该列表是否包含某个元素,那么可以使用memberchk/2

?- L = [a,b,c,b], memberchk(a, L).
L = [a, b, c, b].

?- L = [a,b,c,b], memberchk(b, L).
L = [a, b, c, b].

如果memberchk/2的两个参数中的任何一个都没有根据,那么这会变得更加毛茸茸。看看这个:

?- memberchk(X, [a,b,c]).
X = a. % No more solutions!

所以,这不是解决问题的好方法。

最好使用setof/3代替findall/3。为简化一点,假设您有一个表foo/1,它看起来像上面示例中的列表:

?- listing(foo).

foo(a).
foo(b).
foo(c).
foo(b).

true.

?- findall(X, foo(X), Xs).
Xs = [a, b, c, b].

然后:

?- setof(X, foo(X), Xs), member(Y, Xs).
Xs = [a, b, c],
Y = a ;
Xs = [a, b, c],
Y = b ;
Xs = [a, b, c],
Y = c.

?- setof(X, foo(X), Xs), member(b, Xs).
Xs = [a, b, c] ;
false.

当你使用pop_star/3时,你可能不得不告诉Prolog不要将第二个和第三个参数绑定到setof/3,所以它会像setof(Name, X^Y^pop_star(Name, X, Y), Names)一样。