簡體   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).

所以當我打電話:

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]).
  1. 您的事實數據庫中最短的周期是多少? 會是circular(a, a). 被循環[a] 知道最短的周期是什么,可以幫助您找到謂詞的完成條件(其中之一)。
  2. 為了能夠找到列表,您的謂詞需要構建它。 您的in_cycle/2永遠不會提及任何列表。 您需要使用[Head | Tail] [Head | Tail]構造在其中某處,以便能夠將元素添加到列表中。
  3. 您已經對周期性列表的外觀有所了解。 第一個和最后一個元素相同,並且與您要為其查找循環的符號相同。 使用該信息。
  4. 為了能夠告訴您何時完成一個循環,您需要記住從哪個符號開始。 為了能夠通過遞歸做到這一點,您需要保持狀態。 因此,您將需要一個附加謂詞來保存該狀態。 例如,涉及謂詞的事物如in_cycle(Current_symbol, Cycle, Start_symbol) 然后,您可以從in_cycle/2調用它。

讓我們看看您的嘗試:

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

您可以在提示符處使用trace命令查看正在發生的情況: trace, in_cycle(a, X).

空格鍵單步執行程序。 h尋求幫助,按a退出。 使用notrace. 再次退出跟蹤模式。

在逐步執行此過程時,您會發現謂詞很好地循環了整個循環,但是X永遠不會成為列表。 那很糟。

讓我們嘗試建立一個清單。 正如我在第(3)點中提到的那樣,您已經對列表有所了解。 列表的第一個元素與in_cycle的第一個參數in_cycle 更重要的是,列表的第二個元素與您在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)突然給出結果! 似乎所有使用以a開頭的circular連接的列表。 那不是我們想要的,但是也許我們正在接近?

一個問題是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)中提到的那樣,以跟蹤您的起始元素是什么。

如果您可以找到返回該節點的路徑,則該節點處於循環中。 使用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!

(請參閱此答案,如何獲得"bdab"代替[b,d,a,b] )。

Prolog的優點是上述查詢構成了終止證明 您可以構成的每個查詢都包含在上述查詢中。 並且由於更一般的查詢已經終止,因此任何更具體的查詢也將終止! 任何!

所有這一切,甚至對於circular/2任何可變自由事實都成立。 但是,這種證明不能像針對特定事實的證明那樣容易地進行。


1請注意, 瑣碎的意思是屬於瑣事

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM