練習題3.1
在之前的章節中,我們已經討論了如下的謂詞邏輯:
descend(X, Y) :- child(X, Y).
descend(X, Y) :- child(X, Z), descend(Z, Y).
假設我們將謂詞邏輯重構如下:
descend(X, Y) :- child(X, Y).
descend(X, Y) :- descend(X, Z), descend(Z, Y).
這會導致問題嗎?
我的答案:
1. 這個謂詞邏輯是有問題的,因為規則2中存在左遞歸的情況,即規則2的主干部分的第一個目標,和規則2的頭部是相同的函子;
2. 但是由於規則1是一個非遞歸的謂詞邏輯,所以在進行一些查詢時,能夠根據這個規則進行終止,從而得出結果,比如:
?- descend(anne, bridget).
Prolog會回答true;
?- descend(anne, emily).
Prolog會回答true;
3. 但是在問一些不能由規則1終止的問題時,Prolog會報"Out of local stack"的錯誤,代表遞歸不能終止,比如:
?- descend(bridget, anne).
?- descend(anne, X); 一直使用“;”尋找下一個答案,也會報錯
練習題3.2
知道俄羅斯木偶(又稱為俄羅斯套娃娃)嗎?其中較大的娃娃會包含較小的娃娃,如下圖所示:
首先,寫出一個使用謂詞邏輯directlyIn/2的知識庫,表示木偶直接被另外一個木偶包含。其次,定義一個遞歸的謂詞邏輯in/2,告訴某個木偶是否被另外一個木偶包含
(直接或者間接)。比如,如果查詢in(katarina, natasha),應該回答true,但是in(olga, katarina)應該回答false。
我的答案:
directlyIn(katarina, olga). directlyIn(olga, natasha). directlyIn(natasha, irina). in(X, Y) :- directlyIn(X, Y). in(X, Y) :- directlyIn(X, Z), in(Z, Y).
練習題3.3
有如下的知識庫:
directTrain(saarbruecken, dudweiler).
directTrain(forbach, saarbruecken).
directTrain(freyming, forbach).
directTrain(stAvold, freyming).
directTrain(fahlquemont, stAvold).
directTrain(metz, fahlquemont).
directTrain(nancy, metz).
即,這個知識庫記錄了可以直接連通到城鎮。但是,我們可以通過連接不同的城鎮去旅行到更遠的地方。請寫一個謂詞邏輯travelFromTo/2,可以告訴我們如何在這些
城鎮之間通行。比如,如果查詢:
?- travelFromTo(nancy, saarbruecken).
Prolog會回答true。
我的答案:
travelFromTo(X, Y) :- directTrain(X, Y).
travelFromTo(X, Y) :- directTrain(X, Z), travelFromTo(Z, Y).
練習題3.4
定義一個謂詞邏輯greater_than/2,有兩個參數,使用本章中的數字表示方法(比如,numeral(0), numeral(succ(0)), numeral(succ(succ(0)))等),然后判斷第一
個參數是否大於第二個參數,比如:
?- greater_than(numeral(succ(succ(succ(0)))), numeral(succ(0))).
Prolog會回答true;
?- greater_than(numeral(succ(succ(0))), numeral(succ(succ(succ(0))))).
Prolog會回答false;
我的答案:
numeral(0). numeral(succ(X)) :- numeral(X). greater_than(numeral(X), numeral(0)) :- X \= 0. greater_than(numeral(succ(X)), numeral(succ(Y))) :- greater_than(numeral(X), numeral(Y))
練習題3.5
二叉樹是每個內部節點嚴格有兩個子節點的樹形結構。一顆最小的二叉樹僅由一個葉子節點構成。我們使用leaf(Label)代表葉子節點。比如,leaf(3)和leaf(7)都是
葉子節點。假設兩顆二叉樹B1和B2能夠通過謂詞tree/2,合並稱為一顆二叉樹,如下:tree(B1, B2)。那么,從葉子節點開始,我們能夠構建二叉樹:tree(leaf(1),leaf(2)),
類似地,從一顆二叉樹tree(leaf(1),leaf(2))和葉子節點leaf(4),能夠構建出新的二叉樹:tree(tree(leaf(1),leaf(2)), leaf(4))。
現在,請定義一個謂詞邏輯swap/2,能夠根據第一個參數的二叉樹,構建第二個參數成為其鏡像二叉樹,比如:
?- swap(tree(tree(leaf(1),leaf(2)), leaf(4)), T).
T = tree(leaf(4), tree(leaf(2),leaf(1))).
true
我的答案和解釋,測試結果如下:
tree(leaf(X), leaf(Y)) :- integer(X), integer(Y). tree(tree(X1, X2), leaf(Y)) :- tree(X1, X2), integer(Y). tree(leaf(Y), tree(X1, X2)) :- integer(Y), tree(X1, X2). tree(tree(X1, X2), tree(Y1, Y2)) :- tree(X1, X2), tree(Y1, Y2). swap(tree(leaf(X1), leaf(X2)), tree(leaf(X2), leaf(X1))) :- integer(X1), integer(X2). swap(tree(Tree1, leaf(X1)), tree(leaf(X1), Tree2)) :- integer(X1), swap(Tree1, Tree2). swap(tree(leaf(X1), Tree1), tree(Tree2, leaf(X1))) :- integer(X1), swap(Tree1, Tree2). swap(tree(Tree1, Tree2), tree(Tree3, Tree4)) :- swap(Tree1, Tree4), swap(Tree2, Tree3).
一些說明:
1. integer/1謂詞邏輯用於檢查參數是否是一個整數;
2. tree/2謂詞邏輯定義了二叉樹的邏輯,分為四個子句:子句1定義了兩個節點都是葉子節點的基礎邏輯;子句2定義了左節點是二叉樹,右節點是葉子節點的遞歸邏輯;
子句3定義了左節點是葉子節點,右節點是二叉樹的遞歸邏輯;子句4定義了兩個子節點都是二叉樹的遞歸邏輯;
3. swap/2謂詞邏輯定義了二叉樹鏡像實現,方式類似於tree/2的定義。
4. 下面是一些測試和結果:
?- swap(tree(leaf(1), leaf(2)), T).
T = tree(leaf(2), leaf(1)) .
?- swap(tree(tree(leaf(1), leaf(2)), leaf(4)), T).
T = tree(leaf(4), tree(leaf(2), leaf(1))) .
?- swap(tree(leaf(4), tree(leaf(1), leaf(2))), T).
T = tree(tree(leaf(2), leaf(1)), leaf(4)) .
?- swap(tree(tree(leaf(1), leaf(2)), tree(leaf(3), leaf(4))), T).
T = tree(tree(leaf(4), leaf(3)), tree(leaf(2), leaf(1))) .
本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。