产生式系统--prolog语法(知识表示与推理期末总结)

% Some simple test Prolog programs
% --------------------------------

% Knowledge bases

loves(vincent, mia).
loves(marcellus, mia).
loves(pumpkin, honey_bunny).
loves(honey_bunny, pumpkin).

jealous(X, Y) :-
    loves(X, Z),
    loves(Y, Z).


/** <examples>

?- loves(X, mia).
?- jealous(X, Y).

*/

网址:SWISH -- SWI-Prolog for SHaring

产生式规则

基本形式: A → B 或者 IF A THEN B

〈前件〉→〈后件〉 其中, 前件就是前提, 后件是结论或动作

 • 前件和后件可以是由逻辑运算符AND、OR、NOT组 成的表达式

 • 语义: 如果前提满足,则可得结论或者执行相应 的动作, 即后件由前件来触发

• 所以, 前件是规则的执行条件, 后件是规则体。

P1:消去$符号改为*

P2:使用*来消掉$

P3:*与字母的位置兑换

P4:*的消除

P5:字母顺序位置的交换。

P6:增加$。

可触发规则:当一个规则的前件被综合数据库中的数据满足时,该规则称为可触发规则

被触发规则:从可触发规则中选择一个规则来执 行,被执行的规则称为被触发规则

1. A、B是已知的条件,一开始就在综合数据库中。此时只有规则1是可触发的。由于只有一个可触发规则,所以选择 规则1执行。规则1的执行结果得到C,C被加入到综合数据 库中

2. 由于有了C,使得规则2和规则3成为可触发规则(此时规 则1的前件虽然也同样可以被满足,由于该规则已经被执 行过,而且其当前的触发条件并没有改变,与他被执行时 的条件是一样的,所以规则1不在可触发规则之列)。

3. 此时可触发规则有两条,按照顺序排队策略,排在前面的 规则优先执行,所以选择规则2为被触发规则。规则2的执 行结果产生了D,D被加入到综合数据库中。

4. 依次类推,规则3、规则5和规则4先后被执行,最终产生 了F。从而F被求得,结束运行

产生式系统分类

(一)按推理方向分类

1.正向推理

利用事实与规则的前提相匹配,触发匹 配成功的规则,把其结论作为新的事实添加到总数据 库中。

2.逆向推理

3.双向推理

(二)按搜索策略分类

1.不可撤回方式 2.试探性方式 (1)回溯方式 (2)图搜索方式 产

程序实现--Prolog基本语法

一、基本语法

 

Terms(术语)

基本符号、数据对象 represent data objects. There are 3 types of terms三类:

  1. Atoms(原子,常量):

symbolic atoms begin with lower-case letter ex. tom, bill, a1 表示一些人事物的名字(要求小写字母开头)

 numeric atoms ex. 217, -32, 2.76 数字

 Variables(变量):
  • begin with upper-case letter or underscore 用大写字母开头或者下划线
  • ex. X, U, _x1, Tom, A1
Structures(结构):

 two types:

  • function structure: f(t1, ..., tn) 函数结构:函数名称(函数变量/常量)
  • eg.edge(3,7), f(g(1),h(2,3))
  • list structure: [t1, ..., tn] where f is a symbolic atom called functor and t1, ..., tn are terms
  •  ex.  [a,b,c], [tom,X,f(tom)], [], [[a],[b]] 列表结构

Special Notation for lists: [c1, ..., cm|T] where c1, ..., cm are the first m elements of the list and T is a LIST of the remaining elements表示剩下的T个元素我们不关注。

(II) Relation(关系):

  • r(t1, ..., tn) where r is a symbolic atom and t1, ..., tn are terms.
  • ex. round, father(tom,bill), student(1111,jones,freshman,4.0)
(III) A Prolog Program consists of a finite number of Facts and Rules,

where

  • Fact: relation. 事实

  • Rule: relation 那么:- 如果relation-1, ..., relation-n.规则

 (IV) 查询Query:

?- relation-1, ..., relation-n. used to invoke a program.

如:从数组中删除一个元素

del(X,[X|Tail],Tail).

del(X,[Y|Tail],[Y|Tail1]) :- del(X,Tail,Tail1).

?- del(c,[a,b,c,d,e,f],Y)

Call:del(c,[a, b, c, d, e, f],_4372)匹配产生式左边递归调用右边

 Call:del(c,[b, c, d, e, f],_700)

 Call:del(c,[c, d, e, f],_706)匹配上了事实

 Exit:del(c,[c, d, e, f],[d, e, f])逐步返回

 Exit:del(c,[b, c, d, e, f],[b, d, e, f])

 Exit:del(c,[a, b, c, d, e, f],[a, b, d, e, f])

Y = [a, b, d, e, f]

二、例子

      

 例1: (Facts)

Rules & Facts

man(mia).

man(jody).

man(yolanda).

playsAirGuitar(jody).

party.

Query:

?- man(mia).

?- playsAirGuitar(jody).

?- playsAirGuitar(mia).

?- tattoed(jody).

?- party.

?- RockConcert.

例2:(Rule)

happy(yolanda).

listens2music(mia).

listens2music(yolanda):- happy(yolanda).

playsAirGuitar(mia):- listens2music(mia).

playsAirGuitar(yolanda):- listens2music(yolanda).

Query:

?- playsAirGuitar(mia).

也是从查询进入开始匹配,逆向开始推理,直到推出的能与已有事实匹配,再逐步回退

?- playsAirGuitar(yolanda).

例3:(合取,析取)

合取就直接逗号,要两条都满足才能推理,析取就分开写或者使用分号。

happy(vincent).

listens2music(butch).

playsAirGuitar(vincent):- listens2music(vincent), happy(vincent).

playsAirGuitar(butch):- happy(butch).

playsAirGuitar(butch):- listens2music(butch).

Query:

?- playsAirGuitar(vincent).

合取的逗号会在同一层调用两个知识去验证。

?- playsAirGuitar(butch).

简化一下:使用分号

happy(vincent).

listens2music(butch).

playsAirGuitar(vincent):- listens2music(vincent), happy(vincent).

playsAirGuitar(butch):- happy(butch); listens2music(butch).

例4:(疑问句query)

woman(mia).

woman(jody).

woman(yolanda).

loves(vincent, mia).

loves(marsellus, mia).

loves(pumpkin, honey_bunny).

loves(honey_bunny, pumpkin).

Query:

?- woman(X).

?- loves(marsellus,X), woman(X).

?- loves(pumpkin,X), woman(X).

查询中,逗号也是同时满足条件,先匹配一个,回退之后再匹配另一个。

例5:

loves(vincent,mia).

loves(marsellus,mia).

loves(pumpkin, honey_bunny).

loves(honey_bunny, pumpkin).

 jealous(X,Y):- loves(X,Z), loves(Y,Z).

Query;
?- jealous(marsellus,W).

大写字母表示未知变量,不断回退匹配事实求出未知变量。

例6:(Unification 实例化)

vertical( line(point(X,Y), point(X,Z))).

horizontal( line(point(X,Y), point(Z,Y))).

?- vertical(line(point(1,1),point(1,3))).

?- vertical(line(point(1,1),point(3,2))).

?- horizontal(line(point(1,1),point(1,Y))).

?- horizontal(line(point(2,3),Point)).        Point = point(_1704,3)

例7:(递归recursion)

isDigesting(X,Y):- justAte(X,Y).

isDigesting(X,Y):- justAte(X,Z), isDigesting(Z,Y). 规则

是递归,普通的两条规则

justAte(mosquito,blood(john)).

justAte(frog,mosquito).

justAte(stork,frog). 事实

Query:

?- isDigesting(stork,mosquito).

Call:isDigesting(stork,blood(john))始终从第一条规则开始匹配

         Call:justAte(stork,blood(john))

         Fail:justAte(stork,blood(john))

 Redo:isDigesting(stork,blood(john))

         Call:justAte(stork,_644)

         Exit:justAte(stork,frog)

         Call:isDigesting(frog,blood(john))

                 Call:justAte(frog,blood(john))

                 Fail:justAte(frog,blood(john))

         Redo:isDigesting(frog,blood(john))

                 Call:justAte(frog,_646)

                 Exit:justAte(frog,mosquito)

                 Call:isDigesting(mosquito,blood(john))    两个交集条件

                         Call:justAte(mosquito,blood(john))匹配上上面那条单个的条件

                         Exit:justAte(mosquito,blood(john))

                 Exit:isDigesting(mosquito,blood(john))

         Exit:isDigesting(frog,blood(john))

 Exit:isDigesting(stork,blood(john))

又如:

child(anna,bridget).

child(bridget,caroline).

child(caroline,donna).

child(donna,emily).

descend(X,Y):- child(X,Y).

descend(X,Y):- child(X,Z), child(Z,Y). 不是递归,普通的两条规则

?- descend(anna,donna). (有结果吗?)

又如:

child(anna,bridget).

child(bridget,caroline).

child(caroline,donna).

 child(donna,emily).

descend(X,Y):- child(X,Y).

descend(X,Y):- child(X,Z), child(Z,Y).

descend(X,Y):- child(X,Z), child(Z,U), child(U,Y). 三代,也不是递归

?- descend(anna,danna). (有结果吗?)

又如:

child(anna,bridget).

child(bridget,caroline).

