在進入正題以前,咱們先一塊兒思考一個問題:當咱們在編程時,咱們在作什麼?html
看到這個問題,有些同窗可能會第一時間要回答:前端
呃,我不是那個意思,說認真的:當咱們在編程時,咱們在作什麼?程序員
咱們在把所想的「解決方案」轉換成計算機可理解的「計算機語言」。編程
JavaScript, Python, Java, Ruby, C++ …… 等等等等,哪怕是世界上最好的語言 PHP,也大抵如此:「解決方案」->「計算機語言」。bash
但你有沒有想過反過來?「計算機語言」->「解決方案」 這樣,咱們使用「計算機語言」描述問題,而計算機來告訴咱們「解決方案」?微信
或許你會想到人工智能、深度學習等等概念,但那些熱門話題不是咱們今天要討論的。編程語言
今天,咱們來一塊兒聊聊那迷人的被遺忘的語言:Prolog.函數
Prolog(Programming in Logic)是一種邏輯編程語言。它建立在邏輯學的理論基礎之上, 誕生與 1972 年,最初被運用於天然語言等研究領域,距今 46 年曆史。當下火熱的 JavaScript 語言 23 歲,年齡恰好是 Prolog 的一半。學習
說到 Prolog 是一種邏輯編程語言,那麼跟通常的函數式語言有什麼區別呢?答:徹底不是一碼事情。在 Prolog 裏,最基本的作法是先描述事實(定立對象與對象之間的關係),而後用詢問目標的方式來查詢各類對象之間的關係,系統會自動進行匹配、回溯,並給出答案。ui
舉個例子:
咱們使用下面的語法來表述一個事實
handsome(ergou).
複製代碼
這個語句描述了一個事實:二狗 (ergou) 是無比帥氣 (handsome) 的,而後以句號 (.) 結束,代表這個事實描述完畢,無可置疑。
而後接下來咱們在 Prolog 的控制檯 (REPL) 裏就會獲得以下的結論:
?- handsome(X).
X = ergou.
?-
複製代碼
其中 ?-
開頭的是咱們手動輸入的,其餘的是 Prolog 返回的。上面的那些操做是:
handsome(X).
其中 X
是大寫字母開頭,在 Prolog 裏全部大寫字母開頭的都是變量。X = ergou.
,固然是二狗了!以上,應該能夠算做 Prolog 基本思路的一個演示。你能夠去下載適用於你的 Prolog 環境,而後在本身的電腦上把玩一下。
建議使用 SWI Prolog(本文的全部演示代碼都是在 SWI Prolog 進行的操做):www.swi-prolog.org/
安裝完畢以後,執行下面三步,便可復現上面的結果:
echo 'handsome(ergou).' > fact.prolog
複製代碼
swipl fact.prolog
複製代碼
handsome(X).
複製代碼
剛纔的例子是咱們描述了一個事實,而後又讓 Prolog 告訴了咱們這個事實,好像沒有太大的用途,接下來咱們試着作一下別的事情:
father(yigou,ergou).
father(linggou,yigou).
grandfather(X,Z) :- father(X,Y), father(Y,Z).
複製代碼
看了上面的代碼,應該能夠理解到,咱們是描述了三個事實:
有了這些事實,咱們能夠幹什麼?能夠找到二狗爺爺啊!
載入既定事實
swipl grandfather.prolog
複製代碼
執行詢問語句
?- grandfather(X,yigou).
false.
?- grandfather(X,ergou).
X = linggou.
?-
複製代碼
能夠看到一狗 (yigou) 是沒有爺爺的,二狗 (ergou) 的爺爺是零狗 (linggou) 。
像剛纔那個例子,咱們再舉一個來加深一下這種思惟方式:
listen(ergou, bach). % 二狗 聽 巴赫
listen(ergou, beethoven). % 二狗 聽 貝多芬
listen(ergou, mozart). % 二狗 聽 莫扎特
listen(xiaohong, mj). % 小紅 聽 邁克爾·傑克遜
listen(xiaohong, dylan). % 小紅 聽 鮑勃·迪倫
listen(xiaohong, bach). % 小紅 聽 巴赫
listen(xiaohong, beethoven). % 小紅 聽 貝多芬
複製代碼
上面這些代碼描述了二狗和小紅的聽歌品味,如今若是二狗想要找出本身與小紅在聽歌品味上的共同之處,該怎麼辦?
載入既定事實
swipl music.prolog
複製代碼
執行詢問語句
?- listen(ergou, X),listen(xiaohong,X).
X = bach ;
X = beethoven ;
false.
?-
複製代碼
咱們在加載了既定事實以後,開始詢問:有什麼音樂是二狗 (ergou) 和小紅 (xiaohong) 都有在聽的呢?
?- listen(ergou, X),listen(xiaohong,X).
複製代碼
而後咱們獲得了下面的答案:
?- listen(ergou, X),listen(xiaohong,X).
X = bach
複製代碼
若是你有在跟着文章手動操做,若是你是個細心的同窗,你會發現此次詢問以後光標停留在了 X = bach
這裏,而不是換行顯示出 ?-
。這是爲何呢?
這時候 Prolog 是在說:問題還有別的解答,按下 ;
尋求更多,按下 Enter
表示接受當前答案。在上邊了例子中,咱們持續按下 ;
,直到返回 false
才停下來。
因而咱們獲得了二狗和小紅共同欣賞的音樂,是巴赫和貝多芬。
接下來咱們來一個經典問題:
今有雉兔同籠,上有三十五頭,下有九十四足,問雉兔各幾何?
—— 《孫子算經》
翻譯成白話文:
有若干只雞兔同在一個籠子裏,從上面數,有35個頭,從下面數,有94只腳。問籠中各有多少隻雞和兔?
停!快中止思考!
若是你在使用 JavaScript、Python 等等語言的思路去嘗試編程解決問題的話,趕忙停下來,如今咱們要用描述既定事實的方式,讓 Prolog 給咱們答案!
% 首先,咱們引入一個 clpq 的庫來幫助咱們進行運算符描述
:- use_module(library(clpq)).
% 而後,咱們定義事實:腦殼的總數量(H) 應當等於 雞的總數量(C) 加上 兔子的總數量(R)
head(C,R,H) :- {H = C + R}.
% 而後,咱們定義事實:腳的總數量(F) 應當等於 雞的總數量(C)乘以二 加上 兔子的總數量(R)乘以四
foot(C,R,F) :- {F = C*2 + R*4}.
複製代碼
咱們定義好了事實,那麼接下來讓咱們去詢問 Prolog 答案:
載入既定事實
swipl chicken-and-rabbits.prolog
複製代碼
執行詢問語句
?- head(C,R,35),foot(C,R,94).
C = 23,
R = 12.
複製代碼
答:雞有 23 只!兔有 12 只!
哈哈哈哈,沒錯!不再須要去絞盡腦汁思考怎麼告訴計算機去計算啦!只須要告訴 Prolog 既定事實,剩下的,就是提出正確的問題啦!
古老的 Prolog 在計算機科學中的逐漸退熱,必然有對應的緣由,但這種語言所特有的思惟方式,也不妨去探尋一下。在當下的編程氛圍裏,或許 Prolog 就像是夏日的一杯加冰檸檬水,給咱們帶來涼爽和清新呢!
好了,關於 Prolog 的討論,咱們今天就到這裏了,多謝各位!
還有更多關於 Prolog 的資料,感興趣能夠繼續閱讀:
文 / 王二狗 職業程序員,週末愛好者
編 / 熒聲
本文已由做者受權發佈,版權屬於創宇前端。歡迎註明出處轉載本文。本文連接:knownsec-fed.com/2018-08-09-…
想要看到更多來自知道創宇開發一線的分享,請搜索關注咱們的微信公衆號:創宇前端(KnownsecFED)。歡迎留言討論,咱們會盡量回復。
感謝您的閱讀。