2017-02-26 91 views
1

我想出來的行使下列事實在抽象謂詞

byCar(auckland,hamilton). 
byCar(hamilton,raglan). 
byCar(valmont,saarbruecken). 
byCar(valmont,metz). 

byTrain(metz,frankfurt). 
byTrain(saarbruecken,frankfurt). 
byTrain(metz,paris). 
byTrain(saarbruecken,paris). 

byPlane(frankfurt,bangkok). 
byPlane(frankfurt,singapore). 
byPlane(paris,losAngeles). 
byPlane(bangkok,auckland). 
byPlane(singapore,auckland). 
byPlane(losAngeles,auckland). 

開始...並要求讀者定義謂詞travel/3這樣,例如,

travel(valmont, losAngeles, T) 

...會找到像這樣的解決方案

T = go(byCar(valmont, metz), 
     go(byTrain(metz, paris), 
      go(byPlane(paris, losAngeles)))). 

這是我想到的:

travel(X,Y,go(byCar(X,Y))):-byCar(X,Y). 
travel(X,Y,go(byTrain(X,Y))):-byTrain(X,Y). 
travel(X,Y,go(byPlane(X,Y))):-byPlane(X,Y). 

travel(X,Z,go(byCar(X,Y),T)):-byCar(X,Y),travel(Y,Z,T). 
travel(X,Z,go(byTrain(X,Y),T)):-byTrain(X,Y),travel(Y,Z,T). 
travel(X,Z,go(byPlane(X,Y),T)):-byPlane(X,Y),travel(Y,Z,T). 

看來工作...

?- travel(valmont, losAngeles, X). 
X = go(byCar(valmont, saarbruecken), go(byTrain(saarbruecken, paris), go(byPlane(paris, losAngeles)))) ; 
X = go(byCar(valmont, metz), go(byTrain(metz, paris), go(byPlane(paris, losAngeles)))) ; 
false. 

...但它傷害了我的眼睛;所有這些重複都是抽象的呼喊。

我試圖通過定義

oneLeg(X,Y):-byCar(X,Y);byTrain(X,Y);byPlane(X,Y). 

...並重新定義,以消除重複travel/3

travel(X,Y,go(oneLeg(X,Y))):-oneLeg(X,Y). 
travel(X,Z,go(oneLeg(X,Y),T)):-oneLeg(X,Y),travel(Y,Z,T). 

...但結果還沒有應用:

?- travel(valmont, losAngeles, X). 
X = go(oneLeg(valmont, saarbruecken), go(oneLeg(saarbruecken, paris), go(oneLeg(paris, losAngeles)))) ; 
X = go(oneLeg(valmont, metz), go(oneLeg(metz, paris), go(oneLeg(paris, losAngeles)))) ; 
false. 

我該如何強制更換結果中第oneLeg個實例e具體的byCar,byTrainbyPlane那「證明」oneLeg實例?

+1

查看高級謂詞的'call/N'系列。在你的情況下,'call/3'將特別有用。另外,'(= ..)/ 2'也值得一看。 – mat

+0

@mat:謝謝,但是我無法弄清楚你的建議...... – kjo

+0

如果你沒有分成三個不同的表格,但有一個表格有三個參數:從,到,意味着一切都會更容易。然後,如果突然你還需要乘船出海或類似的東西,你不必改變你的計劃。 – 2017-03-03 12:40:14

回答

3

firstACommentOnNamingThingsasInJavaByMixingTheCasesWhichIsHardToReadyou_may_find_even_long_names_very_readable_when_using_underscores

其次,Prolog是一個非常動態語言,你可以很容易地使用call/N家人元謂詞和其他高階謂詞像  (=..)/2構建和調用任意關閉。

在你的榜樣,首先考慮改變謂詞的名字,以適應命名通常的Prolog的慣例,使用強調分隔單詞:

 
by_car(auckland, hamilton). 
by_car(hamilton, raglan). 
by_car(valmont, saarbruecken). 
by_car(valmont, metz). 

