使用prolog邏輯語言解決愛因斯坦斑馬難題


如果你想獲得更好的閱讀體驗,可以前往我在 github 上的博客進行閱讀,http://lcomplete.github.io/blog/2013/06/28/sevenlang-prolog/


 

目前商業上廣泛使用的編程語言多是命令式或函數式的編程語言,這些語言在某些方面具有很高的相似度,比如 python 和 ruby 在很多地方是相通的,學會了一門,再學另一門便能夠事半功倍,很多語言都是如此,然而今天要介紹的這門語言,卻跟主流編程語言截然不同,它就是prolog——一門邏輯編程語言。

prolog 是 Programming in Logic 的縮寫,它被廣泛應用在人工智能、自然語言等研究領域,使用它來解決邏輯難題完全不在話下,今天我們將使用它來解決着名的愛因斯坦邏輯難題(斑馬難題),首先讓我們來認識一下 prolog 的語法。

prolog 基本語法

prolog 中有3種基本元素:事實、規則和查詢。事實和規則用於描述數據,查詢用於獲取問題的答案。
我們可以這樣定義事實:

human(lucy).
human(lili).
father(lucy,david).
sister(lucy,lili).
sister(lili,lucy).

這段代碼表示 lucy 和 lili 是人類,且她們是姐妹,david 是 lucy 的父親,繼續定義規則:

daughter(Father,A,B) :-
    father(A,Father), sister(A,B)

這段規則表示對於變量A、B,如果Father變量是A的父親,且A、B是姐妹,則A、B是Father對象的女兒。 
注意,在 prolog 中一個詞若以小寫開頭,那么它是一個固定值,若以大寫字母開頭,則是一個變量。 
將這些事實和規則放在一個文件里面,在命令行下打開 prolog ,對這個文件進行編譯,即可提出查詢,比如 daughter(david,A,_),prolog 將會求出A可能的取值並輸出到控制台,最后的下划線是一個占位符,不會進行求值。

在 prolog 中還可以使用遞歸完成列表和數學等運算,這部分是很強大的,但這里不打算講,因為有了上面的基礎知識后,我們就可以利用它來解決邏輯問題了,下面就讓我們來解決“斑馬難題”吧。

愛因斯坦邏輯難題

題目:5個不同國家且工作各不相同的人分別住在一條街上的5所房子里,每所房子的顏色不同,每個人都有自己養的不同寵物,喜歡喝不同的飲料。根據以下提示,你能告訴我哪所房子里的人養斑馬,哪所房子里的人喜歡喝礦泉水嗎?

  1. 英國人住在紅色的房子里
  2. 西班牙人養了一條狗
  3. 日本人是一個油漆工
  4. 意大利人喜歡喝茶
  5. 挪威人住在左邊的第一個房子里
  6. 綠房子在白房子的右邊
  7. 攝影師養了一只蝸牛
  8. 外交官住在黃房子里
  9. 中間那個房子的人喜歡喝牛奶
  10. 喜歡喝咖啡的人住在綠房子里
  11. 挪威人住在藍色的房子旁邊
  12. 小提琴家喜歡喝橘子汁
  13. 養狐狸的人所住的房子與醫生的房子相鄰
  14. 養馬的人所住的房子與外交官的房子相鄰

這道題的解題關鍵在於,要以一種清晰的方式將每個房子相關的屬性(國家、顏色、工作、寵物、飲料、編號)列出來,前面5個提示中包含了5個國家,那么可以利用這一點畫出一個表格,每一行表示一個國家,每一列表示房子的一種屬性。一步步根據提示得到一些推論,將結果填入表格,答案便漸漸清晰起來,使用這種人工方式推理的結果如下圖所示: 

雖然我們知道了解題的關鍵,但這個問題仍然需要經過很多步的推導才能得出結果,如果使用 prolog 那得到這個問題的答案就簡單多了,只需要定義好事實和規則,然后向 prolog 提出問題,邏輯引擎就會為我們查出結果來。

下面是解決這個問題的 prolog 代碼。

復制代碼
house(A,[A,_,_,_,_]).
house(A,[_,A,_,_,_]).
house(A,[_,_,A,_,_]).
house(A,[_,_,_,A,_]).
house(A,[_,_,_,_,A]).

right(A,B,[A,B,_,_,_]).
right(A,B,[_,A,B,_,_]).
right(A,B,[_,_,A,B,_]).
right(A,B,[_,_,_,A,B]).

middle(A,[_,_,A,_,_]).

first(A,[A,_,_,_,_]).

neighbor(A,B,[A,B,_,_,_]).
neighbor(A,B,[_,A,B,_,_]).
neighbor(A,B,[_,_,A,B,_]).
neighbor(A,B,[_,_,_,A,B]).
neighbor(A,B,[B,A,_,_,_]).
neighbor(A,B,[_,B,A,_,_]).
neighbor(A,B,[_,_,B,A,_]).
neighbor(A,B,[_,_,_,B,A]).

attr(Country,Pet,Color,Drink,Work).

all_houses(Houses) :-
    house(attr(britsh,_,red,_,_), Houses),
    house(attr(spain,dog,_,_,_), Houses),
    house(attr(japan,_,_,_,painter), Houses),
    house(attr(italy,_,_,tea,_), Houses),
    house(attr(norway,_,_,_,_), Houses),
    first(attr(norway,_,_,_,_), Houses),
    right(attr(_,_,white,_,_), attr(_,_,green,_,_), Houses),
    house(attr(_,snail,_,_,photographer), Houses),
    house(attr(_,_,yellow,_,diplomat), Houses),
    middle(attr(_,_,_,milk,_), Houses),
    house(attr(_,_,green,cafe,_), Houses),
    neighbor(attr(norway,_,_,_,_), attr(_,_,blue,_,_), Houses),
    house(attr(_,_,_,orange,violinst), Houses),
    neighbor(attr(_,fox,_,_,_), attr(_,_,_,_,doctor), Houses),
    neighbor(attr(_,horse,_,_,_), attr(_,_,_,_,diplomat), Houses),

    house(attr(_,zebra,_,_,_), Houses),
    house(attr(_,_,_,water,_), Houses).
復制代碼

在事實部分,將房子看做一個整體,描述了房子在5所房子中、房子的左右關系、中間的房子處於什么位置、第一所房子處於什么位置、房子間的相鄰關系以及每所房子擁有哪些屬性。
規則部分包含了對題目中提示的描述和最終問題的描述,這些定義是為了告訴邏輯引擎,在求值時必須滿足這些條件。
最終的查詢為 all_houses(A) ,prolog 邏輯引擎將會查找出滿足結果的房子數組,注意每所房子由它的屬性組成,這樣最后得到的結果為:

[attr(norway, fox, yellow, water, diplomat), 
attr(italy, horse, blue, tea, doctor), 
attr(britsh, snail, red, milk, photographer), 
attr(spain, dog, white, orange, violinst), 
attr(japan, zebra, green, cafe, painter)] .

 

出處:http://www.cnblogs.com/lcomplete/p/3192488.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM