Prolog:具有计算结束条件的递归问题

发布于 2024-10-31 09:16:24 字数 887 浏览 0 评论 0原文

我正在尝试在 Prolog 中对一组齿轮进行建模。并查询两个轮子是否由其他轮子连接起来。

我有一个简单的递归:

connected(X,Y) :-   
    engages(X,Y).

connected(X,Y) :-
    engages(X,Z),
    connected(Z,Y).

如果我根据硬连线谓词定义参与:

engages(X,Y) :- touches(X,Y).

然后

touches(z1,z2).
touches(z2,z3).
touches(z3,z4).

这有效。

的测试

connected(z1,z4).

产生 true 并

connected(z1,z5).

产生 false。

但是,如果我用计算替换触摸谓词(两个半径的总和大致等于两个中心之间的距离),那么当答案应该为 false 时,此搜索将进入看起来像无限递归(堆栈溢出)的情况。

鉴于我的“接触”计算本身并不调用“连接”函子,为什么会这样呢?是因为接触函子会尝试匹配比显式谓词更多的原子吗?

粗略地说,这是我计算出的接触点(A 和 B 是轮子,ARAD 和 BRAD 是它们的半径,D 是距离,approx 是“大约等于”函数。

touches(A,B) :- 
    wheel(A,_,_,ARAD),
    wheel(B,_,_,BRAD),
    distance(A,B,D),
    approx(D,(ARAD+BRAD),2),
    A \== B.

I'm trying to model a set of cog wheels in Prolog. And to query to find if two wheels are connected by a chain of others.

I have a simple recursion :

connected(X,Y) :-   
    engages(X,Y).

connected(X,Y) :-
    engages(X,Z),
    connected(Z,Y).

If I define engages in terms of a hard-wired predicate :

engages(X,Y) :- touches(X,Y).

and

touches(z1,z2).
touches(z2,z3).
touches(z3,z4).

Then this works.

A test of

connected(z1,z4).

produces true and

connected(z1,z5).

produces false.

However, if I replace my touches predicate with a calculation (that the sum of the two radii is roughly the distance between the two centres), then this search goes into what looks like an infinite recursion (stack overflow) when the answer should be false.

Why should this be, given that my "touches" calculation doesn't itself call the "connected" functor? Is it because a touches functor is going to try to match more atoms than the explicit predicates?

This, roughly, is my calculated touches (A and B are the wheels, ARAD and BRAD are their radii, D is distance and approx is an "approximately equals" function.

touches(A,B) :- 
    wheel(A,_,_,ARAD),
    wheel(B,_,_,BRAD),
    distance(A,B,D),
    approx(D,(ARAD+BRAD),2),
    A \== B.

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

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

发布评论

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

评论(1

终弃我 2024-11-07 09:16:24

发生无限递归是因为程序不检查循环。可能会发生以下情况:

  1. 程序找到了轮子 AB,它们相互接触。
  2. 给定B,它会寻找一个接触的轮子。它找到A
  3. 转到 1。

您可以阻止它维护已在 connected 的额外参数中考虑的“封闭组”轮子:(

connected(X,Y) :-
    connected(X,Y,[]).
connected(X,Y,Closed) :-
    touches(X,Y),
    \+ memberchk(Y,Closed).
connected(X,Z,Closed) :-
    touches(X,Y),
    \+ memberchk(Y,Closed),
    connected(Y,Z,[Y|Closed]).

给读者的练习:缩短它。)

The infinite recursion occurs because the program doesn't check for cycles. Here's what might happen:

  1. The program finds wheels A and B, that touch.
  2. Given B, it looks for a wheel that touches. It finds A.
  3. Goto 1.

You can prevent this from maintaining a "closed set" of wheels already considered in an extra argument to connected:

connected(X,Y) :-
    connected(X,Y,[]).
connected(X,Y,Closed) :-
    touches(X,Y),
    \+ memberchk(Y,Closed).
connected(X,Z,Closed) :-
    touches(X,Y),
    \+ memberchk(Y,Closed),
    connected(Y,Z,[Y|Closed]).

(Exercise for the reader: shorten this.)

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