CLIPS是一个专家系统,它用C语言编定。全称是The C Language Integrated Production System.它可以应用到很多的系统上,如Microsoft Windows,Macintosh,VAX 11/780等。事实上,由于CLIPS 由C语言编写,所以理论上,只要有C语言的编绎器,我们可以将CLIPS移值到任何的系统上。
专家系统是将某领域专家们的知识与经验,经过知识加工服务的过程,建立一套以推理的方式来解决问题的系统。它就像某一领域的专家一样,能够对该领域的一系列问题进行判定。比如医学疹断专家系统(疹断各种疾病),农业分析系统等。
1.从C到CLIPS
虽然CLIPS是用C语言编定出来的,但是事实上,它跟C语言完全完全是两码事。因为它们在思想上是不同的。如果你想深入学习CLIPS,我建议你先去看看有关函数式语言(如LISP)的东西。在函数式语言中,没有顺序跟循环(在命令式语言比如C中到处都是),只有递归还有一些其他的东西。可能我们用C语言编程时老是想着怎么定义程序的输入,怎么样通过一个算法得到程序的输出。这是标准的冯。诺依曼体系结构的扩展,它很大程度上改进了程序的执行效率,但从另一方面来说,它加大了程序员的工作量和工作复杂度。相对来说,函数式语言恰好做了相反的事情。程序员轻松,而机器跑得辛苦,应该算是函数式语言的一大特点。
在CLIPS中,我们最需要考虑的是怎么样设计一个程序(也可以称为系统)的规则(Rules),给定了规则以后,你就可以给定一些事实,然后这个系统就可以像一个专家一样判定你这个事实,并给出相应的结论。当然,从本质上说,这也是一种输入和输出。但想深一层,我们世间万物无外乎一种计算和变换。而变换永远是从A变到B,这里的A就是输入,而B正是我们说的输出。不过不论本质,专家系统以及函数式语言确实提供了一种程序员所见到的不同的体系结构。
2.CLIPS中一些需要掌握的知识
事实跟知识的区别
我想这个话题跟现实中是差不多的。事实跟知识的差别也许可以这样说:事实是一种客观的存在,而知识是一种抽象的理性表达。在CLIPS中,我们建立了一系列的规则,这些规则的建立必须是要以知识为基础的。说得更详细点,比如说我们定义的类,模板等,这些我们可以称之为知识,而这些类和模板被实例化后,我们称它们为事实。
CLIPS = 知识库 + 产生式系统推理模型 + 可嵌入
- 知识库由初始事实,初始对象实例和规则库组成。
- 推理模型由黑板(用于存储推理结果数据(黑板数据):包话当前推理结果和历史结果数据),推理机(黑板数据针对知识库的规则进行模板匹配)以及“行动”的执行次序控制,三部分组成。
- 黑板数据包括开始推理以来得到的事实集和对象实例集。
- 行动的执行顺序控制:主要是运用数据驱动原则(RETE网)和RHS行动执行的优先控制规则。
去除循环控制的思想
我想凡是精于C或C++等高级命令式程序语言设计的,都是很善于运用循环控制这个概念的。但是在CLIPS里,这种思想似乎没有用处。因为它编程的思想发生了变化,是一种由初始知识一步步应用规则最终得到结果的过程,这当中可能包含了不确定性。而在命令式语言中,我们知道,给定相同的输入,一般情况下,输出都是相同的。
3.CLIPS编程的一些要求
CLIPS中有个类似SHELL的程序,这就是命令解释器。只要单击CLIPSWIN.EXE就可以进入这个界面,开始输入命令。事实上,所谓的CLIPS程序也就是一堆命令的组合。基于形式上的认识,我们可以称CLIPS是一个解释形系统。
书写格式
我不想讲一大堆书写格式上的东西。这样搞得像写User Guide似的。不过有几个地方还是值得注意一下的。CLIPS中所有的命令,声明,定义以及函数都是要用括号括住的。比如(facts),(assert (exist a))等。另外,CLIPS中讲求括号匹配,如果括号没有完全匹配,则回车符将被视为一种调整命令可读性的方式,命令不会被执行。最后,在写程序时,最好多利用回车符,将程序写得结构清晰,这样自己或别人读程序时都会很快上手。
一些常用的命令
(facts) – 用于显示当前的事实。
(agenda) – 用于显示当前可以执行的规则(并列出满足条件的事实)
(run) – 当规则和事实都有了后,这个命令用来启用程序
(reset) – 重新初始化事实,初始化后,会自动的给系统加上Fact-0号事实,名为
(clear) – 清除所有的规则和事实以及对象实例
(deftemplate) – 定义模板,这个模板类似C语言中的Structure,用(reset)命令可以实例化模板
(deffacts) – 定义事实模板,实例化与(deftemplate)相同
4.四个例子
这四个例子是我自己根据所看的资料,想出来的考验自己的例子。学习一门工具时,我总喜欢给自己出一些题目来解决,我觉得这样学起来会更主动,学到的东西会更多。
法官判案的例子(这是我想的第一个例子,虽然简单,但重在说明问题)
我们只以一条简单的法律规则来列出这个系统(程序)。如果A杀了B,那么A应该被判死刑。
(defrule result
(kill ?A ?B)
=>
(printout t ?A ” kill ” ?B “,” ?A ” should be sentenced to death!”))
那么仅有一条规则,接下来我们给定事实。
CLIPS>(assert (kill bob tom)) //定义事实 bob kill tom
CLIPS>(run)
bob kill tom,bob should be sentenced to death!
简单的文法推理
a->b
b->c
c->d
这个文法事实上没有多大的实际意义,但是考虑到很多的数学模型、演算都是用这种转换的模式写成,所以,它的指
导意义还是蛮大的。
(defrule ex-1
(exist a) //如果有a这个事实
?f0 <- (exist a) //记录a这个事实的index
=>
(assert (exist b)) // 建立b这个事实
(printout t “a->b” crlf)
(retract ?f0)) //删除a
(defrule ex-2
(exist b)
?f1 <- (exist b)
=>
(assert (exist c))
(printout t “b->c” crlf)
(retract ?f1))
(defrule ex-3
(exist c)
?f2 <- (exist c)
=>
(assert (exist d))
(printout t “c->d” crlf)
(retract ?f2))
CLIPS>(assert (exist a))
CLIPS>(run)
a->b
b->c
c->d
CLIPS>(facts)
f-3 (exist d)
For a total of 1 fact.
稍微复杂的文法推理
a->eb
b->cd
这个例子主要说明了复合文法的规则书写方式。
(defrule ex-1
(exist a)
?f0 <- (exist a)
=>
(assert (exist e b))
(printout t “a->eb” crlf)
(retract ?f0))
(defrule ex-2
(exist
?
n
a
m
e
b
)
?
f
1
<
−
(
e
x
i
s
t
?name b)
=>
(assert (exist ?name c d))
(printout t “b->cd” crlf)
(retract ?f1))
动行方式同与上例是一样的。
简单的语言识别器
识别a(n)ba(n) (这里a(n)代表n个a,n是自然数)
事实上,在一些循环跟判断的方法上,至今我仍在摸索。比如上例中如果有a->ab,那么似乎程序会无止境的运行。所以,在命今式里面的一些控制方法,还需要更进一步的学习,这个例子事实上只能给出接受时的判断。当然,在不能接受时,系统不会给出任何提示,取巧的说,不给出提示就相当于不识别语言了。
(defrule ex-1
(exist a
?
n
a
m
e
a
)
?
f
0
<
−
(
e
x
i
s
t
a
?name a)
=>
(assert (exist ?name))
(retract ?f0))
(defrule ex-2
(exist b)
?f1 <- (exist b)
=>
(printout t “succeed!” crlf)
(retract ?f1))
CLIPS》(assert (exist a a a b a a a))
CLIPS>(run)
succeed!
5.一些总结
这篇文章也许可以做为一个初学CLIPS的人的一个guide,其实还有很多我在学习过程中的思想并没有写上去,我想每个人在学习的过程中都会不自觉的思考一些东西。而我总是试图去思考一些知识外面稍微深刻点的东西。其实知识这东西是一把双刃剑。学多了,广博,思维更发散,知识的结构性更强;学深了,术业有专攻,但可能思维日趋定势化。关键是自己要认识到这一点,时常以一种旁观者的姿态去审势,这样,也许才不至于迷失。
学到这里,我想开始着手使用CLIPS模拟一些数学的模型,但问题还是存在的。比如说循环跟判断等。最后,我想能通过CLIPS去模拟一些生物模型,比如P-SYSTEM等。