CLIPS中文手册 下载本文

CLIPS>(+ 2.0 2.0) ; 两个浮点参数的运算结果还是浮点型 4.0

CLIPS>(+ 2 2.0) ; 混合型参数输出浮点型结果 4.0

注意最后一个情形是混合的参数,CLIPS自动将结果转变为双精度浮点型。

你可以显式的转变结果的类型,通过使用float和integer运算符,如下所示:

CLIPS>(float (+ 2 2)) ; 显式转换整型到浮点型 4.0

CLIPS>(integer (+ 2.0 2.0)) ; 显式转换浮点到整型 4

圆括号用来指定表达式的运算顺序。在?x+?y*?z的例子中,通常的计算顺序是先计算?y*?z,然后再与?x相加。然而,在CLIPS中,如果你想按照此顺序计算的话,那么必须显式的使用圆括号,如下:

(defrule mixed-cals

(numbers ?x ?y ?z) =>

(assert (answer (+ ?x (* ?y ?z)))))

在这条规则中,最内一层的圆括号里的运算最先执行,所以先执行?y*?z,然后再与?x相加。

约束变量

由模式匹配在LHS中分配一个值给变量类似于通过绑定函数(bind function)在RHS中绑定(binding)一个值到变量。如果同一个变量被重复的使用到,那么在RHS中绑定其变量值将非常方便。

以一个简单的数学计算为例,让我们首先将答案绑定到一个变量,并随后打印约束变量(bound variable)。

CLIPS>(clear)

CLIPS>(defrule addition

(numbers ?x ?y) =>

(assert (answer (+ ?x ?y))) (bind ?answer (+ ?x ?y))

(printout t “answer is ”?answer crlf)) CLIPS>

(assert (numbers 2 2)) CLIPS>(run) answer is 4 CLIPS>(facts)

f-0 (initial-fact) f-1 (numbers 2 2) f-2 (answer 4)

For a total of 3 facts. CLIPS>

(bind)同样可以被用在RHS中,用来绑定单或多字段值到一个变量。(bind)被用来绑定零个,一个或多个值到一个变量,而不带“$”运算符。调用LHS中的变量,你可以在一个字段中,使用“$”运算符创建多字段模式,如“$?x”。然而,在RHS中,“$”运算符是不需要的,因为(bind)的参数显式的告知了CLIPS它绑定值的个数。事实上,“$”运算符在RHS中只是一个无用的附属物。

下面的例子给出的是在RHS中绑定多个变量。多字段值函数(multifield value function),create$被用来创建一个多字段值。它的基本语法如下所示:

(create$ ?)

这里,任意个数的参数都可以被作为创建多字段值附属在一起。这些多字段值,或单字段值,可以被约束到RHS行为中的一个变量,如下所示:

CLIPS>(clear)

CLIPS>(defrule bind-values-demo =>

(bind ?duck-bachelors (create$ Dopey Dorky Dinky)) (bind ?happy-bachelor-mv (create$ Dopey)) (bind ?none (create$)) (printout t

“duck-bachelors” ?duck-bachelors crlf

“duck-bachelors-no-()” (implode$ ?duck-bachelor) crlf “happy-bachelor-mv ”?happy-bachelor-mv crlf “none” ?none crlf))

CLIPS>(reset) CLIPS>(run)

duck-bachelors (Dopey Dorky Dinky) duck-bachelors-no-() Dopey Dorky Dinky happy-bachelor-mv (Dopey) none () CLIPS>

自定义函数

像其他语言一样,CLIPS允许程序员通过deffunction来定义自己的函数。众所周知,deffuntion可以帮助你节省重复输入相同的行为(actions)。

自定义函数(deffunction)在提高程序的可读性上也是非常有用的,你可以像调用其他函数一样调用自定义函数,自定义函数也可以被用来当作其他函数的参数使用。在自定义函数中,(printout)可以在任何位置使用,甚至不是作为最后一个行为,因为打印的一个副作用是调用了(printout)函数。

自定义函数的通用语法如下所示:

(deffunction [optional comment]

(?arg1 ?arg2 ? ?argM [$?argN]) ; 参数表,最后一个为可选多字段参数 ( ; actionK之前的行为不会返回值,仅最后一个行为返回值 ?

))

