简体   繁体   English

SWI-prolog:如何通过使用一些事实制作一份循环清单

[英]SWI-prolog : how to make a circular list by using some facts

loop1(a).
loop1(b).
loop1(c).
loop1(d).

circular(d, a).
circular(b, c).
circular(b, d).
circular(a, b).

so when I call: 所以当我打电话:

in_cycle(a, Cycle). 

it will return: 它会返回:

[a,b,d,a]

if I call: 如果我打电话给:

in_cycle(b, Cycle).

it will return: 它会返回:

[b,d,a,b].

however, if you call: 但是,如果您致电:

in_cycle(c, Cycle).

it will return: 它会返回:

false. (because no loop is included).

here is my try: 这是我的尝试:

in_cycle(C,Cycle) :- circular(C,Cycle1),in_cycle(Cycle1,Cycle).

I know this predicate has very serious problem : it won't stop...I really want to know what kind of base case I should add so this predicate will stop ? 我知道此谓词有一个非常严重的问题:它不会停止...我真的想知道我应该添加哪种基本情况,以便该谓词停止? Should i add a condition so prolog will stop when it find the same alphbet ? 我应该添加一个条件,以便当序言找到相同的字母时,序言将停止吗?

It would be grateful if someone could help me! 如果有人可以帮助我,将不胜感激!

-------updated------- - - - -更新 - - - -

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]).
  1. What is the shortest cycle you could have in your fact database? 您的事实数据库中最短的周期是多少? Would circular(a, a). 会是circular(a, a). be cycle [a] ? 被循环[a] Knowing what the shortest cycle is might help you find (one of) the finishing condition(s) for your predicate. 知道最短的周期是什么,可以帮助您找到谓词的完成条件(其中之一)。
  2. To be able to find a list, your predicate needs to build it. 为了能够找到列表,您的谓词需要构建它。 Your in_cycle/2 never mentions any lists. 您的in_cycle/2永远不会提及任何列表。 You need to use the [Head | Tail] 您需要使用[Head | Tail] [Head | Tail] construct somewhere in there to be able to add elements to a list. [Head | Tail]构造在其中某处,以便能够将元素添加到列表中。
  3. You already know something about what your cyclical list looks like. 您已经对周期性列表的外观有所了解。 The first and last element are the same, and they are the same as the symbol you're trying to find the cycle for. 第一个和最后一个元素相同,并且与您要为其查找循环的符号相同。 Use that information. 使用该信息。
  4. To be able to tell when you completed a cycle, you need to remember which symbol you started with. 为了能够告诉您何时完成一个循环,您需要记住从哪个符号开始。 To be able to do that with recursion, you need to keep state. 为了能够通过递归做到这一点,您需要保持状态。 So you're going to need an additional predicate where you keep that state. 因此,您将需要一个附加谓词来保存该状态。 Eg something involving a predicate like in_cycle(Current_symbol, Cycle, Start_symbol) . 例如,涉及谓词的事物如in_cycle(Current_symbol, Cycle, Start_symbol) You can then call that from your in_cycle/2 . 然后,您可以从in_cycle/2调用它。

Let's have a look at your try: 让我们看看您的尝试:

in_cycle(C, Cycle) :-
    circular(C, Cycle1),
    in_cycle(Cycle1, Cycle).

You can use the trace command at the prompt to see what's happening: trace, in_cycle(a, X). 您可以在提示符处使用trace命令查看正在发生的情况: trace, in_cycle(a, X).

Press Space to step through your program. 空格键单步执行程序。 Press h for help, and a to exit. h寻求帮助,按a退出。 Use notrace. 使用notrace. to get out of trace mode again. 再次退出跟踪模式。

As you step through this, you'll find that your predicate is nicely looping through the cycle, but at no point does the X ever become a list. 在逐步执行此过程时,您会发现谓词很好地循环了整个循环,但是X永远不会成为列表。 That's bad. 那很糟。

Let's try and make this build a list. 让我们尝试建立一个清单。 As I mentioned in point (3), you already know something about the list. 正如我在第(3)点中提到的那样,您已经对列表有所了解。 The first element of the list is the same as the first argument to in_cycle . 列表的第一个元素与in_cycle的第一个参数in_cycle Even more, the second element of the list is the same as the element you'll find with circular/2 . 更重要的是,列表的第二个元素与您在circular/2可以找到的元素相同。 So we know a cycle has at least two elements. 因此,我们知道一个循环至少包含两个元素。 How about this? 这个怎么样?

