Learn Prolog Now 翻譯 - 第十章 - 中斷和否認 - 第一節, 中斷

中斷



自動回溯是Prolog中頗有表明性的一個特徵。可是回溯可能會致使低效。有時Prolog會浪費時間在一些沒有結果的可能性搜索上。若是在回溯行爲方面有一些控制機制的話,會是一件比較有意義的事情,可是直到如今爲止咱們看到只有兩種至關初級的方式能夠用於這個目的:交換規則順序,和交換目標順序。其實有另一種方式:存在一個內置的謂詞:!(英文感嘆號),稱爲中斷,能夠提供一種更爲直接地控制Prolog搜尋解決方案的方式。學習

到底中斷是什麼,它是如何起做用的?它實際上是一個特殊的原子,咱們能夠在子句中使用它。看例子:code

p(X) :- b(X), c(X), !, d(X), e(X).

上面的例子就是一個完美的Prolog規則。中斷是這樣起做用的:首先,它是一個永遠成功的目標;其次,更爲重要的是,它有一個反作用。假設有其餘一些目標會使用這個子句(咱們稱之爲父目標,好比例子中的p(X)),在進行搜索時,中斷會使得規則左邊的目標沒法回溯,而只能回溯規則右邊的目標。讓咱們經過例子來學習。blog

首先思考沒有中斷的代碼:原理

p(X) :- a(X).
p(X) :- b(X), c(X), d(X), e(X).

p(X) :- f(X).

a(1). b(1). b(2). c(1). c(2). d(2). e(2). f(3).

若是查詢p(X),咱們會獲得以下的答案:搜索

?- p(X).
X = 1;
X = 2;
X = 3;
false

下面是對應的搜索樹,注意其中必須回溯的地方,當進入第二個子句,決定知足第一個目標b(1),回溯後被替換爲b(2)。程序

如今假設咱們在第二個子句中加入中斷:im

p(X) :- b(X), c(X), !, d(X), e(X).

若是如今查詢p(X),會獲得以下的答案:d3

X = 1;
false

這裏發生了什麼?讓咱們思考一下。查詢

  1. p(X)首先和第一個子句合一,因此獲得新的目標 a(X)。經過將X初始化爲1,Prolog將a(X)和事實a(1)合一,從而找到了一個解決方案。目前爲止,發生的一切和第一個版本是一致的。
  2. 當咱們繼續搜索第二個解決方案。p(X)與第二個規則合一,因此咱們得到新的目標:b(X), c(X), !, d(X), e(X)。經過將X初始化爲1,Prolog將b(X)和b(1)合一,因此咱們得到新的目標:c(1), !, d(1), e(1)。同時c(1)是知識庫中存在的事實,因此目標簡化爲:!, d(1), e(1)。
  3. 如今到了發生鉅變的時刻。目標!爲真(正如其定義的,這是一個永真的目標)而且會提交目前爲止的選擇。具體來講,咱們會提交X = 1,同時咱們也會提交使用的第二個規則。
  4. 可是d(1)失敗了。這樣咱們就沒法知足目標p(X)。固然,若是咱們容許重試將X初始化爲2,咱們可以使用第二個規則去生成一個解決方案(就是在原始版本程序中發生的)。可是這裏咱們沒法這樣作:中斷已經在搜索樹種刪除了這種可能性。同時,若是容許嘗試第三個規則,也能夠生成X = 3的解決方案。可是咱們仍是沒法這樣作:中斷一樣從搜索樹中刪除了這種可能性。

若是觀察以下的搜索樹,你會發現一些樹枝被刪除:當目標d(1)不能在進行,可是須要回溯尋找新的選擇時,搜索已經被中止:db

有一個須要強調的要點:中斷會提交全部的選擇,這些選擇是爲了知足父目標而將包含中斷的子句合一時作出的,而且是從中斷左端進行合一的那些選擇。好比,在以下規則的模式中:

q :- p1, ..., pn, !, r1, ..., rm

當咱們到達中斷的時候,Prolog會提交爲了知足q的而且包含中斷的子句的全部選擇,而且這些選擇是運算p1, ..., pm得出的。然而,在r1, ..., rm內,咱們可以進行回溯,而且知足目標q以前的其餘選擇咱們也能夠進行回溯。經過看下面的例子來明確這些原理。

首先思考沒有中斷的程序:

s(X, Y) :- q(X, Y).
s(0, 0).

q(X, Y) :- i(X), j(Y).

i(1).
i(2).
j(1).
j(2).
j(3).

以下是查詢和結果:

?- s(X, Y).

X = 1
Y = 1;

X = 1
Y = 2;

X = 1
Y = 3;

X = 2
Y = 1;

X = 2
Y = 2;

X = 2
Y = 3;

X = 0
Y = 0;
false

下面是對應的搜索樹:

假設咱們在q/2子句中加入中斷:

q(X, Y) :- i(X), !, j(Y).

如今程序的行爲以下:

?- s(X, Y).

X = 1
Y = 1;

X = 1
Y = 2;

X = 1
Y = 3;

X = 0
Y = 0;
false

讓咱們看看爲何:

  1. s(X, Y)首先和第一個規則合一,這會給出新的目標:q(X, Y)。
  2. q(X, Y)接着和第三個規則合一,這會給出新的目標:i(X), !, j(Y)。經過將X初始化爲1,Prolog將i(X)和事實i(1)合一,這會得出新的目標:!, j(Y)。中斷固然爲真,同時會提交直到如今爲止作出的選擇。
  3. 可是有哪些選擇呢?這裏存在:X = 1,和咱們正在使用的子句。可是注意:咱們沒有爲Y選擇任何的值。
  4. Prolog會繼續,經過將Y初始化爲1,Prolog將j(Y)和事實j(1)合一,因此咱們找到了一個解決方案。
  5. 可是咱們可以找到更多解決方案。Prolog可以對Y嘗試其餘的值。因此回溯而且將Y初始化爲2,因此這樣找到了第二種解決方案。事實上還能夠繼續找到解決方案:再次回溯,經過將Y初始化爲3,找到第三種解決方案。
  6. 可是這些都是搜索j(X)的匹配值,在中斷左邊的回溯是不容許的,因此沒法將X從新初始化爲2,因此這裏沒法找到相似沒有中斷程序中X = 2的那些解決方案。回溯到達q(X, Y)以前的目標是容許的,因此Prolog會找到s/2的第二個規則子句。

以下式對應的搜索樹:

相關文章
相關標籤/搜索