【问题标题】:Prolog Predicate findall/3 and member/2 IssueProlog 谓词 findall/3 和 member/2 问题
【发布时间】:2016-03-08 06:54:16
【问题描述】:

基本上,我的知识库中有一系列关于流行歌星及其最成功岁月的事实(见下文)。

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

我需要创建一个谓词,该谓词采用单个参数,如果 popStar 的名称被识别,则该参数为 true,如果使用变量代替,它将产生回溯,没有任何重复。最初我从一些非常简单的东西开始(见下文)。

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

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

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

谢谢。

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

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

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

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

非常感谢通过向我展示在此示例中的操作来提供帮助。我真的被卡住了,所以真的很感激。

【问题讨论】:

  • setof(Name,popStar(Name),Names), member('Jackson',Names). 将会成功(你称之为“返回真”)并向你展示它为变量 Names 得出的结果。这就是它的工作原理。您能否解释一下您的意思,当我尝试将变量插入到成员中时,以及您想要实现的目标是什么?

标签: prolog


【解决方案1】:

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

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

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

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

【讨论】:

  • 嗨@Boris .. 已经尝试过,但仍然没有运气 - 已将更新发布到我的原始帖子 - 非常感谢您能提供的任何进一步帮助
  • @SamNeeds 您仍然没有正确使用setof/3:通过您自己的阅读,您应该能够弄清楚。您定义的谓词popStar/3 有3 个参数;当把它交给setof/3时,你用一个参数写它。如果您按照我在回答中显示的那样输入它,带有 3 个参数,它肯定可以满足您的需求。
  • 是的,谢谢您-现在设法弄清楚了大部分-感谢您的帮助。
  • 对不起 - 一直感谢人们的贡献。将标记您的答案。谢谢。
  • @SamNeeds 感谢是礼貌的;投票和接受也是问题和答案对其他人有用的方式。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-07-17
  • 2014-01-26
  • 2018-05-14
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多