其中,?arg为虚拟参数(dummy arguments),代表参数的名字,如果在一条规则中参数名相同,变量不会发生冲突。虚拟变量在其他书本中,通常被称之为参量(parameter)。

尽管每个行为都可以从函数中返回值,这些都被自定义函数返回给用户。自定义函数仅仅返回最后一个行为,该行为可能是个函数,一个变量或一个常量。

下面的例子是一个用来计算三角形斜边的自定义函数,然后被用在规则中。即使规则中作为虚拟参数的变量名都是一样的,也不会有冲突,这是因为它们都是虚拟的,并不指代任何参数。

CLIPS>(clear)

CLIPS>(deffunction hypotenuse ; 函数名

(?a ?b) ; 虚拟参数 (sqrt(+ (* ?a ?a)(* ?b ?b)))) ; 行为 CLIPS>(defrule calculate-hypotenuse

(dimensions ?base ?height) =>

(printout t “Hypotenuse=” (hypotenuse ?base ?height) crlf)) CLIPS>(assert (dimensions 3 4)) CLIPS>(run) Hypotenuse=5.0 CLIPS>

自定义函数也通常被用在多字段值中,如下例子所示:

CLIPS>(clear)

CLIPS>(deffunction count ($?arg)

(length $?arg))

CLIPS>(count 1 2 3 a duck “quacks”) 6

CLIPS>

其他特性

其他一些有用的函数如下所示。更多的信息,请参看CLIPS参考指南。 函数 含义 round 四舍五入 integer 取整 format 格式输出 list-deffunctions 函数列表 ppdeffuntion 打印出函数 undeffunction 删除函数

length 字段的长度,或字符串中字母的个数 nth$ 指定存在的字段,否则为nil

member$ 如果变量存在,则返回字段的成员,否则为FALSE

subsetp 如果一个多字段值是另一多字段值的一部分则返回TRUE,否则返回

FALSE

delete$ 删除给出数字字段内的值

explode$ 将多字段值以每个字符串元素返回

subseq$ 返回字段的指定范围 replace$ 替代指定的值

第七章 程序的控制

当你年轻的时候,你被世界所控制,当你老的时候,你将控制世界。

到目前为止,你已经学历了CLIPS的基本句法。现在,你将学习怎样将所学的句法应用到实际有用的程序当中去。同时,你还将会学到一些关于输入的新的句法,怎样比较变量和产生循环。

读入函数

除了模式匹配外,规则还可以通过其他方式获取信息。CLIPS可以通过使用读入函数(read function)来读入用户输入的键盘信息。

下面是使用(read)命令来输入数据的例子。注意(read)命令在新的一行中插入光标后并不需要多余的(crlf)。(read)自动将光标重置到新的一行中。

CLIPS>(clear)

CLIPS>(defrule read-input =>

(printout t “Name a primary color” crlf) (assert (color (read)))) CLIPS>

(defrule check-input

?color <- (color ?color-read&red|yellow|blue) =>

(retract ?color)

(printout t “Correct” crlf)) CLIPS>(reset) CLIPS>(agenda) 0 read-input:*

For a total of 1 activation. CLIPS>(run)

Name a primary color green

CLIPS> ; 没有打印出“correct”

上面的规则中,在RHS中使用键盘输入,不用指定任意LHS中的模式就可以非常方便的被触发,且当(reset)出现后自动的被激活。当输入(agenda)命令后,读入规则的激活将被显示,打印一个*号,而不是像事实标识符,如f-1。*号的使用用来表示该模式不用指定事实,均可满足。

(read)函数并不是可以读入所有键盘输入的通用函数,它仅能读入一个字段。所以,当你想读入下面的:

primary color is red

那么,只有第一个字段“primary”能被读入。如果你想读入所有的字段,那么必须使用双引号将其包含起来。当然,一旦使用了双引号,那么就会被当作一个单字符串。然后可以通过str-explode或sub-string function访问子字符串,如“primary”,“color”,“is”和“and”。

(read)的第二个限制是不能输入圆括号,除非使用双引号。就像不能声明一个包含圆括号的事实一样,也不能使用(read)直接读入圆括号。