in_cycle(First, [First, Next|Cycle]) :-
    circular(First, Next),
    in_cycle(Next, [Next|Cycle]).

If you trace this now, you'll see something is happening with X , but still not actually anything useful. 如果您现在跟踪它,您会发现X发生了一些事情,但实际上仍然没有任何有用的东西。 Cycle remains a mystery and we're just looping through the facts forever. Cycle仍然是一个谜,我们只是在不断地了解事实。 You need some end condition here. 您在这里需要一些结束条件。 Let's try a simple one: 让我们尝试一个简单的方法:

in_cycle(First, [First]).
in_cycle(First, [First, Next|Cycle]) :-
    circular(First, Next),
    in_cycle(Next, [Next|Cycle]).

Whoa! 哇! in_cycle(a, X) suddenly gives results! in_cycle(a, X)突然给出结果! All possible lists using circular connections starting with a , it seems. 似乎所有使用以a开头的circular连接的列表。 That's not exactly what we want, but maybe we're getting closer? 那不是我们想要的,但是也许我们正在接近?

One problem with this is that in_cycle(Next, [Next|Cycle]) is not actually correct! 一个问题是in_cycle(Next, [Next|Cycle])实际上不正确!

If you do in_cycle(a, X) , you already know that X should become [a, b, d, a] , so filling those values into in_cycle(First, [First, Next|Cycle]) , you get: 如果执行in_cycle(a, X) ,您已经知道X应该成为[a, b, d, a] ,因此将这些值填充到in_cycle(First, [First, Next|Cycle]) ,您将获得:

First = a
Next = b
Cycle = [d, a]

When you get to in_cycle(Next, [Next|Cycle]) , that means it's in_cycle(b, [b, d, a]) . 当您进入in_cycle(Next, [Next|Cycle]) ,这意味着它是in_cycle(b, [b, d, a]) But [b, d, a] is not a cycle! 但是[b, d, a]不是一个循环! You need to be able to distinguish these two situations somehow. 您需要能够以某种方式区分这两种情况。 One way of doing that is to call a separate predicate like I mentioned in (4) to keep track of what your starting element was. 一种方法是调用一个单独的谓词,如我在(4)中提到的那样,以跟踪您的起始元素是什么。

A node is in a cycle, if you can find a path back to that very node. 如果您可以找到返回该节点的路径,则该节点处于循环中。 Using path/4 : 使用path/4

in_cycle(C, [C|Cs]) :-
   circular(C, A),
   path(circular, Cs, A,C).

Now, does this predicate terminate? 现在,该谓词是否终止? How can we test this in a systematic manner? 我们如何系统地测试呢? How can we ensure that we do not forget any special case? 我们如何确保我们不会忘记任何特殊情况? For pure, monotonic programs as this one, testing for termination is trivial 1 : Simply take the most general query ! 对于像这样的纯单调程序,终止测试是微不足道的1 :只需接受最通用的查询 That is: 那是:

?- in_cycle(C, Cs).
   C = d,
   Cs = "dabd"           % [d,a,b,d]
;  C = b,
   Cs = "bdab"
;  C = a, Cs = "abda"
;  false.                % it terminates!

(See this answer how to get "bdab" in place of [b,d,a,b] ). (请参阅此答案,如何获得"bdab"代替[b,d,a,b] )。

What is so nice in Prolog is that above query constitutes a proof of termination . Prolog的优点是上述查询构成了终止证明 Each query you can pose is included in above query. 您可以构成的每个查询都包含在上述查询中。 And since the more general query already terminates, any more specific query will terminate too! 并且由于更一般的查询已经终止,因此任何更具体的查询也将终止! Any! 任何!

And all of this holds even for any variable free facts for circular/2 . 所有这一切,甚至对于circular/2任何可变自由事实都成立。 However, this proof cannot be carried out so easily as the proof for a specific set of facts. 但是,这种证明不能像针对特定事实的证明那样容易地进行。


1 Note that trivial means belonging to the trivium . 1请注意, 琐碎的意思是属于琐事

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM