人工智能程序設(shè)計(jì)語言課件_第1頁
人工智能程序設(shè)計(jì)語言課件_第2頁
人工智能程序設(shè)計(jì)語言課件_第3頁
人工智能程序設(shè)計(jì)語言課件_第4頁
人工智能程序設(shè)計(jì)語言課件_第5頁
已閱讀5頁,還剩145頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡介

第2章人工智能程序設(shè)計(jì)語言

2.1綜述2.2函數(shù)型程序設(shè)計(jì)語言LISP2.3邏輯型程序設(shè)計(jì)語言PROLOG2.4TurboPROLOG程序設(shè)計(jì)

2.1綜述

2.1.1函數(shù)型語言LISP是一種函數(shù)型程序設(shè)計(jì)語言。LISP程序由一組函數(shù)組成,程序的執(zhí)行過程就是一系列的函數(shù)調(diào)用和求值過程。但LISP還不是純函數(shù)型語言,準(zhǔn)確地講,它是基于λ--函數(shù)的語言。除LISP外,20世紀(jì)70年代J.Backus還提出了一種稱為FP的所謂純函數(shù)型程序設(shè)計(jì)語言。但該語言現(xiàn)在還限于理論研究,實(shí)現(xiàn)上還存在一定困難。2.1.2邏輯型語言邏輯型程序設(shè)計(jì)語言起源于PROLOG(PROgramminginLOGic的縮寫)。PROLOG語言首先由法國馬塞大學(xué)的Colmerauer和它的研究小組于1972年研制成功,后來在歐洲得到進(jìn)一步發(fā)展。特別是1981年日本宣布要以PROLOG作為他們正在研制的新一代計(jì)算機(jī)——智能計(jì)算機(jī)的核心語言,更使PROLOG舉世矚目,迅速風(fēng)靡世界。2.1.3面向?qū)ο笳Z言20世紀(jì)80年代以來,面向?qū)ο蟪绦蛟O(shè)計(jì)(ObjectOrientedProgramming,簡稱OOP)異軍突起,發(fā)展迅速,如今已日漸成熟,并越來越流行起來。面向?qū)ο蟪绦蛞云湫畔㈦[蔽、封裝、繼承、多態(tài)、消息傳遞等一系列優(yōu)良機(jī)制,大大改善了軟件的復(fù)雜性、模塊性、重用性和可維護(hù)性,有望從根本上解決軟件的生產(chǎn)效率問題。另一方面,由于面向?qū)ο蟪绦蛟O(shè)計(jì)的類、對(duì)象、繼承等概念,與人工智能特別是知識(shí)表示和知識(shí)庫產(chǎn)生了天然的聯(lián)系。因而,現(xiàn)在面向?qū)ο蟪绦蛟O(shè)計(jì)語言也成為一種人工智能程序設(shè)計(jì)語言,面向?qū)ο蟪绦蛟O(shè)計(jì)也被廣泛引入人工智能程序設(shè)計(jì),特別是知識(shí)工程、專家系統(tǒng)程序設(shè)計(jì)。面向?qū)ο蟪绦蛟O(shè)計(jì)語言也種類繁多,已發(fā)展成為一個(gè)大家族。其中最純正、最具面向?qū)ο箫L(fēng)格的語言當(dāng)推Smalltalk,而最流行的OOP語言是C++,Java則是適于網(wǎng)絡(luò)(Internet)環(huán)境的一種面向?qū)ο笳Z言。2.1.4混合型語言以上三種語言都各有所長,但也都有其不足之處。為了揚(yáng)長避短,于是便出現(xiàn)了基于這三種語言的混合型語言。1.函數(shù)型與邏輯型相結(jié)合的語言函數(shù)型與邏輯型語言的結(jié)合方式有耦合型和統(tǒng)一型兩類。統(tǒng)一型又可分為具有歸結(jié)語義的函數(shù)型語言和集成式語言兩個(gè)子類。

2.函數(shù)型與面向?qū)ο笙嘟Y(jié)合的語言在LISP語言的基礎(chǔ)上再擴(kuò)充面向?qū)ο髾C(jī)制而產(chǎn)生的語言,稱為函數(shù)型的面向?qū)ο蟪绦蛟O(shè)計(jì)語言(亦稱為面向?qū)ο蟮腖ISP)。3.邏輯型與面向?qū)ο笙嘟Y(jié)合的語言2.2.1LISP的程序結(jié)構(gòu)與運(yùn)行機(jī)制LISP的程序一般由函數(shù)的定義和函數(shù)的調(diào)用兩部分組成。其一般格式為:(DEFUN(<函數(shù)名>(<形參表>)<函數(shù)體>)(<函數(shù)名>(〖WB〗<形參表>)<函數(shù)體>)

…(<函數(shù)名>(<形參表>)<函數(shù)體>))

(<函數(shù)名><實(shí)參表>)(<函數(shù)名><實(shí)參表>)…(<函數(shù)名><實(shí)參表>)(DEFUNMOVE-DISK(fromto)(TERPRI)(PRINC″MoveDiskFrom″)(PRINCfrom)(PRINC"To")(PRINCto))

(HANOI′a′b′c3)串原子是由雙引號(hào)括起來的一串字符。如"LISPProgram"。數(shù)字原子由數(shù)字串組成。在其前面可以有符號(hào)“-”或“+”,中間可出現(xiàn)“.”,用來表示整數(shù)和實(shí)數(shù)。例如:256、-66、3.14159等。S─表達(dá)式可以遞歸定義如下:(1)原子是S─表達(dá)式。(2)若S1和S2是S─表達(dá)式,則(S1·S2)也是S─表達(dá)式。由定義,下面的式子都是S─表達(dá)式:X2123(A·B)(A·(B·C))表(list)是LISP語言中最常用的數(shù)據(jù)類型,也是主要的處理對(duì)象。表是由圓括號(hào)括起來的由空格分開的若干個(gè)元素的集合。表的一般形式為:(<S─表達(dá)式><S─表達(dá)式>…<S─表達(dá)式>)例如:(XYZ),(+12),(A(BC))左括號(hào)后面的第一個(gè)元素稱為表頭,其余的元素組成的表稱為表尾。例如,對(duì)于表(+12)的頭為+,尾為(12)。特別地,元素個(gè)數(shù)為零的表為空表,記為()或NIL。表是一種特殊的S─表達(dá)式,每一個(gè)表都對(duì)應(yīng)著一個(gè)S─表達(dá)式。二者的關(guān)系由下面的例子說明。表←————————————→S-表達(dá)式(A)(A·NIL)(AB)(A·(B·NIL))(ABC)(A·(B·(C·NIL)))((AB)CD)((A·(B·NIL))·(C·(D·NIL)))可以看出,表的S─表達(dá)式的結(jié)構(gòu)實(shí)際是一棵二叉樹。1)CAR函數(shù)格式(CAR<表>)其中CAR為函數(shù)名,它是一個(gè)保留字(下同)。功能取出表中的表頭。例如:(CAR′(LISPLanguageProgram))返回值為:LISP

2)CDR函數(shù)格式(CDR<表>)功能取出表中的表尾。例如:(CDR′(LISPLanguageProgram))返回值為:(LanguageProgram)3)CONS函數(shù)格式(CONS<S─表達(dá)式><表>)功能將S─表達(dá)式作為一個(gè)元素加到表中去,并作為所構(gòu)成新表中的第一個(gè)元素。例如:(CONS′My′(LISPLanguageProgram))返回值為:(MyLISPLanguageProgram)5)LIST函數(shù)格式(LIST<S─表達(dá)式1><S─表達(dá)式2>…<S表達(dá)式n>)功能把n個(gè)S─表達(dá)式作為元素括在一起構(gòu)成一張新表。例如:(LIST′YELLOW′RED′BLUE)返回值為:(YELLOWREDBLUE)2.算術(shù)函數(shù)LISP的算術(shù)表達(dá)式也是用函數(shù)表示的,稱為算術(shù)函數(shù)。下面我們僅舉例說明。(+25)表示2+5,返回值為7。(-(*48)(/105))表示4×8-10/5,返回值為30。格式(SET<變量><S─表達(dá)式>)功能把S─表達(dá)式賦給變量。例如:(SET′X′8);X得到值8(SET′Y′(abc));Y得到值(abc)(SET′Z(CDRY);Z得到值(bc)另外,賦值函數(shù)還有SETQ、SETF(COMMONLISP),其功能是類似的。4.謂詞函數(shù)返回值為邏輯值真或假的函數(shù)稱為謂詞函數(shù),簡稱謂詞。LISP中真和假分別用T和NIL表示,當(dāng)函數(shù)的返回值為非NIL時(shí),也表示為真。另外,NIL也表示空表。謂詞函數(shù)也有多個(gè),下面我們僅給出常用的幾個(gè)。

(1)原子謂詞ATOM格式(ATOM<參數(shù)>)功能檢測(cè)其參數(shù)是否為原子,是則返回T,否則返回NIL。例如:(ATOM′a);返回T(ATOM′(ab));返回NIL

(3)判空表函數(shù)NULL格式(NULL<參數(shù)>)功能判斷參數(shù)是否為空表,是則返回T,否則返回NIL。5.條件函數(shù)條件函數(shù)也稱分支函數(shù),類似于其他語言中的分支語句,其作用是控制程序的流程。格式(COND(P1e1)(P2e2)…(Pnen))其中Pi(i=1,...,n)為謂詞,ei(i=1,...,n)為一個(gè)或多個(gè)S─表達(dá)式。功能如果P1為真,則COND函數(shù)的值為e1(當(dāng)e1為多個(gè)S─表達(dá)式時(shí),取最后一個(gè)S─表達(dá)式的值,下同)。否則,判斷P2,……直到某個(gè)Pi真為止,然后將對(duì)應(yīng)的ei作為函數(shù)值。若沒有一個(gè)Pi的值為非NIL,則COND的返回值為NIL。特別地,Pi也可以為邏輯常量T,這時(shí)則對(duì)其對(duì)應(yīng)的各表達(dá)式求值,并把最后一個(gè)表達(dá)式的值作為COND的返回值。

例如:(COND((NULLx)0)((ATOMx)1)((LISTPx)(LENGTHx)))其語義是,若x的值為NIL,則COND的返回值為0;若x為原子,則COND的返回值為1;若x的值為表,則COND的返回值為表的長度。2.2.4自定義函數(shù)基本函數(shù)是LISP提供的基本處理功能,要用LISP編程解決實(shí)際問題,僅有基本函數(shù)還是不夠的,用戶還必須根據(jù)問題的需要,利用基本函數(shù)自定義所需的函數(shù)。自定義函數(shù)的格式為:(DEFUN<函數(shù)名>(<形參表>)<函數(shù)體>)其中函數(shù)體,又可能是用戶自定義的函數(shù)或LISP基本函數(shù)的某種組合。所以,一般來講,LISP自定義函數(shù)就是由其基本函數(shù)組合而成的。常用的組合方法有復(fù)和、分支、遞歸、迭代等。其中最具特色的構(gòu)造方法是遞歸。

例2.1定義求N!的LISP函數(shù)。階乘的公式是n!=n×(n-1)!1!=10!=1由此我們給出其LISP函數(shù)如下:(DEFUNN!(n)(COND((=n0)1)((=n1)1)(T(*n(N!(-n1))))))可以看出,該函數(shù)的最后一行中又調(diào)用了它自己。所以,這個(gè)函數(shù)N!是遞歸定義的。需說明的是,一個(gè)函數(shù)是否能遞歸定義,要取決于以下兩條:(1)函數(shù)的求值存在最簡的情形,在這種情形下函數(shù)值是顯然的或已知的;(2)該函數(shù)對(duì)于其參數(shù)的求值,可以歸結(jié)為對(duì)另一些參數(shù)的求值,而且后者比前者更容易求值,即使問題朝最簡情形逼近了一步。2.2.5程序舉例例2.2符號(hào)微分程序。這里是指數(shù)學(xué)上的一元函數(shù)求導(dǎo)。我們用D(ex)表示數(shù)學(xué)上的de/dx,這里e為需求導(dǎo)的函數(shù)表達(dá)式,x為自變量。程序如下:(DEFUND(ex)(COND((ATOMe)(IF(Eqex)10))(T(APPLY(D-RULE(CARe))(APPEND(CDRe))(LISTx)))))其中D-RULE是一個(gè)獲取給定操作符的微分規(guī)則的LISP函數(shù)。微分規(guī)則的存放,是通過為相應(yīng)操作符建立d特性的方法完成的。D-RULE的定義為(DEFUND-RULE(operator)(GEToperator′d))其中操作符d的特性值需事先用SETF函數(shù)建立好。例如對(duì)于操作符加+和乘·,在數(shù)學(xué)上有d(u+v)/dx=du/dx+dv/dxd(u·v)/dx=v·du/dx+u·dv/dx用LISP表示就是(SETF(GET′+′D)′(LAMBDA(uvx)′(+,(Dux),(Dvx))))(SETF(GET′*′D)′(LAMBDA(uvx)′(+(*,(Dux),v)(*,(Dvx),u)))))有了這些函數(shù),我們就可以用機(jī)器求符號(hào)微分了。例如,給出如下的函數(shù)調(diào)用(D′(+(*2x)(*xx))′x);即求一元函數(shù)2x+x2關(guān)于x的導(dǎo)函數(shù)則得到返回值為(+(+(*0x)(*12))(+(*1x)(*1x)))即2+2x,結(jié)果正確。

由于篇幅所限,上面我們對(duì)LISP語言僅做了簡要介紹。需進(jìn)一步學(xué)習(xí)的讀者,可參閱有關(guān)專門著作。實(shí)際上,以此為入門和基礎(chǔ),讀者就可以參照某一具體的LISP語言資料,進(jìn)行LISP程序設(shè)計(jì)了。經(jīng)過30多年的發(fā)展,LISP的方言和版本也很多。目前比較流行的有INTERLISP、MACLISP、COMMONLISP。其中COMMONLISP將成為一種標(biāo)準(zhǔn),以統(tǒng)一各種LISP方言。2.3邏輯型程序設(shè)計(jì)語言PROLOG

2.3.1PROLOG的語句PROLOG語言只有三種語句,分別稱為事實(shí)、規(guī)則和問題。

1.事實(shí)(fact)格式<謂詞名>(<項(xiàng)表>).其中謂詞名是以小寫英文字母打頭的字母、數(shù)字、下劃線等組成的字符串,項(xiàng)表是以逗號(hào)隔開的項(xiàng)序列。

PROLOG中的項(xiàng)包括由常量或變量表示的簡單對(duì)象以及函數(shù)、結(jié)構(gòu)和表等,即事實(shí)的形式是一個(gè)原子謂詞公式。

例如:student(john).like(mary,music).就是PROLOG中的兩個(gè)合法事實(shí)。

功能一般表示對(duì)象的性質(zhì)或關(guān)系。例如上面的兩個(gè)事實(shí)就分別表示“約翰是學(xué)生”和“瑪麗喜歡音樂”。作為特殊情形,一個(gè)事實(shí)也可以只有謂詞名而無參量。例如:abc.repeat.等也是允許的。2.規(guī)則(rule)格式<謂詞名>(<項(xiàng)表>):-<謂詞名>(<項(xiàng)表>){,<謂詞名>(<項(xiàng)表>)}.其中“:-”號(hào)表示“if”(也可以直接寫為if),其左部的謂詞是規(guī)則的結(jié)論(亦稱為頭),右部的謂詞是規(guī)則的前提(亦稱為體),{}表示零次或多次重復(fù),逗號(hào)表示and(邏輯與),即規(guī)則的形式是一個(gè)邏輯蘊(yùn)含式。

例如:bird(X):-animal(X),has(X,feather).grandfather(X,Y):-father(X,Z),father(Z,Y).就是PROLOG的合法規(guī)則。功能一般表示對(duì)象間的因果關(guān)系、蘊(yùn)含關(guān)系或?qū)?yīng)關(guān)系。例如,上面的第一條規(guī)則就表示“如果X是動(dòng)物,并且X有羽毛,則X是鳥”;第二條規(guī)則就表示“X是Y的祖父,如果存在Z,X是Z的父親并且Z又是Y的父親”。作為特殊情形,規(guī)則中的謂詞也可以只有謂詞名而無參量。例如:run:-start,step1(X),step2(X),end.也是一個(gè)合法規(guī)則。3.問題(question)格式?-<謂詞名>(<項(xiàng)表>){,<謂詞名>(<項(xiàng)表>)}.例如:?-student(john).?-like(mary,X).就是兩個(gè)合法的問題。功能問題表示用戶的詢問,它就是程序運(yùn)行的目標(biāo)。

2.3.2PROLOG程序PROLOG程序一般由一組事實(shí)、規(guī)則和問題組成。問題是程序執(zhí)行的起點(diǎn),稱為程序的目標(biāo)。例如下面就是一個(gè)PROLOG程序。likes(bell,sports).likes(mary,music).likes(mary,sports).likes(jane,smith).friend(john,X):-likes(X,reading),likes(X,music).friend(john,X):-likes(X,sports),likes(X,music).?-friend(john,Y).可以看出,這個(gè)程序中有四條事實(shí)、兩條規(guī)則和一個(gè)問題。其中事實(shí)、規(guī)則和問題都分行書寫。規(guī)則和事實(shí)可連續(xù)排列在一起,其順序可隨意安排,但同一謂詞名的事實(shí)或規(guī)則必須集中排列在一起。問題不能與規(guī)則及事實(shí)排在一起,它作為程序的目標(biāo)要么單獨(dú)列出,要么在程序運(yùn)行時(shí)臨時(shí)給出。這個(gè)程序的事實(shí)描述了一些對(duì)象(包括人和事物)間的關(guān)系;而規(guī)則則描述了john交朋友的條件,即如果一個(gè)人喜歡讀書并且喜歡音樂(或者喜歡運(yùn)動(dòng)和喜歡音樂),則這個(gè)人就是john的朋友(當(dāng)然,這個(gè)規(guī)則也可看作是john朋友的定義);程序中的問題是“約翰的朋友是誰?”當(dāng)然,PROLOG程序中的目標(biāo)可以變化,也可以含有多個(gè)語句(上例中只有一個(gè))。如果有多個(gè)語句,則這些語句稱為子目標(biāo)。例如對(duì)上面的程序,其問題也可以是?-likes(mary,X).或?-likes(mary,music).或?-friend(X,Y).或?-likes(bell,sports),likes(mary,music),friend(john,X).等等。當(dāng)然,對(duì)于不同的問題,程序運(yùn)行的結(jié)果一般是不一樣的。2.3.3PROLOG程序的運(yùn)行機(jī)理既然PROLOG程序是基于Horn子句的邏輯程序,那么其運(yùn)行機(jī)理自然就是基于歸結(jié)原理的演繹推理(歸結(jié)原理將在第3章介紹)。下面我們就來看PROLOG程序是怎樣運(yùn)行的。PROLOG程序的運(yùn)行是從目標(biāo)出發(fā),并不斷進(jìn)行匹配、合一、歸結(jié),有時(shí)還要回溯,直到目標(biāo)被完全滿足或不能滿足時(shí)為止。那么,什么是匹配、合一和回溯呢?下面我們就先介紹這幾個(gè)概念。1.自由變量與約束變量PROLOG中稱無值的變量為自由變量,有值的變量為約束變量。一個(gè)變量取了某值就說該變量約束于某值,或者說該變量被某值所約束,或者說該變量被某值實(shí)例化了。2.匹配合一兩個(gè)謂詞可匹配合一,是指兩個(gè)謂詞的名相同,參量項(xiàng)的個(gè)數(shù)相同,參量類型對(duì)應(yīng)相同,并且對(duì)應(yīng)參量項(xiàng)還滿足下列條件之一:(1)如果兩個(gè)都是常量,則必須完全相同。(2)如果兩個(gè)都是約束變量,則兩個(gè)約束值必須相同。(3)如果其中一個(gè)是常量,一個(gè)是約束變量,則約束值與常量必須相同。(4)至少有一個(gè)是自由變量。例如:下面的兩個(gè)謂詞pre1("ob1","ob2",Z)pre1("ob1",X,Y)只有當(dāng)變量X被約束為"ob2",且Y、Z的約束值相同或者至少有一個(gè)是自由變量時(shí),它們才是匹配合一的。3.回溯所謂回溯,就是在程序運(yùn)行期間,當(dāng)某一個(gè)子目標(biāo)不能滿足(即謂詞匹配失?。r(shí),控制就返回到前一個(gè)已經(jīng)滿足的子目標(biāo)(如果存在的話),并撤消其有關(guān)變量的約束值,然后再使其重新滿足。成功后,再繼續(xù)滿足原子目標(biāo)。如果失敗的子目標(biāo)前再無子目標(biāo),則控制就返回到該子目標(biāo)的上一級(jí)目標(biāo)(即該子目標(biāo)謂詞所在規(guī)則的頭部)使它重新匹配?;厮菀彩荘ROLOG的一個(gè)重要機(jī)制。下面,我們介紹PROLOG程序的運(yùn)行過程。我們?nèi)砸陨厦娴某绦驗(yàn)槔?。設(shè)所給的詢問是?-friend(john,Y).(john和誰是朋友?)則求解目標(biāo)為friend(john,Y).這時(shí),系統(tǒng)對(duì)程序進(jìn)行掃描,尋找能與目標(biāo)謂詞匹配合一的事實(shí)或規(guī)則頭部。顯然,程序中前面的四條事實(shí)均不能與目標(biāo)匹配,而第五個(gè)語句的左端即規(guī)則friend(john,X):-likes(X,reading),likes(X,music).的頭部可與目標(biāo)謂詞匹配合一。但由于這個(gè)語句又是一個(gè)規(guī)則,所以其結(jié)論要成立則必須其前提全部成立。于是,對(duì)原目標(biāo)的求解就轉(zhuǎn)化為對(duì)新目標(biāo)likes(X,reading),likes(X,music).的求解。這實(shí)際是經(jīng)歸結(jié),規(guī)則頭部被消去,而目標(biāo)子句變?yōu)?-likes(X,reading),likes(X,music).現(xiàn)在依次對(duì)子目標(biāo)likes(X,reading)和likes(X,music)求解。子目標(biāo)的求解過程與主目標(biāo)完全一樣,也是從頭對(duì)程序進(jìn)行掃描,不斷進(jìn)行測(cè)試和匹配合一等,直到匹配成功或掃描完整個(gè)程序?yàn)橹???梢钥闯觯瑢?duì)第一個(gè)子目標(biāo)like(X,reading)的求解因無可匹配的事實(shí)和規(guī)則而立即失敗,進(jìn)而導(dǎo)致規(guī)則friend(john,X):-likes(X,reading),likes(X,music).的整體失敗。于是,剛才的子目標(biāo)likes(X,reading)和likes(X,music)被撤消,系統(tǒng)又回溯到原目標(biāo)friend(john,X)。這時(shí),系統(tǒng)從該目標(biāo)剛才的匹配語句處(即第五句)向下繼續(xù)掃描程序中的子句,試圖重新使原目標(biāo)匹配,結(jié)果發(fā)現(xiàn)第六條語句的左部,即規(guī)則friend(john,X):-likes(X,sports),likes(X,music).的頭部可與目標(biāo)為謂詞匹配。但由于這個(gè)語句又是一個(gè)規(guī)則,于是,這時(shí)對(duì)原目標(biāo)的求解,就又轉(zhuǎn)化為依次對(duì)子目標(biāo)likes(X,sports)和likes(X,music)的求解。這次子目標(biāo)likes(X,sports)與程序中的事實(shí)立即匹配成功,且變量X被約束為bell。于是,系統(tǒng)便接著求解第二個(gè)子目標(biāo)。由于變量X已被約束,所以這時(shí)第二個(gè)子目標(biāo)實(shí)際上已變成了likes(bell,music).由于程序中不存在事實(shí)likes(bell,music),所以該目標(biāo)的求解失敗。于是,系統(tǒng)就放棄這個(gè)子目標(biāo),并使變量X恢復(fù)為自由變量,然后回溯到第一個(gè)子目標(biāo),重新對(duì)它進(jìn)行求解。由于系統(tǒng)已經(jīng)記住了剛才已同第一子目標(biāo)謂詞匹配過的事實(shí)的位置,所以重新求解時(shí),便從下一個(gè)事實(shí)開始測(cè)試。易見,當(dāng)測(cè)試到程序中第三個(gè)事實(shí)時(shí),第一個(gè)子目標(biāo)便求解成功,且變量X被約束為mary。這樣,第二個(gè)子目標(biāo)也就變成了likes(mary,music).再對(duì)它進(jìn)行求解。這次很快成功。由于兩個(gè)子目標(biāo)都求解成功,所以,原目標(biāo)friend(john,Y)也成功,且變量Y被約束為mary(由Y與X的合一關(guān)系)。于是,系統(tǒng)回答:Y=mary程序運(yùn)行結(jié)束。上面只給出了問題的一個(gè)解。如果需要和可能的話,系統(tǒng)還可把john的所有朋友都找出來。我們把上述程序的運(yùn)行過程再用示意圖(圖2─1)描述如下:圖2─1PROLOG程序運(yùn)行機(jī)理示例上述程序的運(yùn)行是一個(gè)通過推理實(shí)現(xiàn)的求值過程。我們也可以使它變?yōu)樽C明過程。例如,把上述程序中的詢問改為friend(john,mary)則系統(tǒng)會(huì)回答:yes若將詢問改為:friend(john,smith)則系統(tǒng)會(huì)回答:no從上述程序的運(yùn)行過程可以看出,PROLOG程序的執(zhí)行過程是一個(gè)(歸結(jié))演繹推理過程。其特點(diǎn)是:推理方式為反向推理,控制策略是深度優(yōu)先,且有回溯機(jī)制。其具體實(shí)現(xiàn)方法是:匹配子句的順序是自上而下;子目標(biāo)選擇順序是從左向右;(歸結(jié)后)產(chǎn)生的新子目標(biāo)總是插入被消去的目標(biāo)處(即目標(biāo)隊(duì)列的左部)。PROLOG的這種歸結(jié)演繹方法被稱為SLD(LinearresolutionwithSelectionfunctionforDefiniteclause)歸結(jié),或SLD反駁-消解法。SLD歸結(jié)就是PROLOG程序的運(yùn)行機(jī)理,它也就是所謂的PROLOG語言的過程性語義。2.4TurboPROLOG程序設(shè)計(jì)

2.4.1TurboPROLOG的程序結(jié)構(gòu)一個(gè)完整的TurboPROLOG(2.0版)程序一般包括常量段、領(lǐng)域段、數(shù)據(jù)庫段、謂詞段、目標(biāo)段和子句段等六個(gè)部分。各段以其相應(yīng)的關(guān)鍵字constants、domains、database、predicates、goal和clauses開頭加以標(biāo)識(shí)。:另外,在程序的首部還可以設(shè)置指示編譯程序執(zhí)行特定任務(wù)的編譯指令;在程序的任何位置都可設(shè)置注解??傊?,一個(gè)完整的TurboPROLOG(2.0版)程序的結(jié)構(gòu)如下/*<注釋>*/<編譯指令>constants<常量說明>domains<域說明>database<數(shù)據(jù)庫說明>predicates<謂詞說明>goal<目標(biāo)語句>clauses<子句集>當(dāng)然,一個(gè)程序不一定要包括上述所有段,但一個(gè)程序至少要有一個(gè)predicates段、clauses段和goal段。在大多數(shù)情形中,還需要一個(gè)domains段,以說明表、復(fù)合結(jié)構(gòu)及用戶自定義的域名。如若省略goal段,則可在程序運(yùn)行時(shí)臨時(shí)給出,但這僅當(dāng)在開發(fā)環(huán)境中運(yùn)行程序時(shí)方可給出。若要生成一個(gè)獨(dú)立的可執(zhí)行文件,則在程序中必須包含goal段。另一方面,一個(gè)程序也只能有一個(gè)goal段。

