那迷人的被遺忘的語言:Prolog

在進入正題以前,咱們先一塊兒思考一個問題:當咱們在編程時,咱們在作什麼?html

看到這個問題,有些同窗可能會第一時間要回答:前端

  • 在聽音樂
  • 在打字
  • 在發呆
  • 在裝做很忙的樣子
  • ……

呃,我不是那個意思,說認真的:當咱們在編程時,咱們在作什麼?程序員

咱們在把所想的「解決方案」轉換成計算機可理解的「計算機語言」。編程

JavaScript, Python, Java, Ruby, C++ …… 等等等等,哪怕是世界上最好的語言 PHP,也大抵如此:「解決方案」->「計算機語言」bash

但你有沒有想過反過來?「計算機語言」->「解決方案」 這樣,咱們使用「計算機語言」描述問題,而計算機來告訴咱們「解決方案」?微信

或許你會想到人工智能、深度學習等等概念,但那些熱門話題不是咱們今天要討論的。編程語言

今天,咱們來一塊兒聊聊那迷人的被遺忘的語言:Prolog.函數

Prolog 簡介

Prolog(Programming in Logic)是一種邏輯編程語言。它建立在邏輯學的理論基礎之上, 誕生與 1972 年,最初被運用於天然語言等研究領域,距今 46 年曆史。當下火熱的 JavaScript 語言 23 歲,年齡恰好是 Prolog 的一半。學習

說到 Prolog 是一種邏輯編程語言,那麼跟通常的函數式語言有什麼區別呢?答:徹底不是一碼事情。在 Prolog 裏,最基本的作法是先描述事實(定立對象與對象之間的關係),而後用詢問目標的方式來查詢各類對象之間的關係,系統會自動進行匹配、回溯,並給出答案。ui

舉個例子:

咱們使用下面的語法來表述一個事實

handsome(ergou).
複製代碼

這個語句描述了一個事實:二狗 (ergou) 是無比帥氣 (handsome) 的,而後以句號 (.) 結束,代表這個事實描述完畢,無可置疑。

而後接下來咱們在 Prolog 的控制檯 (REPL) 裏就會獲得以下的結論:

?- handsome(X).
X = ergou.

?-
複製代碼

其中 ?- 開頭的是咱們手動輸入的,其餘的是 Prolog 返回的。上面的那些操做是:

  1. 咱們首先問 Prolog:誰是世界上最帥的人?handsome(X). 其中 X 是大寫字母開頭,在 Prolog 裏全部大寫字母開頭的都是變量。
  2. 而後 Prolog 回答說:X = ergou. ,固然是二狗了!

以上,應該能夠算做 Prolog 基本思路的一個演示。你能夠去下載適用於你的 Prolog 環境,而後在本身的電腦上把玩一下。

建議使用 SWI Prolog(本文的全部演示代碼都是在 SWI Prolog 進行的操做):www.swi-prolog.org/

安裝完畢以後,執行下面三步,便可復現上面的結果:

  1. 將事實寫入文件
echo 'handsome(ergou).' > fact.prolog
複製代碼
  1. 啓動 Prolog REPL 並加載既定事實:
swipl fact.prolog
複製代碼
  1. 在 Prolog REPL 內輸入如下語句並回車:
handsome(X).
複製代碼

誰是我大爺?

剛纔的例子是咱們描述了一個事實,而後又讓 Prolog 告訴了咱們這個事實,好像沒有太大的用途,接下來咱們試着作一下別的事情:

文件名:grandfather.prolog

father(yigou,ergou).
father(linggou,yigou).

grandfather(X,Z) :- father(X,Y), father(Y,Z).
複製代碼

看了上面的代碼,應該能夠理解到,咱們是描述了三個事實:

  1. 二狗 (ergou) 的父親是 一狗 (yigou)
  2. 一狗 (yigou) 的父親是零狗 (linggou)
  3. X 是 Z 大爺的前提條件是:X 是 Y 的父親,Y 是 Z 的父親

有了這些事實,咱們能夠幹什麼?能夠找到二狗爺爺啊!

載入既定事實

swipl grandfather.prolog
複製代碼

執行詢問語句

?- grandfather(X,yigou).
false.

?- grandfather(X,ergou).
X = linggou.

?-
複製代碼

能夠看到一狗 (yigou) 是沒有爺爺的,二狗 (ergou) 的爺爺是零狗 (linggou) 。

我和小紅的共同愛好是什麼?

像剛纔那個例子,咱們再舉一個來加深一下這種思惟方式:

文件名:music.prolog

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 給咱們答案!

文件名:chicken-and-rabbits.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)。歡迎留言討論,咱們會盡量回復。

感謝您的閱讀。

相關文章
相關標籤/搜索