Prolog 变量查询中的“\+”问题

发布于 2024-11-06 19:39:10 字数 1130 浏览 0 评论 0原文

我正在读《七周七种语言》atm,我对一些 Prolog 查询感到困惑,我不明白对“否”的回答。

friends.pl 文件如下所示:

likes(wallace, cheese).
likes(grommit, cheese).
likes(wendolene, sheep).

friend(X, Y) :- \+(X = Y), likes(X, Z), likes(Y, Z).

我可以对其进行一些简单的查询,例如:

| ?- ['friends'].
compiling /home/marc/btlang-code/code/prolog/friends.pl for byte code...
/home/marc/btlang-code/code/prolog/friends.pl compiled, 12 lines read - 994 bytes written, 8 ms

yes
| ?- friend(wallace,grommit).

yes
| ?- friend(wallace,wendolene).

no

这一切都符合预期。现在,我想在查询中引入一个变量。我的意图是 Prolog 将为我提供华莱士所有朋友的列表。我期待 X = grommit,但得到 no

| ?- trace.
The debugger will first creep -- showing everything (trace)

yes
{trace}
| ?- friend(wallace,X).
      1    1  Call: friend(wallace,_16) ?
      2    2  Call: \+wallace=_16 ?
      3    3  Call: wallace=_16 ?
      3    3  Exit: wallace=wallace ?
      2    2  Fail: \+wallace=_16 ?
      1    1  Fail: friend(wallace,_16) ?

no
{trace}

它甚至没有尝试统一 X (_16)与grommit。为什么?

I'm reading "Seven languages in seven weeks" atm, and I'm stumped over some Prolog query that I don't understand the 'no' response to.

The friends.pl file looks like this:

likes(wallace, cheese).
likes(grommit, cheese).
likes(wendolene, sheep).

friend(X, Y) :- \+(X = Y), likes(X, Z), likes(Y, Z).

I can do some trivial queries on it, such as:

| ?- ['friends'].
compiling /home/marc/btlang-code/code/prolog/friends.pl for byte code...
/home/marc/btlang-code/code/prolog/friends.pl compiled, 12 lines read - 994 bytes written, 8 ms

yes
| ?- friend(wallace,grommit).

yes
| ?- friend(wallace,wendolene).

no

This is all as expected. Now, I want to introduce a variable in the query. My intent being that Prolog will give me a list of all of Wallace's friends. I'm expecting X = grommit, but I'm getting no:

| ?- trace.
The debugger will first creep -- showing everything (trace)

yes
{trace}
| ?- friend(wallace,X).
      1    1  Call: friend(wallace,_16) ?
      2    2  Call: \+wallace=_16 ?
      3    3  Call: wallace=_16 ?
      3    3  Exit: wallace=wallace ?
      2    2  Fail: \+wallace=_16 ?
      1    1  Fail: friend(wallace,_16) ?

no
{trace}

It doesn't even try to unify X (_16) with grommit. Why?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

清音悠歌 2024-11-13 19:39:10

这是朋友的定义:

friend(X, Y) :- \+(X = Y), likes(X, Z), likes(Y, Z).

这里重要的是你以 \+(X = Y) 开头,通常定义为:

\+ Goal :- Goal,!,fail

请注意,这意味着如果目标成功,你肯定会失败。自由变量(尚未分配的变量)将始终统一,因此是相等的,因此自由变量总是会失败。因此,如果 X 或 Y 还没有值,它永远不会分配值。

相反,他们的

friend(X, Y) :-  likes(X, Z), likes(Y, Z), \+(X = Y)

行为会更加符合你的预期。

这里的问题是 prolog 为您提供了控制程序流程的强大方法,但这些方法并不太适合其更面向逻辑的设计。应该可以以不会产生这些问题的方式表达“否定为失败”类型的约束。由于这个原因,我并不是 prolog 的忠实粉丝。

It is the definition of friend:

friend(X, Y) :- \+(X = Y), likes(X, Z), likes(Y, Z).

The important thing here is that you start with \+(X = Y) which is normally defined as:

\+ Goal :- Goal,!,fail

Note that this means that if goal succeeds, you are sure to fail. Free variables (ones that havent been assigned) will always unify, and thus be equal, so you will always fail with a free variable. It will thus never assign a value to X or Y if it doesn't already have one.

Instead

friend(X, Y) :-  likes(X, Z), likes(Y, Z), \+(X = Y)

will behave more as you expect.

The problem here is that prolog gives you powerful ways to control the flow of programs, but those dont really fit nicely with its more logic oriented design. It should be possible to express "negation as failure" type constraints in a way that does not produce these problems. I'm not a huge prolog fan for this reason.

风吹雨成花 2024-11-13 19:39:10

关于 Philip JF 的上述评论:

应该可以表达
“否定即失败”类型约束
以一种不产生这些的方式
问题。

这是可能的:此类问题的现代解决方案是约束。在这种情况下,请使用例如 dif/2,它在所有严肃的 Prolog 系统中都可用。

Regarding Philip JF's comment above:

It should be possible to express
"negation as failure" type constraints
in a way that does not produce these
problems.

This is possible: The modern solution for such problems are constraints. In this case, use for example dif/2, available in all serious Prolog systems.

苹果你个爱泡泡 2024-11-13 19:39:10

friend/2 的第一个子目标是 \+(X = Y)。这是通过首先尝试找到 X = Y 的解决方案,然后否定该结果来执行的。谓词 =/2 大致相当于 unify/2,即它尝试将左操作数与右操作数统一。现在,当您使用例如 friend(wallace, gromit) 进行查询时,wallacegromit 这两个原子不会统一;但是当一个自由变量被放入混合中时,它总是与给定的任何术语统一,因此 X = Y 总是成功的,因此 \+(X = Y)总是失败,并且执行永远不会超过第一个子目标。

The first subgoal of friend/2 is \+(X = Y). This is executed by first trying to find a solution for X = Y, then negating that result. The predicate =/2 is roughly the equivalent of unify/2, that is it tries to unify the left operand with the right operand. Now, when you are asking queries using e.g. friend(wallace, gromit), the two atoms wallace and gromit do not unify; but when a free variable is thrown into the mix, it always unifies with whatever term is given, so X = Y is always successful, therefore \+(X = Y) always fails, and the execution never gets past that first subgoal.

极度宠爱 2024-11-13 19:39:10

首先具有不等式约束的另一个问题是:无法找到未绑定的 X 的绑定(暂时排除将其与 grommit 统一的简单情况)。 Prolog 通过运行其数据库来查找绑定,尝试统一未绑定的变量。这就是为什么 likes(grommit, Z) 会找到一些 Z 的绑定,然后可以进一步处理,因为在数据库。但是没有这样的子句来表示 gromit 与某些东西的不等式,因此 Prolog 无法产生任何绑定。按照目前的情况,friend 谓词必须确保所有变量都已绑定,然后才能测试不等式。

Another issue with having the inequality constraint first is: It is uncapable to find a binding for the unbound X (excluding the trivial case of unifying it with grommit for the moment). Prolog finds bindings by running through its database, trying to unify the unbound variable. That is why likes(grommit, Z) will find some binding for Z which can then be further processed, because there are likes clauses in the database. But there are no such clauses for the inequality of grommit with something, so Prolog cannot produce any bindings. As things stand, the friend predicate has to make sure that all variables are bound before the inequality can be tested.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文