例2.3如果把上節(jié)中的程序要作為TurboPROLOG程序,則應(yīng)改寫為:/*例子程序-1*/DOMAINSname=symbolPREDICATESlikes(name,name).friend(name,name)GOALfriend(john,Y),write(″Y=″,Y).

CLAUSESlikes(bell,sports).likes(mary,music).likes(mary,sports).likes(jane,smith).friend(john,X):-likes(X,sports),likes(X,music).friend(john,X):-likes(X,reading),likes(X,music).結(jié)合上例,我們?cè)賹?duì)上述程序結(jié)構(gòu)中的幾個(gè)主要段的內(nèi)容和作用加以說明(其余段在后面用到時(shí)再作說明):領(lǐng)域段該段說明程序謂詞中所有參量項(xiàng)所屬的領(lǐng)域。領(lǐng)域的說明可能會(huì)出現(xiàn)多層說明,直到最終說明到TurboPROLOG的標(biāo)準(zhǔn)領(lǐng)域?yàn)橹?如上例所示)。TurboPROLOG的標(biāo)準(zhǔn)領(lǐng)域即標(biāo)準(zhǔn)數(shù)據(jù)類型,包括整數(shù)、實(shí)數(shù)、符號(hào)、串和符號(hào)等,其具體說明如表2.1所示。表2.1TurboPROLOG的標(biāo)準(zhǔn)領(lǐng)域謂詞段該段說明程序中用到的謂詞的名和參量項(xiàng)的名(但TurboPROLOG的內(nèi)部謂詞無須說明)。子句段該段是TurboPROLOG程序的核心,程序中的所有事實(shí)和規(guī)則就放在這里,系統(tǒng)在試圖滿足程序的目標(biāo)時(shí)就對(duì)它們進(jìn)行操作。

目標(biāo)段該段是放置程序目標(biāo)的地方。目標(biāo)段可以只有一個(gè)目標(biāo)謂詞,例如上面的例子中就只有一個(gè)目標(biāo)謂詞;也可以含有多個(gè)目標(biāo)謂詞,如:goalreadint(X),Y=X+3,write("Y=",Y).就有三個(gè)目標(biāo)謂詞。這種目標(biāo)稱為復(fù)合目標(biāo)。另外,一般稱程序目標(biāo)段中的目標(biāo)為內(nèi)部目標(biāo),而稱在程序運(yùn)行時(shí)臨時(shí)給出的目標(biāo)為外部目標(biāo)。2.4.2TurboPROLOG的數(shù)據(jù)與表達(dá)式1.領(lǐng)域1)標(biāo)準(zhǔn)領(lǐng)域TurboPROLOG中不定義變量的類型,只說明謂詞中各個(gè)項(xiàng)的取值域。2)結(jié)構(gòu)結(jié)構(gòu)也稱復(fù)合對(duì)象,它是TurboPROLOG謂詞中的一種特殊的參量項(xiàng)(類似于謂詞邏輯中的函數(shù))。結(jié)構(gòu)的一般形式為<函子>(<參量表>)其中函子及參量的標(biāo)識(shí)符與謂詞相同。注意,這意味著結(jié)構(gòu)中還可包含結(jié)構(gòu)。所以,復(fù)合對(duì)象可表達(dá)樹形數(shù)據(jù)結(jié)構(gòu)。例如下面的謂詞likes(Tom,sports(football,basketball,table-tennis)).中的sports(football,basketball,table-tennis)就是一個(gè)結(jié)構(gòu),即復(fù)合對(duì)象。又如:person("張華",student("西安石油學(xué)院"),address("中國","陜西","西安")).

reading("王宏",book("人工智能技術(shù)基礎(chǔ)教程","西安電子科技大學(xué)出版社")).

friend(father("Li"),father("Zhao")).這幾個(gè)謂詞中都有復(fù)合對(duì)象。復(fù)合對(duì)象在程序中的說明,需分層進(jìn)行。例如,對(duì)于上面的謂詞likes(Tom,sports(football,basketball,table-tennis)).在程序中可說明如下:domainsname=symbolsy=symbolsp=sports(sy,sy,sy)predicateslikes(name,sp)3)表表的一般形式是[x1,x2,…,xn]其中xi(i=1,2,…,n)為PROLOG的項(xiàng),一般要求同一個(gè)表的元素必須屬于同一領(lǐng)域。不含任何元素的表稱為空表,記為[]。例如下面就是一些合法的表。[1,2,3][apple,orange,banana,grape,cane]["PROLOG","MAENS","PROGRAMMING","inlogic"][[a,b],[c,d],[e]][]表的最大特點(diǎn)是其元素個(gè)數(shù)可在程序運(yùn)行期間動(dòng)態(tài)變化。表的元素也可以是結(jié)構(gòu)或表,且這時(shí)其元素可以屬于不同領(lǐng)域。例如:[name("LiMing"),age(20),sex(male),address(xian)][[1,2],[3,4,5],[6,7]]都是合法的表。后一個(gè)例子說明,表也可以嵌套。實(shí)際上,表是一種特殊的結(jié)構(gòu)。它是遞歸結(jié)構(gòu)的另一種表達(dá)形式。這個(gè)結(jié)構(gòu)的函數(shù)名取決于具體的PROLOG版本。這里我們就用一個(gè)圓點(diǎn)來表示。下面就是一些這樣的結(jié)構(gòu)及它們的表表示形式:結(jié)構(gòu)形式表形式·(a,[])[a]·(a,·(b,[]))[a,b]·(a,·(b,·(c,[])))[a,b,c]表的說明方法是在其組成元素的說明符后加一個(gè)星號(hào)*。如:domainslists=string*predicatespl(lists)就說明謂詞pl中的項(xiàng)lists是一個(gè)由串string組成的表。對(duì)于由結(jié)構(gòu)組成的表,至少得分三步說明。例如對(duì)于下面謂詞p中的表p([name("Liming"),age(20)])則需這樣說明:domainsrec=seg*seg=name(string);age(integer)predicatesp(rec)2.常量與變量由上面的領(lǐng)域可知,TurboPROLOG的常量有整數(shù)、實(shí)數(shù)、字符、串、符號(hào)、結(jié)構(gòu)、表和文件這八種數(shù)據(jù)類型。同理,TurboPROLOG的變量也就有這八種取值。另外,變量名要求必須是以大寫字母或下劃線開頭的字母、數(shù)字和下劃線序列,或者只有一個(gè)下劃線。這后一種變量稱為無名變量。3.算術(shù)表達(dá)式TurboPROLOG提供了五種最基本的算術(shù)運(yùn)算:加、減、乘、除和取模,相應(yīng)運(yùn)算符號(hào)為+、-、*、/、mod。這五種運(yùn)算的順序?yàn)椋?、/、mod優(yōu)先于+、-。同級(jí)從左到右按順序運(yùn)算,括號(hào)優(yōu)先。算術(shù)表達(dá)式的形式與數(shù)學(xué)中的形式基本一樣。例如:數(shù)學(xué)中的算術(shù)表達(dá)式PROLOG中的算術(shù)表達(dá)式x+yzX+Y*Zab-c/dA*B-C/DumodvUmodV(表示求U除以V所得的余數(shù))即是說,TurboPROLOG中算術(shù)表達(dá)式采用通常數(shù)學(xué)中使用的中綴形式。這種算術(shù)表達(dá)式為PROLOG的一種異體結(jié)構(gòu),若以PROLOG的結(jié)構(gòu)形式來表示,則它們應(yīng)為+(X,*(Y,Z))-(*(A,B),/(C,D))mod(U,V)所以,運(yùn)算符+、-、*、/和mod實(shí)際也就是PROLOG內(nèi)部定義好了的函數(shù)符。在TurboPROLOG程序中,如果一個(gè)算術(shù)表達(dá)式中的變?cè)勘粚?shí)例化(即被約束)的話,則這個(gè)算術(shù)表達(dá)式的值就會(huì)被求出。求出的值可用來實(shí)例化某變量,也可用來同其他數(shù)量進(jìn)行比較,用一個(gè)算術(shù)表達(dá)式的值實(shí)例化一個(gè)變量的方法是用謂詞“is”或“=”來實(shí)現(xiàn)。例如:YisX+5或Y=X+5(*)就使變量Y實(shí)例化為X+5的值(當(dāng)然X也必須經(jīng)已被某值實(shí)例化),可以看出,這里對(duì)變量Y的實(shí)例化方法類似于其他高級(jí)程序語言中的“賦值”,但又不同于賦值。例如,在PROLOG中下面的式子是錯(cuò)誤的:X=X+14.關(guān)系表達(dá)式TurboPROLOG提供了六種常用的關(guān)系運(yùn)算,即小于、小于或等于、等于、大于、大于或等于和不等于,其運(yùn)算符依次為<,<=,=,>,>=,<>TurboPROLOG的關(guān)系表達(dá)式的形式和數(shù)學(xué)中的也基本一樣,例如:數(shù)學(xué)中的關(guān)系式TurboPROLOG中的關(guān)系式X+1≥YX+1>=YX≠YX<>Y