by_train(metz, frankfurt). 
by_train(saarbruecken, frankfurt). 
by_train(metz, paris). 
by_train(saarbruecken, paris). 

by_plane(frankfurt, bangkok). 
by_plane(frankfurt, singapore). 
by_plane(paris, los_angeles). 
by_plane(bangkok, auckland). 
by_plane(singapore, auckland). 
by_plane(losAngeles, auckland). 

現在,合適的抽象可能是謂語means/1,這我們可以這樣定義:

 
means(plane). 
means(train). 
means(car). 

這是很容易使用這個動態調用合適的謂詞:

使用此
 
by_means(From, To, Means) :- 
     means(Means), 
     atom_concat(by_, Means, Pred), 
     call(Pred, From, To). 

一種方法看起來是這樣的:

 
route(To, To) --> []. 
route(From, To) --> [Step], 
     { by_means(From, Next, Means), 
      Step =.. [Means,From,Next] }, 
     route(Next, To). 

樣品的查詢和答案:

 
?- phrase(route(valmont, los_angeles), Rs). 
Rs = [car(valmont, saarbruecken), train(saarbruecken, paris), plane(paris, los_angeles)] ; 
Rs = [car(valmont, metz), train(metz, paris), plane(paris, los_angeles)] ; 
false. 

這項工作的關鍵在於手段的系統化的命名約定,書信等方式謂詞。在這種情況下,對應關係是動態構建的,以便一次說明幾個概念。爲了提高效率,靈活性和甚至可能的安全性,您當然也可以通過靜態的Prolog事實對通信本身進行編碼。例如:

 
means_predicate(plane, by_plane). 
means_predicate(train, by_train). 
means_predicate(car, by_car). 

by_means(From, To, Means) :- 
     means_predicate(Means, Pred), 
     call(Pred, From, To). 
+1

額外的感謝。我從你的答案中學到了大量的Prolog。 – kjo

+1

不客氣!作爲一個練習,考慮寫一個也避免使用'(= ..)/ 2'的版本! – mat

+0

我對Prolog不太瞭解,但你爲什麼要做動態的事情,而'= ..'和'call'呢?難道不可能使用像康涅狄格州(汽車,奧克蘭,哈密爾頓)或康恩(飛機,法蘭克福,新加坡)這樣的單一桌子嗎?或者Prolog和關係數據庫有很大的不同? – 2017-03-03 12:43:58

2

如果我必須這樣做,我可能會嘗試將汽車和平面以及火車轉換爲單一表from_to_means。我發現你可以這樣做,如下所示:

forall(byCar(From, To), assertz(from_to_means(From, To, car))) 

然後相同的飛機和火車。在SWI-Prolog的也有短期的擴展,所以也許你可以插入三個原始表

term_expansion(byCar(From, To), from_to_means(From, To, car)). 

與同爲飛機和火車的上方。

然後,您只需評估from_to_means(From, To, Means)或者如果您編寫from_to_means(From, To, train),則只能選擇一種運輸工具。

+2

這是問題的一部分(好)替代解決方案。然而,它並沒有解釋如何解決第二個問題:你如何將這些謂詞的解決方案轉化爲形式爲[car(valmont,metz),train(metz,paris),plane(paris,los_angeles)]'的列表,這是我在答案的第二部分中展示的。爲此,您需要再次使用不同的表示法,表中的冗餘數據,或者使用'(= ..)/ 2'。很顯然,當你可以自由地重組表格時,你可以使表格更加統一。 +1表示一個很好的替代表示! – mat

+0

你好@mat,謝謝你的客氣話。我真的不知道Prolog足夠好評判。我認爲數據結構及其在屏幕上的顯示方式更爲獨立,但如果您不想單獨打印到屏幕上,您似乎總是需要更多代碼才能將一個數據結構映射到另一個數據結構。 – 2017-03-06 07:58:58