child(caroline,donna).

child(donna,emily).

descend(X,Y):- child(X,Y).

descend(X,Y):- child(X,Z), descend(Z,Y).递归正确写法

?- descend(anna,donna). (有结果吗?)

例子:

定义数字succ后继

numeral(0). 事实

numeral(succ(X)):- numeral(X). 规则

?- numeral(succ(succ(succ(0)))).             true

逐步回退,只要最终匹配上了,那么就一定能够推导过来。

?- numeral(X).            X = 0

例子:

加法

add(0,X,X).

add(succ(X),Y,succ(Z)):- add(X,Y,Z). 把第一个的succ加到第二个上变成第三个

?- add(0,succ(succ(succ(0))), Result).                            Result = succ(succ(succ(0)))

?- add(succ(0),succ(succ(succ(0))), Result).

Call:add(succ(0),succ(succ(succ(0))),_4288)匹配上了左边的规则,然后递归

           Call:add(0,succ(succ(succ(0))),_672)匹配上了事实,得到Z

         Exit:add(0,succ(succ(succ(0))),succ(succ(succ(0))))

Exit:add(succ(0),succ(succ(succ(0))),succ(succ(succ(succ(0)))))

Result = succ(succ(succ(succ(0))))

?- add(succ(succ(0)),succ(succ(succ(0))), Result). 匹配三次然后回退

Call:add(succ(succ(0)),succ(succ(succ(0))),_4500)

           Call:add(succ(0),succ(succ(succ(0))),_676)

                 Call:add(0,succ(succ(succ(0))),_680)

                 Exit:add(0,succ(succ(succ(0))),succ(succ(succ(0))))

           Exit:add(succ(0),succ(succ(succ(0))),succ(succ(succ(succ(0)))))

 Exit:add(succ(succ(0)),succ(succ(succ(0))),succ(succ(succ(succ(succ(0))))))

Result = succ(succ(succ(succ(succ(0)))))

例8:(列表List)

列表头head一个元素和列表尾tail未分配的所有元素

?- [Head|Tail] = [mia, vincent, jules, yolanda].

Head = mia,
Tail = [vincentjulesyolanda]

?- [X|Y] = [ ].空列表不能用|来界定第一个元素

false

?- [X,Y|Tail] = [[ ], dead(z), [2, [b,c]], [], Z, [2, [b,c]]] .

Tail = [[2, [bc]], [], Z, [2, [bc]]],
X = [],
Y = dead(z)

?- [X1,X2,X3,X4|Tail] = [mia, vincent, marsellus, jody, yolanda].

Tail = [yolanda],
X1 = mia,
X2 = vincent,
X3 = marsellus,
X4 = jody

?- [ _,X2, _,X4|_ ] = [mia, vincent, marsellus, jody, yolanda]. 下划线位置的元素不关心,占位

X2 = vincent,
X4 = jody

成员判断

member(X,[X|T]).

member(X,[H|T]):- member(X,T). 递归不断往后查

?- member(yolanda,[yolanda,trudy,vincent,jules]).

?- member(zed,[yolanda,trudy,vincent,jules]).

?- member(X,[yolanda,trudy,vincent,jules]).          X = yolanda

member(trudy,[yolanda,trudy,vincent,jules]).  

Call:member(trudy,[yolandatrudyvincentjules])

           Call:member(trudy,[trudyvincentjules])

           Exit:member(trudy,[trudyvincentjules])

 Exit:member(trudy,[yolandatrudyvincentjules])

1true

等长a序列和b序列:

a2b([],[]).

a2b([a|L1],[b|L2]):- a2b(L1,L2).

?- a2b([a,a,a,a],[b,b,b]).         false

?- a2b([a,t,a,a],[b,b,b,c]).          false,这里的a,b是小写指的是具体元素,而不是泛指的未知数。

上面那条规则改成

a2b([X |L1],[Y |L2]):- a2b(L1,L2).

则此查询为正确。

?- a2b([a,a,a,a,a], X).

X = [bbbbb]

Call:a2b([aaaaa],_4246)

           Call:a2b([aaaa],_682)

                     Call:a2b([aaa],_688)

                                Call:a2b([aa],_700)

                                          Call:a2b([a],_712)

                                                     Call:a2b([],_706)

                 ​​​​​​​        ​​​​​​​        ​​​​​​​        Exit:a2b([],[])

                                 Exit:a2b([a],[b])

                              Exit:a2b([aa],[bb])

                     Exit:a2b([aaa],[bbb])

           Exit:a2b([aaaa],[bbbb])

 Exit:a2b([aaaaa],[bbbbb])

X = [bbbbb]

不断递归,直到情况能够满足事实,再回退

 a2b([a,a,a,a],[b,b,b,b]).