即是說,TurboPROLOG中的關(guān)系式也用中綴形式。當(dāng)然,這種關(guān)系式為TurboPROLOG中的異體原子。若按TurboPROLOG中的原子形式來表示,則上面的兩個(gè)例子為>=(X+1,Y)和<>(X,Y)所以上述六種關(guān)系運(yùn)算符,實(shí)際上也就是TurboPROLOG內(nèi)部定義好了的六個(gè)謂詞。這六個(gè)關(guān)系運(yùn)算符可用來比較兩個(gè)算術(shù)表達(dá)式的大小。所以上述六種關(guān)系運(yùn)算符,實(shí)際上也就是TurboPROLOG內(nèi)部定義好了的六個(gè)謂詞。這六個(gè)關(guān)系運(yùn)算符可用來比較兩個(gè)算術(shù)表達(dá)式的大小。例如:brother(Name1,Name2):-person(Name1,man,Age1),person(Name2,man,Age2),mother(Z,Name1),mother(Z,Name2),Age1>Age2.需要說明的是,“=”的用法比較特殊,它既可以表示比較,也可以表示約束值,即使在同一個(gè)規(guī)則中的同一個(gè)“=”也是如此。例如:p(X,Y,Z):-Z=X+Y.當(dāng)變量X、Y、Z全部被實(shí)例化時(shí),“=”就是比較符。如:對(duì)于問題Goal:p(3,5,8).機(jī)器回答:yes。而對(duì)于Goal:p(3,5,7).機(jī)器回答:no。即這時(shí)機(jī)器把X+Y的值,與Z的值進(jìn)行比較。但當(dāng)X,Y被實(shí)例化,為Z未被實(shí)例化時(shí),“=”號(hào)就是約束符。如:Goal:p(3,5,Z).機(jī)器回答:Z=8這時(shí),機(jī)器使Z實(shí)例化為X+Y的結(jié)果。2.4.3輸入與輸出雖然PROLOG能自動(dòng)輸出目標(biāo)子句中的變量的值,但這種輸出功能必定有限,往往不能滿足實(shí)際需要;另一方面,對(duì)通常大多數(shù)的程序來說,運(yùn)行時(shí)從鍵盤上輸入有關(guān)數(shù)據(jù)或信息也是必不可少的。為此每種具體PROLOG一般都提供專門的輸入和輸出謂詞,供用戶直接調(diào)用。例如,下面就是TorboPROLOG的幾種輸入輸出謂詞:(1)readln(X)。這個(gè)謂詞的功能是從鍵盤上讀取一個(gè)字符串,然后約束給變量X。(2)readint(X)。這個(gè)謂詞的功能是從鍵盤上讀取一個(gè)整數(shù),然后約束給變量X,如果鍵盤上打入的不是整數(shù)則該謂詞失敗。(3)readreal(X)。這個(gè)謂詞的功能是從鍵盤上讀取一個(gè)實(shí)數(shù),然后約束給變量X,如果鍵盤上打入的不是實(shí)數(shù)則該謂詞失敗。(4)readchar(X)。這個(gè)謂詞的功能是從鍵盤上讀取一個(gè)字符,然后約束給變量X,如果鍵盤上打入的不是單個(gè)字符,則該謂詞失敗。(5)write(X1,X2,…Xn)。這個(gè)謂詞的功能是把項(xiàng)Xi(i=1,2,…n)的值顯示在屏幕上或者打印在紙上,當(dāng)有某個(gè)Xi未實(shí)例化時(shí),該謂詞失敗,其中的Xi可以是變量,也可以是字符串或數(shù)字。(6)nl換行謂詞。它使后面的輸出(如果有的話)另起一行。另外,利用write的輸出項(xiàng)"\n"也同樣可起換行作用。例如:write("name"),nl,write("age")與write("name","\n","age")的效果完全一樣。例2.4用上面的輸入輸出謂詞編寫一個(gè)簡單的學(xué)生成績數(shù)據(jù)庫查詢程序。PREDICATESstudent(integer,string,real)gradeGOALgrade.CLAUSESstudent(1,"張三",90.2).student(2,"李四",95.5).student(3,"王五",96.4).grade:-write("請(qǐng)輸入姓名:"),readln(Name),student(-,Name,Score),nl,write(Name,"的成績是",Score).grade:-write(“對(duì)不起,找不到這個(gè)學(xué)生!”).grade:-write("對(duì)不起,找不到這個(gè)學(xué)生!").下面是程序運(yùn)行時(shí)的屏幕顯示:請(qǐng)輸入姓名:王五王五的成績是96.4。2.4.4分支與循環(huán)PROLOG中并無專門的分支和循環(huán)語句,但PROLOG也可實(shí)現(xiàn)分支和循環(huán)程序結(jié)構(gòu)。1.分支對(duì)于通常的IF-THEN-ELSE分支結(jié)構(gòu),PROLOG可用兩條同頭的并列規(guī)則實(shí)現(xiàn)。例如,將IFx>0THENx:=1ELSEx:=0用PROLOG實(shí)現(xiàn)則是Br:-x>0,x=1.Br:-x=0.類似地,對(duì)于多分支,可以用多條規(guī)則實(shí)現(xiàn)。例如:Br:-x>0,x=1.Br:-x=0,x=0.Br:-x<0,x=-1.2.循環(huán)PROLOG可以實(shí)現(xiàn)計(jì)循環(huán)次數(shù)的FOR循環(huán),也可以實(shí)現(xiàn)不計(jì)循環(huán)次數(shù)的DO循環(huán)。例如下面的程序段就實(shí)現(xiàn)了循環(huán),它使得write語句重復(fù)執(zhí)行了三次,而打印輸出了三個(gè)學(xué)生的記錄。student(1,"張三",90.2).student(2,"李四",95.5).student(3,"王五",96.4).print:-student(Number,Name,Score),write(Number,Name,Score),nl,Number=3.這個(gè)例子可以看作是計(jì)數(shù)循環(huán)。當(dāng)然,也可以通過設(shè)置計(jì)數(shù)器而實(shí)現(xiàn)真正的計(jì)數(shù)循環(huán)。下面的程序段實(shí)現(xiàn)的則是不計(jì)數(shù)的DO循環(huán)。student(1,"張三",90.2).student(2,"李四",95.5).student(3,"王五",96.4).print:-student(Number,Name,Score),write(Number,Name,Score),nl,fail.print:-.這個(gè)程序段中的fail是一個(gè)內(nèi)部謂詞,它的語義是恒失敗。這個(gè)程序段與上面的程序段的差別僅在于把原來用計(jì)數(shù)器(或標(biāo)記數(shù))循環(huán)控制語句變成了恒失敗謂詞fail,另外再增加了一個(gè)print語句。增加這個(gè)語句的目的是為程序設(shè)置一個(gè)出口。因?yàn)閒ail是恒失敗,下面若無出口的話,將引起print本身的失敗。進(jìn)而又會(huì)導(dǎo)致程序中的連鎖失敗。2.4.5動(dòng)態(tài)數(shù)據(jù)庫動(dòng)態(tài)數(shù)據(jù)庫就是在內(nèi)存中實(shí)現(xiàn)的動(dòng)態(tài)數(shù)據(jù)結(jié)構(gòu)。它由事實(shí)組成,程序可以對(duì)它操作,所以在程序運(yùn)行期間它可以動(dòng)態(tài)變化。TurboPROLOG提供了三個(gè)動(dòng)態(tài)數(shù)據(jù)庫操作謂詞:asserta(<fact>).assertz(<fact>).retract(<fact>).其中fact表示事實(shí)。這三個(gè)謂詞的功能是:asserta(<fact>).把fact插入當(dāng)前動(dòng)態(tài)數(shù)據(jù)庫中的同名謂詞的事實(shí)之前;assertz(<fact>).把fact插入當(dāng)前動(dòng)態(tài)數(shù)據(jù)庫中的同名謂詞的事實(shí)之后;retract(<fact>).把fact從當(dāng)前動(dòng)態(tài)數(shù)據(jù)庫中刪除。例如語句asserta(student(20,"李明",90.5)).將在內(nèi)存的謂詞名為student的事實(shí)前插入一個(gè)新事實(shí):student(20,"李明",90.5)如果內(nèi)存中還沒有這樣的事實(shí),則它就是第一個(gè)。又如語句retract(student(20,-,-)).將從內(nèi)存的動(dòng)態(tài)數(shù)據(jù)庫中的刪除事實(shí)student(20,-,-)它可解釋為學(xué)號(hào)為20的一個(gè)學(xué)生的記錄。注意,這里用了無名變量-??梢钥闯?,PROLOG提供的動(dòng)態(tài)數(shù)據(jù)庫機(jī)制,可非常方便地實(shí)現(xiàn)堆棧、隊(duì)列等動(dòng)態(tài)數(shù)據(jù)結(jié)構(gòu),提供的數(shù)據(jù)庫操作謂詞大大簡化了編程。另外,PROLOG還提供了謂詞save(<>).consult(<>).前者可將當(dāng)前的動(dòng)態(tài)數(shù)據(jù)庫存入磁盤文件,后者則可將磁盤上的一個(gè)事實(shí)數(shù)據(jù)文件調(diào)入內(nèi)存。2.4.6表處理與遞歸表是PROLOG中一種非常有用的數(shù)據(jù)結(jié)構(gòu)。表的表述能力很強(qiáng),數(shù)字中的序列、集合,通常語言中的數(shù)組、記錄等均可用表來表示。表的最大特點(diǎn)是其長度不固定,在程序的運(yùn)行過程中可動(dòng)態(tài)地變化。具體來講,就是在程序運(yùn)行時(shí),可對(duì)表施行一些操作,如給表中添加一個(gè)元素,或從中刪除一個(gè)元素,或者將兩個(gè)表合并為一個(gè)表等等。用表還可以方便地構(gòu)造堆棧、隊(duì)列、鏈表、樹等動(dòng)態(tài)數(shù)據(jù)結(jié)構(gòu)。表還有一個(gè)重要特點(diǎn),就是它可分為頭和尾兩部分。表頭是表中第一個(gè)元素,而表尾是表中除第一個(gè)元素外的其余元素按原來順序組成的表。例如下面的例子:表表頭表尾[1,2,3,4,5]1[2,3,4,5][apple,orange,banana]apple[orange,banana][[a,b],[c],[d,e]][a,b][[c],[d,e]]["PROLOG"]"PROLOG“[][]無定義無定義在程序中是用豎線“|”來區(qū)分表頭和表尾的,而且還可以使用變量。例如一般地用[H|T]來表示一個(gè)表,其中H、T都是變量,H為表頭,T為表尾。注意,此處H是一個(gè)元素(表中第一個(gè)元素),而T則是一個(gè)表(除第一個(gè)元素外的表中其余元素按原來順序組成的表)。表的這種表示法很有用,它為表的操作提供了極大的方便。下面我們就給出用這種表示法通過匹配合一提取表頭和表尾的例子。表1表2合一后的變量值[X|Y][a,b,c]X=a,Y=[b,c][X|Y][a]X=a,Y=[][a|Y][X,b]X=a,Y=[b][X,Y,Z][a,b,c]X=a,Y=b,Z=c[[a,Y]|Z][[X,b],[c]]X=a,Y=b,Z=[[c]]還需說明的是,表中的豎杠“|”后面只能有一個(gè)變量。例如寫法[X|Y,Z]就是錯(cuò)誤的。但豎杠的前面的變量可以多于一個(gè)。例如寫法[X,Y|Z]是允許的。這樣,這個(gè)表同[a,b,c]匹配合一后,有X=a,Y=b,Z=[c]另外,豎杠的前面和后面也可以是常量,例如[a|Y]和[X|b]都是允許的,但注意,后一個(gè)表稱為無尾表,如果它同表[a|Y]匹配,則有X=a,Y=b(而不是Y=[b])如果無豎杠“|”,則不能分離出表尾。例如,表[X,Y,Z]與[a,b,c]合一后得X=a,Y=b,Z=c。其中變量Z并非等于[c]。例2.5設(shè)計(jì)一個(gè)能判斷對(duì)象X是表L的成員的程序。我們可以這樣設(shè)想:(1)如果X與表L中的第一個(gè)元素(即表頭)是同一個(gè)對(duì)象,則X就是L的成員;(2)如果X是L的尾部的成員,則X也就是L的成員。根據(jù)這種邏輯關(guān)系,于是有下面的PROLOG程序:member(X,[X|Tail]).member(X,[Head|Tail]):-member(X,Tail).其中第一個(gè)子句的語義就是上面的第一句話,第二個(gè)子句的語義就是上面的第二句話??梢钥闯?,這個(gè)程序中使用了遞歸技術(shù),因?yàn)橹^詞member的定義中又含有它自身。利用這個(gè)程序我們就可以判定任意給定的一個(gè)對(duì)象和一個(gè)表之間是否具有member(成員)關(guān)系。例如,我們?nèi)”鞮為[a,b,c,d],取X為a,對(duì)上面的程序提出如下詢問:Goal:member(a,[a,b,c,d]).則有回答:yes同樣對(duì)于詢問:Goal:member(b,[a,b,c,d]).Goal:member(c,[a,b,c,d]).Goal:member(d,[a,b,c,d]).都有回答:yes但若詢問Goal:member(e,[a,b,c,d]).則回答:no如果我們這樣詢問Goal:member(X,[a,b,c,d]).意思是要證明存在這樣的X,它是該表的成員,這時(shí)系統(tǒng)返回X的值,即X=a如果需要的話,系統(tǒng)還會(huì)給出X的其他所有值。例2.6表的拼接程序,即把兩個(gè)表連接成一個(gè)表。

