如果你想獲得更好的閱讀體驗,可以前往我在 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所房子里,每所房子的顏色不同,每個人都有自己養的不同寵物,喜歡喝不同的飲料。根據以下提示,你能告訴我哪所房子里的人養斑馬,哪所房子里的人喜歡喝礦泉水嗎?
- 英國人住在紅色的房子里
- 西班牙人養了一條狗
- 日本人是一個油漆工
- 意大利人喜歡喝茶
- 挪威人住在左邊的第一個房子里
- 綠房子在白房子的右邊
- 攝影師養了一只蝸牛
- 外交官住在黃房子里
- 中間那個房子的人喜歡喝牛奶
- 喜歡喝咖啡的人住在綠房子里
- 挪威人住在藍色的房子旁邊
- 小提琴家喜歡喝橘子汁
- 養狐狸的人所住的房子與醫生的房子相鄰
- 養馬的人所住的房子與外交官的房子相鄰
這道題的解題關鍵在於,要以一種清晰的方式將每個房子相關的屬性(國家、顏色、工作、寵物、飲料、編號)列出來,前面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