若是你想得到更好的閱讀體驗,能夠前往我在 github 上的博客進行閱讀,http://lcomplete.github.io/blog/2013/06/28/sevenlang-prolog/。python
目前商業上普遍使用的編程語言可能是命令式或函數式的編程語言,這些語言在某些方面具備很高的類似度,好比 python 和 ruby 在不少地方是相通的,學會了一門,再學另外一門便可以事半功倍,不少語言都是如此,然而今天要介紹的這門語言,卻跟主流編程語言大相徑庭,它就是prolog——一門邏輯編程語言。git
prolog 是 Programming in Logic 的縮寫,它被普遍應用在人工智能、天然語言等研究領域,使用它來解決邏輯難題徹底不在話下,今天咱們將使用它來解決着名的愛因斯坦邏輯難題(斑馬難題),首先讓咱們來認識一下 prolog 的語法。github
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所房子裏,每所房子的顏色不一樣,每一個人都有本身養的不一樣寵物,喜歡喝不一樣的飲料。根據如下提示,你能告訴我哪所房子裏的人養斑馬,哪所房子裏的人喜歡喝礦泉水嗎?函數
這道題的解題關鍵在於,要以一種清晰的方式將每一個房子相關的屬性(國家、顏色、工做、寵物、飲料、編號)列出來,前面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)] .