1,邏輯編程語言能做什么
這兩天正在構思這個“三維度”邏輯編程語言的設計系列的下一篇該怎么寫,正好在上一篇《用寫文章的方式寫程序--“三維度”邏輯編程語言的設計(1)》有位叫做 dwcz 的朋友回帖說:
“沒啥特點。新出的語言都快實現的功能,還在這里進行理論構想。邏輯式編程基本被否定了,和函數式有同樣問題--只能在簡單或靜態環境,在復雜或動態環境,造成的問題比要解決的問題還多。”
不知道這位朋友具體是出於什么原因這么認為的,我認為一個東西不流行不代表它是失敗的、被否定的事物。邏輯編程語言這幾年的確很少出現在編程社區的討論中,更看不到有關職位的招聘信息,本着“用腳投票”的原則,認為邏輯編程語言沒什么用,已經被否定、被淘汰的觀點就有市場了,但是這種觀點是不正確的,流行的東西不一定是好東西,比如流感;不流行的東西只不過很小眾,只要它存在就有它的一小片天地。邏輯編程語言的確很小眾,它有它特殊的應用領域, dwcz 恰恰說反了,邏輯編程語言主要的用武之地就是復雜和動態的環境,這個可以從邏輯編程語言Visual Prolog的官網介紹看到:
https://www.visual-prolog.com/default-chinese.htm
使用Visual Prolog可以構建工業級的商用程序,尤其適合處理復雜的認知問題。
Prolog語言開發中心業已證實,以下項目中的先進資源調度和決策支持系統完全是用Visual Prolog編寫的:
員工規划
機場決策支持
航空公司決策支持
車間調度
基於語音的解決方案
CrewWatch
Ra
上面一段介紹的詳細內容請點擊上面的鏈接了解。而函數式語言跟邏輯編程語言有同樣問題這個說法更不對,函數式語言的鼻祖LISP至今還在,基於JVM的LISP方言Clojure還能常常出現在招聘信息中,還有比Common LISP更為簡單的方言Scheme,它有一個完善IDE環境的DrRacket實現,還有編譯和運行速度比C還快的Chez Scheme,詳情可以看看知乎對此的討論,也可以看看王垠寫的這篇《揭秘Chez Scheme》(王垠自己的博客已經加密,這里貼的是轉載的文章)。我使用Chez Scheme編寫了一個新冠病毒感染風險監測程序,可以點擊我這篇文章《Scheme語言實例入門--怎樣寫一個“新型冠狀病毒感染風險檢測程序” 》了解和下載運行這個Scheme程序。此外,常用的函數式語言還有scala, erlang, F#, Haskell等,說到.NET就不能不提到F#,.NET 5.0將伴隨C#9.0同步發布最新的F# 5.0,可見F#在軟微開發語言中的重要地位。奇怪的是,F#在國內鮮有使用,而在國外被稱為薪水最高的編程語言,如下圖2019編程語言薪資排行榜。
從上面的編程語言排行榜上可以看到,Top 3的語言有兩名都是函數式語言,Erlang都能排名No.9,可見,函數式語言是名副其實的“高薪語言”,還能說函數式語言“只能在簡單或靜態環境”,而不能運用在復雜或動態環境的環境嗎?沒有哪個老板會在那種“簡單或者靜態環境”的軟件開發項目中給程序員高新吧?回歸主題,本篇文章是討論邏輯編程語言的,上面說這么多,就是要告訴大家,邏輯式編程的重要性,它尤其適合處理復雜的認知問題,解決復雜的業務問題,同樣能夠構建工業級的商業軟件。
2,從一個游戲認識邏輯編程
前面說了邏輯編程語言的重要性,簡單介紹了Visual Prolog這個邏輯編程語言的用途,但對於習慣了“命令式編程”的程序員來說可能對於邏輯編程語言還是沒有概念。
Prolog 語言是以一階謂詞邏輯演算為原理設計的計算機程序語言,在人工智能的發展 歷程中被寄予厚望,曾經被成為“第五代計算機語言”。Prolog 的程序結構就是事實、規則 和問題,它內置一個推理機,通過輸入事實,處理規則,求解問題。因此它跟其它程序語言 都不同,大部分都是命令式的,而 Prolog 是陳述式的,因此不需要告訴 Prolog 程序的執行 順序即可求解問題。
比如看下面的Prolog程序例子:
likes(bell, sports). % Bell 喜歡運動 likes(mary, music). % Mary 喜歡音樂 likes(mary, sports). % Mary 喜歡運動 likes(jane, reading). % Jane 喜歡閱讀 friend(john, X) :- likes(X, reading), likes(X, music). % 成為 john 的朋友需要喜歡 閱讀和音樂 friend(john, X) :- likes(X, sports), likes(X, music). % 成為 john 的朋友需要喜歡 運動和音樂 ?- friend(john, Y). %誰是 john 的朋友?
運行此程序,將獲得答案:
Y= mary
上面的代碼第1-第4行,都在說關於“喜歡”什么的事實;第5、第6行,分部定義了成為某個人的朋友的條件,這些條件成為一套規則;最后一行代碼是提問。運行Prolog程序后,Prolog內置的“推理機”回溯程序定義的事實,匹配定義的規則,將問題代入這些事實和規則進行消解,最后匹配出答案。(有關這個過程的理解,推薦大家看看《邏輯式編程語言極簡實現(使用C#) - 1. 邏輯式編程語言介紹》這篇文章,作者寫得詼諧有趣,淺顯易懂。)
上面有關Prolog的介紹節選自本人的新書《SOD框架“企業級”應用數據架構實戰》【2.1.6 數據、信息和知識】一小節的《第三,什么是知識(Knowledge)?》的內容,已購書的朋友可以看看書中相關內容更多的介紹。
也許上面這個示例程序的運行結果有點”費腦子“,並且這個程序是原生的Prolog程序,不喜歡這種語法風格。沒關系,我們只要明白Prolog語言就是由事實、規則和問題組成的就行了。下面我們再通過一個簡單一點的“游戲人生”程序來帶領大家認識邏輯編程,並且示例代碼使用大家熟悉的C#語言來模擬Prolog程序的風格,這樣來看邏輯編程就會自然點。編程之前,我們都會做需求分析,產品經理會給我們講一個”用戶故事“,在這個游戲中這是兩口子決策是否要生孩子的故事。
故事內容:
- 有一個姑娘很漂亮,美如貂蟬;
- 有一個小伙年輕有為,名叫張三;
- 張三是一個打工仔;
- 貂蟬是張三的妻子;
- 張三是貂蟬的丈夫;
- 貂蟬還沒有生孩子;
- 丈夫可以努力工作打工賺錢;
- 妻子過了35歲生孩子就晚了;
- 丈夫要孩子不能超過60歲,且存款不能小於1萬元;
- 張三努力打工。
- 張三和貂蟬現在可以生孩子了嗎?
在這個故事中,第1條-第6條,以及第10條敘述的是故事男女主角已有的“事實”,第7-9條定義的是家庭中有關生孩子的“規則”,第11條提出問題。事實一經發生就不可改變,事實可以是一些對象之間的關系,也可以是對象的行為,比如這里說貂蟬是張三的妻子。規則是一些強制性約束,比如社會性的、生理性的或者法律上的,一般也不可以隨意改變。這里定義的規則只有合法成為夫妻才可以生孩子,所以需要先描述男女主角是夫妻關系。當然不結婚也可以生孩子,但這不是本程序考慮的規則。根據事實和規則,我們就能回答一些問題了,這里的問題是男女主角何時能夠生孩子。
下面,用C#代碼來表示這個故事有關的事實、規則和問題:
Woman diaochan = new Woman() { Name = "貂蟬", Birthday = new DateTime(1990, 1, 2) }; Man zhangsan = new Man() { Name = "張三", Birthday = new DateTime(1988, 3, 5) }; Worker worker1 = new Worker(zhangsan); Wife wife1 = new Wife(diaochan,zhangsan); Husband husband1 = new Husband(zhangsan,diaochan); diaochan.ChildrenCount = 0; diaochan.ActAs<Wife>().Child_bearing(); //生孩子 zhangsan.ActAs<Husband>().Money += zhangsan.ActAs<Worker>().Work(); zhangsan.ActAs<Husband>().Child_rearing(); //生孩子
請看上面這個代碼,基本上和我們的故事“劇本”描述的一模一樣,只不過,生孩子是妻子和丈夫兩個人的事情,“一頭熟”可生不下孩子,所以對象diaocan和zhangsan都可以調用生孩子的方法Child_rearing() ,但是他們兩個人真的能生孩子嗎?這里不得不提出一個嚴肅而認真的問題:生孩子不是小事,它要看情況。這個“看情況”講的就是一個環境、時機、條件等等,比如是否符合我國有特色的“計划生育制度”,是否符合優生優育,物質條件是否足夠,心理有沒有做好准備。。。在本文中,我將這種“看情況”有一個正式的詞語來表達--場景,在當前的游戲人生故事中,這里的問題就是“生育場景”中的問題。
3,“三維度”邏輯編程
在“三維度”理論中,場景就是有角色參與的,角色在其中進行交互活動的環境。場景因為有角色參與才有意義,角色因為有場景的存在才能發揮角色的行為。在角色與場景的交互過程中,角色和場景的改變可能會誕生新的角色、產生新的場景,而這種變化可以體現在時間維度上。所以三維度理論中的角色、場景和時間是相互影響、緊密相關、不可或缺的關系,具體內容可以參考我之前的文章《業務分析三維度(場景+角色+時 間)之程序員坐禪論道》。用三維度理論可以可以很好的描述我們這個游戲人生故事中的生孩子問題,它的角色維度正好可以描述邏輯編程語言中“一階謂詞”,比如上面代碼中的Worker、Wife、Husband類,這些“謂詞”描述了對象的特征,或者對象之間的關系,可以表達一些“事實”之間的關系,實現邏輯編程語言中的“謂詞演算”;它的場景維度可以用來構建一組相關的事實,並且表達這些事實相互之間的一套規則,也就是場景規則。場景更像一個劇本中的槽,這是專家系統中有關知識表達的高級話題,在此先不予討論。這里的角色維度對應的是謂詞邏輯表示法,而場景維度更像是一套產生式規則系統,劇本包含了時間維度下的不同場景,因此三維度理論也是一套描述(表示)復雜業務知識的理論。有關謂詞邏輯、產生式規則和劇本框架,請參考《知識圖譜學習筆記(三)——知識表示方法》。
所以,要解決當前游戲中男女主角是否能生孩子的問題,我們的程序還必須引出“場景”對象,定義一個生育場景,它包括一套有關生孩子的規則,這個規則不同於丈夫、妻子角色自身的規則,前者是社會性、法律法規性質的約束;后者是生理性、心理性的約束。比如我國之前的計划生育制度,要求一對夫妻只能生育一個孩子;現在的制度是可以生兩個。因此,場景規則隨着時間的推移也可以是可以改變的,脫離時間維度去看場景問題是不對的,同樣脫離時間維度去看角色問題也不對,比如我們的故事中男女主角都會隨着時間的變化而增大年齡,有可能過了最佳生育年齡。這里可以總結出,角色對象有角色固有的規則,場景對象也有場景的規則。
假定我們已經定義了一個生育場景對象,我們就可以將男女角色放入生育場景,開始我們故事的排練了,而這個就是我們故事要寫的劇本。為了簡化劇本,下面的代碼不再重復前面已經定義的事實,直接簡化為下面的過程:
- 進入場景。
- 生孩子?
- 努力工作賺錢。
- 生孩子?
- 結束場景。
對應的代碼如下:
Console.WriteLine("-----開啟【生育場景】規則測試-------------"); diaochan.ChildrenCount = 0; husband1.Money = 5000; ProcreateContext context = new ProcreateContext(new DateTime(2010, 1, 1), zhangsan, diaochan); context.StartContext(); //場景參與人開始扮演角色 diaochan.ActAs<Wife>().Child_bearing(); zhangsan.ActAs<Husband>().Money += zhangsan.ActAs<Worker>().Work(); zhangsan.ActAs<Husband>().Child_rearing(); //啟動規則匹配 Console.WriteLine(); bool rulesFlag = context.MatchRules(); Console.WriteLine("{0} 結果:{1}", context.Name, rulesFlag); Console.Read();
運行這段程序,即可看到張三和貂蟬是否可以生孩子的結果,具體運行結果將在本系列結束后公布,讀者也可以從我的《SOD框架“企業級”應用數據架構實戰》一書中事先看到答案。
4,本篇小節
本篇先討論了什么是邏輯編程,以及邏輯編程的重要性,然后用一個實例介紹了Prolog這門邏輯編程語言。然后思考邏輯編程的特點,它和我們的“三維度”理論有着天然的契合度。運用三維度理論,我們可以很容易的用一種非邏輯編程語言--C#來實現邏輯編程的范式,這樣我們就能結合邏輯編程的有點以及.NET平台語言強大的功能,從而輕松的構建一個新的邏輯編程語言,盡管這只能稱之為一種DSL,但它也能為一種新的邏輯編程語言的設計提供一個可實現的參考方案。
在下一篇,我們將討論這個“三維度”邏輯編程語言的設計細節,已經購買了我的書的朋友可以先一睹為快。大家有什么問題可以回帖留言,也方便為我下一篇具體寫作內容提供思路,謝謝大家的支持。