七週七語言之使用prolog解決愛因斯坦斑馬難題

若是你想得到更好的閱讀體驗,能夠前往我在 github 上的博客進行閱讀,http://lcomplete.github.io/blog/2013/06/28/sevenlang-prolog/python


 

目前商業上普遍使用的編程語言可能是命令式或函數式的編程語言,這些語言在某些方面具備很高的類似度,好比 python 和 ruby 在不少地方是相通的,學會了一門,再學另外一門便可以事半功倍,不少語言都是如此,然而今天要介紹的這門語言,卻跟主流編程語言大相徑庭,它就是prolog——一門邏輯編程語言。git

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

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可能的取值並輸出到控制檯,最後的下劃線是一個佔位符,不會進行求值。ruby

在 prolog 中還可使用遞歸完成列表和數學等運算,這部分是很強大的,但這裏不打算講,由於有了上面的基礎知識後,咱們就能夠利用它來解決邏輯問題了,下面就讓咱們來解決「斑馬難題」吧。編程語言

愛因斯坦邏輯難題

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

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

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

雖然咱們知道了解題的關鍵,但這個問題仍然須要通過不少步的推導才能得出結果,若是使用 prolog 那獲得這個問題的答案就簡單多了,只須要定義好事實和規則,而後向 prolog 提出問題,邏輯引擎就會爲咱們查出結果來。spa

下面是解決這個問題的 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)] .

相關文章
相關標籤/搜索