true

例9 算术1

?- 10 is 5+5.

?- 4 is 2+3.

?- X is 3 * 4.

?- R is mod(7,2).

又如:

?- X = 3 + 2.

只有is才会计算。

例9 算术2

等于==

不等于 =\=

小于等于=<

大于等于>=

?- 2 < 4+1.

?- 4+3 > 5+5.

?- 4 = 4.

TRUE

?- 2+2 = 4.

FALSE

?- 2+2 =:= 4.

TRUE

在prolog中,单个等号是不具备数据运算功能的。

例如:

addThreeAndDouble(X, Y):- Y is (X+3) * 2.

?- addThreeAndDouble(1,X).

?- addThreeAndDouble(2,X).

最后:

?- is(X,+(3,2)).

开始做题

如何统计List的长度?

len([],0).

len([_|L],N):- len(L,X), N is X + 1.

Len([3,4,5,6,7,8,9],X)

给定List,如何寻找最大的数

析取,两种情况

accMax([H|T],A,Max):- H > A, accMax(T,H,Max).

accMax([H|T],A,Max):- H =< A, accMax(T,A,Max).始终选择较大的一个放在中间位置上

accMax([],A,A).

遍历完了就把第二个位置上的值给MAX

?- accMax([1,0,5,4],0,Max).

或者添加:max([H|T],Max):- accMax(T,H,Max).

?- max([1,0,5,4], Max).

?- max([-3, -1, -5, -4], Max).

例10:字符串?

如:怎么拼接两个字符串

append([ ], L, L).

append([H|L1], L2, [H|L3]):- append(L1, L2, L3).

?- append([a,b,c],[1,2,3], R).

Call:append([a, b, c],[1, 2, 3],_4316)

         Call:append([b, c],[1, 2, 3],_698)

                 Call:append([c],[1, 2, 3],_704)

                         Call:append([],[1, 2, 3],_710)

                         Exit:append([],[1, 2, 3],[1, 2, 3])

                 Exit:append([c],[1, 2, 3],[c, 1, 2, 3])

         Exit:append([b, c],[1, 2, 3],[b, c, 1, 2, 3])

 Exit:append([a, b, c],[1, 2, 3],[a, b, c, 1, 2, 3])

R = [a, b, c, 1, 2, 3]

相关应用:

分裂

?- append(X,Y, [a,b,c,d]).

第一次匹配上了的规则路线,第二次redo不会再走

前缀:

prefix(P,L):- append(P,_,L).

后缀:

suffix(S,L):- append(_,S,L).

子集:

sublist(Sub,List):- suffix(Suffix,List), prefix(Sub,Suffix).

挑战:

如何翻转一个字符串?

append([ ], L, L).

append([H|L1], L2, [H|L3]):- append(L1, L2, L3).

naiveReverse([],[]).

naiveReverse([H|T],R):- naiveReverse(T,RT), append(RT,[H],R).

append是把字符串拼接

这里,[RT]和[H]逆着拼接就可以实现字符串翻转

可以更高效一些吗?

accReverse([ ],L,L).

accReverse([H|T],Acc,Rev):- accReverse(T,[H|Acc],Rev).

reverse(L1,L2):- accReverse(L1,[ ],L2).

trace, (reverse([a,b,c,d],X)).

 Call:reverse([a, b, c, d],_4602)

         Call:accReverse([a, b, c, d],[],_474)

                 Call:accReverse([b, c, d],[a],_474)

                         Call:accReverse([c, d],[b, a],_474)

                                 Call:accReverse([d],[c, b, a],_474)

                                         Call:accReverse([],[d, c, b, a],_474)中间那个位置存储的倒序的中间过程

                                         Exit:accReverse([],[d, c, b, a],[d, c, b, a])只有当第一个字符串被读完了,才拷贝到最终位置上

                                 Exit:accReverse([d],[c, b, a],[d, c, b, a])

                         Exit:accReverse([c, d],[b, a],[d, c, b, a])

                 Exit:accReverse([b, c, d],[a],[d, c, b, a])

         Exit:accReverse([a, b, c, d],[],[d, c, b, a])

 Exit:reverse([a, b, c, d],[d, c, b, a])

X = [d, c, b, a]

错误示范:

accReverse([],X).
accReverse([H|T],Acc):- accReverse(T,[H|Acc]).没有第三个变量在满足条件的时候保存,它会随着循环回退返回初始状态。

始末状态始终一致,未知部位除外。我们需要第三个在循环中不变的变量,在达到某个条件时(比如第一个列表为空了),将第二个位置的值拷贝过去,这样在回退过程中,第二个位置的值逐步恢复,第三个位置的不变。

call:从左往右。

exit:回退,从右往左。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值