loop1(a).
loop1(b).
loop1(c).
loop1(d).
circular(d, a).
circular(b, c).
circular(b, d).
circular(a, b).
所以我打电话给
in_cycle(a, Cycle).
它将返回:
[a,b,d,a]
如果我打电话给
in_cycle(b, Cycle).
它将返回:
[b,d,a,b].
但是,如果您致电:
in_cycle(c, Cycle).
它将返回:
false. (because no loop is included).
这是我的尝试:
in_cycle(C,Cycle) :- circular(C,Cycle1),in_cycle(Cycle1,Cycle).
我知道此谓词有一个非常严重的问题:它不会停止...我真的想知道我应该添加哪种基本情况,以便该谓词停止?我应该添加一个条件,以便序言在找到相同的字母时将停止吗?
如果有人能帮助我,将不胜感激!
-------更新-------
check([Y,_|Z]) :- check([Y|Z]).
in_cycle(C, [C]).
in_cycle(C, [C, C1|Cycle]) :- circular(C, C1),check([C,C1|Cycle]),
in_cycle(C1, [C1|Cycle]).
答案 0 :(得分:1)
circular(a, a).
是周期[a]
吗?知道最短的周期是什么,可以帮助您找到谓词的完成条件之一。in_cycle/2
从不提及任何列表。您需要在其中的某个地方使用[Head | Tail]
构造,才能将元素添加到列表中。 in_cycle(Current_symbol, Cycle, Start_symbol)
之类的谓词的事物。然后,您可以从in_cycle/2
拨打电话。让我们看看您的尝试:
in_cycle(C, Cycle) :-
circular(C, Cycle1),
in_cycle(Cycle1, Cycle).
您可以在提示符下使用the trace
command来查看正在发生的事情:trace, in_cycle(a, X).
按 Space 可以单步执行程序。按 h 寻求帮助,然后按 a 退出。使用notrace.
再次退出跟踪模式。
逐步浏览时,您会发现谓词很好地遍历了整个循环,但是X
从来没有成为列表。不好。
让我们尝试建立一个清单。正如我在第(3)点中提到的那样,您已经对列表有所了解。列表的第一个元素与in_cycle
的第一个参数相同。此外,列表的 second 元素与您在circular/2
中可以找到的元素相同。因此,我们知道一个循环至少包含两个元素。怎么样?
in_cycle(First, [First, Next|Cycle]) :-
circular(First, Next),
in_cycle(Next, [Next|Cycle]).
如果立即跟踪此内容,您会发现X
正在发生某些事情,但实际上并没有任何用处。 Cycle
仍然是个谜,我们只是在不断地了解事实。您在这里需要一些结束条件。让我们尝试一个简单的例子:
in_cycle(First, [First]).
in_cycle(First, [First, Next|Cycle]) :-
circular(First, Next),
in_cycle(Next, [Next|Cycle]).
哇! in_cycle(a, X)
突然产生结果!似乎所有以circular
开头的a
连接都使用的列表。那不是我们想要的,但是也许我们离我们越来越近了?
一个问题是in_cycle(Next, [Next|Cycle])
实际上不正确!
如果您执行in_cycle(a, X)
,就已经知道X
应该成为[a, b, d, a]
,因此将这些值填充到in_cycle(First, [First, Next|Cycle])
中,您将得到:
First = a
Next = b
Cycle = [d, a]
到达in_cycle(Next, [Next|Cycle])
时,表示为in_cycle(b, [b, d, a])
。但是[b, d, a]
不是一个循环!您需要能够以某种方式区分这两种情况。一种实现方法是调用一个单独的谓词,如我在(4)中提到的那样,以跟踪起始元素是什么。
答案 1 :(得分:1)
如果您可以找到返回该节点的路径,则该节点处于循环中。使用path/4
:
in_cycle(C, [C|Cs]) :-
circular(C, A),
path(circular, Cs, A,C).
现在,该谓词是否终止?我们如何系统地测试呢?我们如何确保我们不会忘记任何特殊情况?对于像这样的纯单调程序,终止测试是很简单的 1 :只需执行最通用的查询!那就是:
?- in_cycle(C, Cs).
C = d,
Cs = "dabd" % [d,a,b,d]
; C = b,
Cs = "bdab"
; C = a, Cs = "abda"
; false. % it terminates!
(请参见this answer,如何获得"bdab"
代替[b,d,a,b]
)。
Prolog的优点是上述查询构成了终止证明。您可以构成的每个查询都包含在上述查询中。并且由于更一般的查询已经终止,因此任何更具体的查询也将终止!任何!
所有这些都适用于circular/2
的任何变量自由事实。但是,这种证明不能像对一组特定事实的证明那样容易地进行。
1请注意,琐碎意味着属于trivium。