append([],L,L).append([H|T],L2,[H|Tn]):-append(T,L2,Tn).程序中第一個(gè)子句的意思是空表同任一表L拼接的結(jié)果仍為表L;第二個(gè)子句的意思是說,一個(gè)非空的表L1與另一個(gè)表L2拼接的結(jié)果L3是這樣一個(gè)表,它的頭是L1的頭,它的尾是由L1的尾T同L2拼接的結(jié)果Tn。這個(gè)程序刻劃了兩個(gè)表與它們的拼接表之間的邏輯關(guān)系??梢钥闯?,謂詞append是遞歸定義的,子句append([],L,L).為終結(jié)條件,即遞歸出口。對(duì)于這個(gè)程序,如果我們?cè)儐朑oal:append([1,2,3],[4,5],L).則系統(tǒng)便三次遞歸調(diào)用程序中的第二個(gè)子句,最后從第一個(gè)子句終止,然后反向依次求出每次的拼接表,最后輸出L=[1,2,3,4,5]當(dāng)然,對(duì)于這個(gè)程序也可以給出其他各種詢問,如:Goal:append([1,2,3],[4,5],[1,2,3,4,5]).系統(tǒng)回答:yesGoal:append([1,2,3],[4,5],[1,2,3,4,5,6]).系統(tǒng)回答:noGoal:append([1,2,3],Y,[1,2,3,4,5]).系統(tǒng)回答:Y=[4,5]Goal:append(X,[4,5],[1,2,3,4,5]).系統(tǒng)回答:X=[1,2,3]Goal:append(X,Y,[1,2,3,4,5]).系統(tǒng)回答:X=[],Y=[1,2,3,4,5]X=[1],Y=[2,3,4,5]X=[1,2],Y=[3,4,5]X=[1,2,3],Y=[4,5]…等等(如果需要所有解的話)。例2.7表的輸出。print([]).print([H|T]):-write(H),print(T).例2.8表的倒置,即求一個(gè)表的逆序表。reverse([],[]).reverse([H|T],L):-reverse(T,L1),append(L1,[H],L).這里,reverse的第一個(gè)項(xiàng)是輸入,即原表,第二個(gè)項(xiàng)是輸出,即原表的倒置。2.4.7回溯控制PROLOG在搜索目標(biāo)解的過程中,具有回溯機(jī)制,即當(dāng)某一個(gè)子目標(biāo)Gi不能滿足時(shí),就返回到該子目標(biāo)的前一個(gè)子目標(biāo)Gi-1,并放棄Gi-1的當(dāng)前約束值,使它重新匹配合一。在實(shí)際問題中,有時(shí)卻不需要回溯,為此PROLOG中就專門定義了一個(gè)阻止回溯的內(nèi)部謂詞——“!”,稱為截?cái)嘀^詞。

截?cái)嘀^詞的語法格式很簡單,就是一個(gè)感嘆號(hào)“!”。!的語義是:(1)若將“!”插在子句體內(nèi)作為一個(gè)子目標(biāo),它總是立即成功;(2)若“!”位于子句體的最后,則它就阻止對(duì)它所在子句的頭謂詞的所有子句的回溯訪問,而讓回溯跳過該頭謂詞(子目標(biāo)),去訪問前一個(gè)子目標(biāo)(如果有的話);(3)若“!”位于其他位置,則當(dāng)其后發(fā)生回溯且回溯到“!”處時(shí),就在此處失敗,并且“!”還使它所在子句的頭謂詞(子目標(biāo))整個(gè)失?。醋柚乖偃ピL問頭謂詞的其余子句(如果有的話),即迫使系統(tǒng)直接回溯到該頭謂詞(子目標(biāo))的前一個(gè)子目標(biāo)(如果有的話))。例2.9考慮下面的程序:p(a).(2─1)p(b).(2─2)q(b).(2─3)r(X):-p(X),q(X).(2─4)r(c).對(duì)于目標(biāo):r(Y).可有一個(gè)解Y=b但當(dāng)我們把式(2─4)改為r(X):-p(X),!,q(X).(2─4′)時(shí),卻無解。這是由于添加了截?cái)嘀^詞“!”。因?yàn)槭?2─4′)中求解子目標(biāo)p(X)時(shí),X被約束到a,然后跳過“!”,但在求解子目標(biāo)q(a)時(shí)遇到麻煩,于是又回溯到“!”,而“!”阻止了對(duì)p(X)的下一個(gè)子句p(b)和r的下一個(gè)定義子句r(c)的訪問。從而,導(dǎo)致整個(gè)求解失敗。例2.10設(shè)有程序:g0:-g11,g12,g13.(2─5)g0:-g14.(2─6)g12:-g21,!,g23.(2─7)g12:-g24,g25.(2─8).........給出目標(biāo):g0.假設(shè)運(yùn)行到子目標(biāo)g23時(shí)失敗,這時(shí)如果子句(2─7)中無!的話,則會(huì)回溯到g21,并且,如果g21也失敗的話,則會(huì)訪問下面的子句(2─8)。但由于有!存在,所以不能回溯到g21,而直接宣告g12失敗。于是,由子句(2─5),這時(shí)則回溯到g11。如果我們把子句(2─7)改為g12:-g21,g23,!.

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

評(píng)論

0/150

提交評(píng)論