简体   繁体   English

Prolog Predicate findall / 3和member / 2 Issue

[英]Prolog Predicate findall/3 and member/2 Issue

Basically, have a series of facts in my Knowledge base regarding PopStars and their most successful years (see below). 基本上,我的知识库中有一系列关于PopStars及其最成功年份的事实(见下文)。

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

I need to create a predicate that takes a single parameter that is true if the name of the popStar is recognized and, if a variable is used instead, it would produce backtracking, without any duplicates. 如果识别出popStar的名称,我需要创建一个带有单个参数的谓词,如果使用变量,它将产生回溯,没有任何重复。 Originally I started off with something very simple (see below). 最初我开始时非常简单(见下文)。

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

But then figured out that any backtracking would include duplicates ('Jackson' mentioned twice). 但后来发现任何回溯都会包括重复('杰克逊'两次提到)。 So, looking to create a list using findall/3 and then use member to check whether the popStar is a valid one. 因此,希望使用findall / 3创建一个列表,然后使用member来检查popStar是否是有效的。

However, whenever I attempt to use the member predicate on the list I've created from the facts, it would always result in an non-stopping, ever expanding list. 但是,每当我尝试使用我从事实创建的列表中的成员谓词时,它总会导致一个不停止的,不断扩展的列表。 I think it could well be a noob error as I've only just started learning prolog. 我认为这很可能是一个菜鸟错误,因为我刚开始学习prolog。 Would really appreciate it if someone could take a look at my code below and could see what I'm doing wrong. 如果有人可以看看我下面的代码并且能看到我做错了什么,真的很感激。

Thanks. 谢谢。

Findall/3 的findall / 3

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

Result 结果

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

Member/2 会员/ 2

   member('Newcastle',X).

Result 结果

   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]

Update 更新

I've had a play around but still very stuck. 我玩过一次但仍然很困难。 I'm using the following predicate below to create a list of unique entries; 我正在使用下面的以下谓词来创建唯一条目列表;

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

And then using the following predicate for the existence of an element (example below). 然后使用以下谓词表示元素的存在(下面的例子)。

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

From the predicate above, it returns a value of; 从上面的谓词中,它返回一个值;

 Names = ['Jackson'].

But really, I would expect it to return true, as 'member' certifies whether a specific elements is within a list. 但实际上,我希望它返回true,因为'member'证明特定元素是否在列表中。 Also, when I try to insert a variable into member (so that it backtracks through all of the available popStars, I receive the following message). 此外,当我尝试将变量插入成员(以便它回溯所有可用的popStars时,我收到以下消息)。

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

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

Would really appreciate some help by showing me what to do in this example. 通过向我展示在这个例子中做什么,真的很感激一些帮助。 I'm really stuck so really appreciate it. 我真的被卡住了所以真的很感激。

There are other more subtle problems with your approach, but first the obvious problem. 您的方法还有其他更微妙的问题,但首先是明显的问题。

Queries on the top level do not share variables between each other. 顶层的查询不会在彼此之间共享变量 Each new query has new variables, even if they use the same name! 每个新查询都有新变量,即使它们使用相同的名称!

?- X = foo.
X = foo.

?- X = bar.
X = bar.

?- X = 3.
X = 3.

?- X == 3.
false.

You need to make a conjunction of subgoals! 你需要结合子目标!

?- 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].

As you see, this is still not what you are after.... If a list has an element occurring twice, member/2 succeeds twice, and this is exactly what you don't want. 如你所见,这仍然不是你所追求的....如果一个列表有一个元素出现两次, member/2成功两次,这正是你不想要的。

You could consider using memberchk/2 instead. 您可以考虑使用memberchk/2 If you compare the documentation on member/2 and memberchk/2 you should see how they differ in semantics and intended use. 如果比较member/2memberchk/2上的文档,您应该看到它们在语义和预期用途上的区别。 In short, if you already have a list that does not contain any variables, and you only want to check if that list contains a certain element, it is OK to use memberchk/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].

This gets more hairy if any of the two arguments to memberchk/2 is not ground. 如果memberchk/2的两个参数中的任何一个都没有被接地,那么这会变得更加毛茸茸。 Look at this: 看这个:

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

So, this is not a good way to solve your problem. 所以,这不是解决问题的好方法。

It is maybe better to use setof/3 instead of findall/3 . 使用setof/3而不是findall/3可能更好。 To simplify a bit, say you have a table foo/1 that looks like the list from the example above: 为简化一点,假设您有一个表foo/1 ,它看起来像上面示例中的列表:

?- listing(foo).

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

true.

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

Then: 然后:

?- 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.

You would have to probably tell Prolog not to bind the second and third argument to pop_star/3 when you use setof/3 , so it would go something along the lines of setof(Name, X^Y^pop_star(Name, X, Y), Names) . 当你使用setof/3 ,你可能不得不告诉Prolog不要将第二个和第三个参数绑定到pop_star/3 ,所以它会沿着setof(Name, X^Y^pop_star(Name, X, Y), Names)的行setof(Name, X^Y^pop_star(Name, X, Y), Names)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM