GNU Prolog - 递归问题(简单?)

发布于 2024-09-27 20:45:39 字数 606 浏览 1 评论 0原文

好的,所以我有这个

edu_less(hs,college).
edu_less(college,masters).
edu_less(masters,phd).

,我需要编写一个函数来判断某些东西是否小于另一个。谓词是

edu_le.

So if i put edu_le(hs,phd). 它应该返回 yes。 我想出了这个。

edu_le(A,B) :- A = B.
edu_le(A,B) :- edu_less(A,B).
edu_le(A,B) :- edu_less(A,C), edu_le(C,B).

我真的不希望它遍历所有内容并返回多个答案。

如果发现它实际上小于或等于第二个参数,是否可以只返回 yes 或 no?

所以基本上,如果我再次使用示例 edu_le(hs,phd),那么因为 hs 小于 College,而 College 小于 Master,而 Master 小于 phd,那么 hs 必定小于 phd它会说是的。

抱歉,序言真的很新,仍在尝试掌握这一点。

Ok, so i have this

edu_less(hs,college).
edu_less(college,masters).
edu_less(masters,phd).

I need to write a function to tell if something is less than the other. The predicate is

edu_le.

So if i put edu_le(hs,phd). it should return yes.
I came up with this.

edu_le(A,B) :- A = B.
edu_le(A,B) :- edu_less(A,B).
edu_le(A,B) :- edu_less(A,C), edu_le(C,B).

I really don't want it to go through everything and return multiple answers.

Is it possible to only return yes or no if it finds that it is in fact less than or equal to the 2nd argument?

So basically if i use the example edu_le(hs,phd) again, then because hs is less than college, and college is than masters, and masters is less than phd, then hs must be less than phd and it would say yes.

Sorry, really new to prolog, still trying to get the hang of this.

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

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

发布评论

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

评论(4

宫墨修音 2024-10-04 20:45:39

在谓词定义中,

edu_le(A,B) :- A = B.
edu_le(A,B) :- edu_less(A,B).
edu_le(A,B) :- edu_less(A,C), edu_le(C,B).

第二个子句是多余的,会导致重复生成答案。使用

edu_le(A,B) :- A = B.
edu_le(A,B) :- edu_less(A,C), edu_le(C,B).

这会给您一个true答案,然后在回溯时不再有答案(false)。您可以在第一个子句中使用剪切,但随后生成将不再起作用。

?- edu_le(hs,X).
X = hs ;
X = college ;
X = masters ;
X = phd ;
false.

变得不完整:

?- edu_le(hs,X).
X = hs.

正如 mat 所建议的,使用 once/1 代替。在良好的 Prolog 实现中,该谓词的工作方式就好像您的程序在战略位置进行了削减,从而在不干扰其逻辑语义的情况下加速您的程序。

In the predicate definition

edu_le(A,B) :- A = B.
edu_le(A,B) :- edu_less(A,B).
edu_le(A,B) :- edu_less(A,C), edu_le(C,B).

the second clause is superfluous and causes repeated generation of answers. Use

edu_le(A,B) :- A = B.
edu_le(A,B) :- edu_less(A,C), edu_le(C,B).

This gives you one true answer, then no more answers (false) on backtracking. You can use a cut in the first clause, but then generating won't work anymore.

?- edu_le(hs,X).
X = hs ;
X = college ;
X = masters ;
X = phd ;
false.

becomes incomplete:

?- edu_le(hs,X).
X = hs.

As mat suggested, use once/1 instead. In a good Prolog implementation, this predicate works as if your program had cuts in strategic places, speeding up your program without disturbing its logical semantics.

请叫√我孤独 2024-10-04 20:45:39

编写此类谓词的最实用方法是使用剪切 (!)。削减导致回溯时不考虑进一步的条款。您可以将谓词编写如下:

edu_le(A,B) :- A = B, !.
edu_le(A,B) :- edu_less(A,B), !.
edu_le(A,B) :- edu_less(A,C), edu_le(C,B).

最后一个子句不需要剪切,因为无论如何都没有其他子句需要考虑。剪切是在任何测试之后进行的,以确定该子句是否应该成功。

逻辑编程纯粹主义者不赞成剪切,因为它使谓词的含义取决于子句的顺序,这与数学中的逻辑不同。

The most practical way to write predicates like that is to use the cut (!). The cut causes further clauses not to be considered when backtracking. You would write your predicate as following:

edu_le(A,B) :- A = B, !.
edu_le(A,B) :- edu_less(A,B), !.
edu_le(A,B) :- edu_less(A,C), edu_le(C,B).

The last clause does not need a cut because there are no further clauses to consider anyway. The cut is placed after any tests to determine whether the clause should succeed.

Logic programming purists disapprove of the cut, because it makes the meaning of a predicate depend on the ordering of the clauses, which is unlike logic in mathematics.

老旧海报 2024-10-04 20:45:39

!/0 也会使这个程序不完整,例如考虑两个版本的最通用查询:

?- edu_le(X, Y).

如果您只想要特定目标的单个证明,通常最好使用一次/1:

?- once(edu_le(hs, phd)).

!/0 also makes this program incomplete, consider for example the most general query with both versions:

?- edu_le(X, Y).

It is often better to use once/1 if you only want a single proof of a particular goal:

?- once(edu_le(hs, phd)).
长梦不多时 2024-10-04 20:45:39

我建议你不要遵循 Juho Östman 提出的路径并保持纯洁性 - 否则,为什么你应该首先使用 Prolog?如果你过于宽容地坚持逻辑范式,你会得到一些令人不快的结果。在这种情况下,Juho 的谓词肯定与您的不同,我将向您展示原因。

首先,按照 larsmans 的建议,删除无用的 edu_le(A,B) :- edu_less(A,B). 规则。您将获得原始谓词的冗余度较低的版本:

edu_le1(A, A).
edu_le1(A, B) :- edu_less(A, C), edu_le1(C, B).

它的行为与 edu_le 相同,意思是:给定任意查询,它会生成完全相同的答案,除了重复项 (edu_le1 较少)。你可能只是对它感到满意,但它仍然有一些你可能不喜欢的冗余答案;例如,在SWI下:

?- edu_le1(hs, hs)
true ;
false.

现在你可能会说你不喜欢它,因为它仍然有多余的false,但是如果你使用Juho的谓词来代替(没有无用的规则):

edu_le2(A, A) :- !.
edu_le2(A, B) :- edu_less(A, C), edu_le2(C, B).

你确实消除了无用的Final false

?- edu_le2(hs, hs)
true.

?-

但你失去的不止于此:正如 mat 所说,当一个变量未实例化时,你失去了生成所有解决方案的可能性:

?- edu_le1(hs, B) %same, with more copies, for edu_le
B = hs ;
B = college ;
B = masters ;
B = phd ;
false.

?- edu_le2(hs, B)
B = hs.           %bad!

?-

换句话说,后一个谓词不等于前者:edu_leedu_le1 的类型为 edu_le(?A, ?B),而 edu_le2 的类型为 < code>edu_le2(+A, +B) (含义参见[1])。请确保:edu_le2 的用处较小,因为它执行的操作较少,因此可以在较少的上下文中重用。这是因为edu_le2 中的剪切是红色剪切,即改变了引入它的谓词的含义的剪切。不过,鉴于您了解两者之间的区别,您可能会对此感到满意。这完全取决于您想用它做什么。

如果您想充分利用这两个世界,则需要在 edu_le1 中引入适当的绿色剪切,以在 A 和 B 完全实例化为项时降低冗余。为此,您必须在切割之前检查 A 和 B 是否已实例化为相同的项。您不能使用 = 来执行此操作,因为 = 不会检查,而是统一。正确的运算符是 ==

edu_le3(A, B) :- (A == B -> ! ; true), A = B.
edu_le3(A, B) :- edu_less(A, C), edu_le3(C, B).

请注意,仅当 AB 恰好是同一个术语时,第一条规则中的附加剪切才有效。既然切割是正确的绿色切割,那么在最常见的情况下,谓词也可以像原始情况一样工作:

?- edu_le3(A, A).
true.

?- edu_le3(A, B).  %note that A and B are not the same term
A = B ;
A = hs,
B = college ;
A = hs,
B = masters ;
A = hs,
B = phd ;
A = college,
B = masters ;
A = college,
B = phd ;
A = masters,
B = phd ;
false.

?-

通过 Prolog 回溯所有解决方案。

我认为没有某种方法可以消除最后一个 false 而不引入对 edu_lt 的过强依赖。这是因为我们必须保持开放的可能性,即有另一个 edu_lt 可供探索,以防您稍后决定用更多基础事实来丰富它。所以,在我看来,这是你能拥有的最好的。

[1] SWI Prolog 参考手册,第 4.1 节。

I would suggest you NOT to follow the path proposed by Juho Östman and keep purity - otherwise, why should you use Prolog in first instance? If you are too lenient with sticking to the logical paradigm you obtain some unpleasing results. In this case, Juho's predicate is definitely different from yours, and I'll show you why.

First, just drop the useless edu_le(A,B) :- edu_less(A,B). rule, as larsmans suggests. You will obtain a less redundant version of your original predicate:

edu_le1(A, A).
edu_le1(A, B) :- edu_less(A, C), edu_le1(C, B).

It just behaves as edu_le, meaning: given an arbitrary query, it produces exactly the same answer, except for duplicates (edu_le1 has less). You may just be happy with it, but it still has some redundant answers that you may not like; e.g, under SWI:

?- edu_le1(hs, hs)
true ;
false.

Now you may say you do not like it because it still has the redundant false, but if you use Juho's predicate instead (without the useless rule):

edu_le2(A, A) :- !.
edu_le2(A, B) :- edu_less(A, C), edu_le2(C, B).

it's true that you eliminate the useless final false:

?- edu_le2(hs, hs)
true.

?-

but you lose more than that: You lose, as mat remarks, the possibility of generating all the solutions when one variable is not instantiated:

?- edu_le1(hs, B) %same, with more copies, for edu_le
B = hs ;
B = college ;
B = masters ;
B = phd ;
false.

?- edu_le2(hs, B)
B = hs.           %bad!

?-

In other words, the latter predicate is NOT equivalent to the former: edu_le and edu_le1 have type edu_le(?A, ?B), while instead edu_le2 has type edu_le2(+A, +B) (see [1] for the meaning). Be sure: edu_le2 is less useful because it does less things, and thus can be reused in less contexts. This because the cut in edu_le2 is a red cut, i.e., a cut that changes the meaning of the predicate where it is introduced. You may nevertheless be content with it, given that you understand the difference between the two. It all depends on what you want to do with it.

If you want to get the best of the two worlds, you need to introduce in edu_le1 a proper green cut that lowers the redundancy when A and B are completely instantiated to terms. At the purpose, you must check that A and B are instantiated to the same term before cutting. You cannot do it with =, because = does not check, but unifies. The right operator is ==:

edu_le3(A, B) :- (A == B -> ! ; true), A = B.
edu_le3(A, B) :- edu_less(A, C), edu_le3(C, B).

Note that the additional cut in the first rule is active only when A and B happen to be the same term. Now that the cut is a proper green cut, the predicate works also in the most general cases as your original one:

?- edu_le3(A, A).
true.

?- edu_le3(A, B).  %note that A and B are not the same term
A = B ;
A = hs,
B = college ;
A = hs,
B = masters ;
A = hs,
B = phd ;
A = college,
B = masters ;
A = college,
B = phd ;
A = masters,
B = phd ;
false.

?-

with Prolog backtracking through all the solutions.

I don't think there is some way to eliminate the last false without introducing too strong dependency on edu_lt. This because we must keep open the possibility that there is another edu_lt to explore, in the case you decide later to enrich it with more ground facts. So, in my opinion, this is the best you can have.

[1] SWI Prolog reference manual, section 4.1.

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