第一篇:逻辑型程序设计语言PROLOG详细教程
逻辑型程序设计语言PROLOG教程
2.3.1逻辑型程序设计语言PROLOG PROLOG的语句
PROLOG语言只有三种语句,分别称为事实、规则和问题。
1.事实(fact)
格式: <谓词名>(<项表>).功能
一般表示对象的性质或关系。
其中谓词名是以小写英文字母打头的字母、数字、下划线等组成的字符串,项表是以逗号隔开的项序列。
例如:
student(john).like(mary ,music).表示“约翰是学生”和“玛丽喜欢音乐”。2.规则(rule)
格式:
<谓词名>(<项表>):-<谓词名>(<项表>){,<谓词名>(<项表>)}.功能: 一般表示对象间的因果关系、蕴含关系或对应关系。
其中“:-”号表示“if”(也可以直接写为if),其左部的谓词是规则的结论(亦称为头),右部的谓词是规则的前提(亦称为体),{}表示零次或多次重复,逗号表示and(逻辑与),即规则的形式是一个逻辑蕴含式。
例如:
bird(X):-animal(X),has(X,feather).grandfather(X,Y):-father(X,Z),father(Z,Y).第一条规则表示“如果X是动物,并且X有羽毛,则X是鸟”;第二条规则就表示“X是Y的祖父,如果存在Z,X是Z的父亲并且Z又是Y的父亲”。
3.问题(question)
格式: ?-<谓词名>(<项表>){,<谓词名>(<项表>)}.功能 表示用户的询问,它就是程序运行的目标。
例如:
?-student(john).?-like(mary,X).2.3.2 PROLOG程序
PROLOG程序一般由一组事实、规则和问题组成。问题是程序执行的起点,称为程序的目标。
例如下面就是一个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).可以看出,这个程序中有四条事实、两条规则和一个问题。其中事实、规则和问题都分行书写。规则和事实可连续排列在一起,其顺序可随意安排,但同一谓词名的事实或规则必须集中排列在一起。问题不能与规则及事实排在一起,它作为程序的目标要么单独列出,要么在程序运行时临时给出。
这个程序的事实描述了一些对象(包括人和事物)间的关系;而规则则描述了john交朋友的条件,即如果一个人喜欢读书并且喜欢音乐(或者喜欢运动和喜欢音乐),则这个人就是john的朋友(当然,这个规则也可看作是john朋友的定义);程序中的问题是“约翰的朋友是谁?”
当然,PROLOG程序中的目标可以变化,也可以含有多个语句(上例中只有一个)。如果有多个语句,则这些语句称为子目标。例如对上面的程序,其问题也可以是 ?-likes(mary,X).或
?-likes(mary,music).或
?-friend(X,Y).或
?-likes(bell,sports), likes(mary,music), friend(john,X).等等。当然,对于不同的问题,程序运行的结果一般是不一样的。
2.3.3 PROLOG程序的运行机理
PROLOG程序的运行是从目标出发,并不断进行匹配、合一、归结,有时还要回溯,直到目标被完全满足或不能满足时为止。1.自由变量与约束变量
PROLOG中称无值的变量为自由变量,有值的变量为约束变量。一个变量取了某值就说该变量约束于某值,或者说该变量被某值所约束,或者说该变量被某值实例化了。
2.匹配合一
两个谓词可匹配合一,是指两个谓词的名相同,参量项的个数相同,参量类型对应相同,并且对应参量项还满足下列条件之一:
(1)如果两个都是常量,则必须完全相同。
(2)如果两个都是约束变量,则两个约束值必须相同。
(3)如果其中一个是常量,一个是约束变量,则约束值与常量必须相同。
(4)至少有一个是自由变量。例如:下面的两个谓词
pre1(“ob1”,“ob2”,Z)
pre1(“ob1”,X,Y)
只有当变量X被约束为“ob2”,且Y、Z的约束值相同或者至少有一个是自由变量时,它们才是匹配合一的。
3.回溯
所谓回溯,就是在程序运行期间,当某一个子目标不能满足(即谓词匹配失败)时,控制就返回到前一个已经满足的子目标(如果存在的话),并撤消其有关变量的约束值,然后再使其重新满足。成功后,再继续满足原子目标。如果失败的子目标前再无子目标,则控制就返回到该子目标的上一级目标(即该子目标谓词所在规则的头部)使它重新匹配。回溯也是PROLOG的一个重要机制。
下面,我们介绍PROLOG程序的运行过程。我们仍以上面的程序为例。设所给的询问是
?-friend(john,Y).(john和谁是朋友?)
则求解目标为
friend(john,Y).这时,系统对程序进行扫描,寻找能与目标谓词匹配合一的事实或规则头部。显然,程序中前面的四条事实均不能与目标匹配,而第五个语句的左端即规则
friend(john,X):-likes(X,reading),likes(X,music).的头部可与目标谓词匹配合一。但由于这个语句又是一个规则,所以其结论要成立则必须其前提全部成立。于是,对原目标的求解就转化为对新目标
likes(X,reading),likes(X,music).的求解。这实际是经归结,规则头部被消去,而目标子句变为
?-likes(X,reading),likes(X,music).现在依次对子目标
likes(X,reading)和likes(X,music)
求解。
子目标的求解过程与主目标完全一样,也是从头对程序进行扫描,不断进行测试和匹配合一等,直到匹配成功或扫描完整个程序为止。可以看出,对第一个子目标like(X,reading)的求解因无可匹配的事实和规则而立即失败,进而导致规则
friend(john,X):-likes(X,reading),likes(X,music).的整体失败。于是,刚才的子目标
likes(X,reading)和likes(X,music)
被撤消,系统又回溯到原目标friend(john,X)。这时,系统从该目标刚才的匹配语句处(即第五句)向下继续扫描程序中的子句,试图重新使原目标匹配,结果发现第六条语句的左部,即规则
friend(john,X):-likes(X,sports),likes(X,music).的头部可与目标为谓词匹配。但由于这个语句又是一个规则,于是,这时对原目标的求解,就又转化为依次对子目标
likes(X,sports)和likes(X,music) 的求解。这次子目标likes(X,sports)与程序中的事实立即匹配成功,且变量X被约束为bell。于是,系统便接着求解第二个子目标。由于变量X已被约束,所以这时第二个子目标实际上已变成了
likes(bell,music).由于程序中不存在事实likes(bell,music),所以该目标的求解失败。于是,系统就放弃这个子目标,并使变量X恢复为自由变量,然后回溯到第一个子目标,重新对它进行求解。由于系统已经记住了刚才已同第一子目标谓词匹配过的事实的位置,所以重新求解时,便从下一个事实开始测试。
易见,当测试到程序中第三个事实时,第一个子目标便求解成功,且变量X被约束为mary。这样,第二个子目标也就变成了
likes(mary,music).再对它进行求解。这次很快成功。
由于两个子目标都求解成功,所以,原目标friend(john,Y)也成功,且变量Y被约束为mary(由Y与X的合一关系)。于是,系统回答:
Y=mary
程序运行结束。
上面只给出了问题的一个解。如果需要和可能的话,系统还可把john的所有朋友都找出来。我们把上述程序的运行过程再用示意图(图2─1)描述如下:
图2─1
PROLOG程序运行机理示例
上述程序的运行是一个通过推理实现的求值过程。我们也可以使它变为证明过程。例如,把上述程序中的询问改为
friend(john,mary)
则系统会回答:yes
若将询问改为:
riend(john,smith)
则系统会回答:no
从上述程序的运行过程可以看出,PROLOG程序的执行过程是一个(归结)演绎推理过程。其特点是:推理方式为反向推理,控制策略是深度优先,且有回溯机制。其具体实现方法是:匹配子句的顺序是自上而下;子目标选择顺序是从左向右;(归结后)产生的新子目标总是插入被消去的目标处(即目标队列的左部)。PROLOG的这种归结演绎方法被称为SLD(LinearresolutionwithSelectionfunctionforDefiniteclause)归结,或SLD反驳-消解法。SLD归结就是PROLOG程序的运行机理,它也就是所谓的PROLOG语言的过程性语义。2.4
Turbo PROLOG程序设计 2.4.1 Turbo PROLOG的程序结构
一个完整的Turbo PROLOG(2.0版)程序一般包括常量段、领域段、数据库段、谓词段、目标段和子句段等六个部分。各段以其相应的关键字constants、domains、database、predicates、goal和clauses开头加以标识。:
另外,在程序的首部还可以设置指示编译程序执行特定任务的编译指令;在程序的任何位置都可设置注解。总之,一个完整的TurboPROLOG(2.0版)程序的结构如下
/*<注释>*/
<编译指令>
constants
<常量说明>
domains
<域说明>
database
<数据库说明>
predicates
<谓词说明>
goal
<目标语句>
clauses
<子句集>
当然,一个程序不一定要包括上述所有段,但一个程序至少要有一个predicates段、clauses段和goal段。在大多数情形中,还需要一个domains段,以说明表、复合结构及用户自定义的域名。如若省略goal段,则可在程序运行时临时给出,但这仅当在开发环境中运行程序时方可给出。若要生成一个独立的可执行文件,则在程序中必须包含goal段。另一方面,一个程序也只能有一个goal段。
例2.3 如果把上节中的程序要作为TurboPROLOG程序,则应改写为:
/*例子程序-1*/
DOMAINS
name=symbol
PREDICATES
likes(name,name).friend(name,name)
GOAL
friend(john,Y),write(″Y=″,Y).CLAUSES likes(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).结合上例,我们再对上述程序结构中的几个主要段的内容和作用加以说明(其余段在后面用到时再作说明):
领域段该段说明程序谓词中所有参量项所属的领域。领域的说明可能会出现多层说明,直到最终说明到Turbo PROLOG的标准领域为止(如上例所示)。Turbo PROLOG的标准领域即标准数据类型,包括整数、实数、符号、串和符号等,其具体说明如表2.1所示。
表2.1 Turbo PROLOG的标准领域
谓词段:该段说明程序中用到的谓词的名和参量项的名(但Turbo PROLOG的内部谓词无须说明)。
子句段:该段是Turbo PROLOG程序的核心,程序中的所有事实和规则就放在这里,系统在试图满足程序的目标时就对它们进行操作。
目标段:该段是放置程序目标的地方。目标段可以只有一个目标谓词,例如上面的例子中就只有一个目标谓词;也可以含有多个目标谓词,如:
goal
readint(X),Y=X+3,write(“Y=”,Y).就有三个目标谓词。这种目标称为复合目标。
另外,一般称程序目标段中的目标为内部目标,而称在程序运行时临时给出的目标为外部目标。
2.4.2 Turbo PROLOG的数据与表达式 1.领域
1)标准领域
Turbo PROLOG中不定义变量的类型,只说明谓词中各个项的取值域。2)结构
结构也称复合对象,它是TurboPROLOG谓词中的一种特殊的参量项(类似于谓词逻辑中的函数)。
结构的一般形式为
<函子>(<参量表>)
其中函子及参量的标识符与谓词相同。注意,这意味着结构中还可包含结构。所以,复合对象可表达树形数据结构。例如下面的谓词
likes(Tom,sports(football,basketball,table-tennis)).中的
sports(football,basketball,table-tennis)
就是一个结构,即复合对象。
又如:
person(“张华”,student(“西安石油学院”),address(“中国”,“陕西”,“西安”)).reading(“王宏”,book(“人工智能技术基础教程”,“西安电子科技大学出版社”)).friend(father(“Li”),father(“Zhao”)).这几个谓词中都有复合对象。复合对象在程序中的说明,需分层进行。例如,对于上面的谓词
likes(Tom,sports(football,basketball,table-tennis)).在程序中可说明如下:
domains
name=symbol
sy=symbol
sp=sports(sy,sy,sy)
predicates
likes(name,sp)3)表
表的一般形式是
[x1,x2,…,xn]
其中xi(i=1,2,…,n)为PROLOG的项,一般要求同一个表的元素必须属于同一领域。
不含任何元素的表称为空表,记为[]。例如下面就是一些合法的表。
[1,2,3]
[apple,orange,banana,grape,cane]
[“PROLOG”,“MAENS”,“PROGRAMMING”,“in logic”] [[a,b],[c,d],[e]] []
表的最大特点是其元素个数可在程序运行期间动态变化。表的元素也可以是结构或表,且这时其元素可以属于不同领域。
例如:
name(“Li Ming”),age(20),sex(male),address(xi an)] [[1,2],[3,4,5],[6,7]]
都是合法的表。后一个例子说明,表也可以嵌套。
实际上,表是一种特殊的结构。它是递归结构的另一种表达形式。这个结构的函数名取决于具体的PROLOG版本。这里我们就用一个圆点来表示。
下面就是一些这样的结构及它们的表表示形式:
结构形式
表形式 ·(a,[])
[a] ·(a,·(b,[]))
[a,b] ·(a,·(b,·(c,[])))
[a,b,c]
表的说明方法是在其组成元素的说明符后加一个星号*。如:
domains
lists=string*
predicates
pl(lists)
就说明谓词pl中的项lists是一个由串string组成的表。
对于由结构组成的表,至少得分三步说明。例如对于下面谓词p中的表
p([name(“Liming”),age(20)])
则需这样说明:
domains
rec=seg*
seg=name(string);age(integer)
predicates
p(rec)2.常量与变量
由上面的领域可知,Turbo PROLOG的常量有整数、实数、字符、串、符号、结构、表和文件这八种数据类型。同理,Turbo PROLOG的变量也就有这八种取值。另外,变量名要求必须是以大写字母或下划线开头的字母、数字和下划线序列,或者只有一个下划线。这后一种变量称为无名变量。3.算术表达式
Turbo PROLOG提供了五种最基本的算术运算:加、减、乘、除和取模,相应运算符号为+、-、*、/、mod。这五种运算的顺序为:*、/、mod优先于+、-。同级从左到右按顺序运算,括号优先。算术表达式的形式与数学中的形式基本一样。例如:
数学中的算术表达式
PROLOG中的算术表达式
x+yz
X+Y*Z
ab-c/d
A*B-C/D
u mod v
U mod V(表示求U除以V所得的余数)即是说,Turbo PROLOG中算术表达式采用通常数学中使用的中缀形式。这种算术表达式为PROLOG的一种异体结构,若以PROLOG的结构形式来表示,则它们应为
+(X,*(Y,Z))
-(*(A,B),/(C,D))
mod(U,V)
所以,运算符+、-、*、/和mod实际也就是PROLOG内部定义好了的函数符。
在Turbo PROLOG程序中,如果一个算术表达式中的变元全部被实例化(即被约束)的话,则这个算术表达式的值就会被求出。求出的值可用来实例化某变量,也可用来同其他数量进行比较,用一个算术表达式的值实例化一个变量的方法是用谓词“is”或“=”来实现。例如:
Y is X+5 或 Y=X+5
(*)
就使变量Y实例化为X+5的值(当然X也必须经已被某值实例化),可以看出,这里对变量Y的实例化方法类似于其他高级程序语言中的“赋值”,但又不同于赋值。例如,在PROLOG中下面的式子是错误的:
X=X+1 4.关系表达式
Turbo PROLOG提供了六种常用的关系运算,即小于、小于或等于、等于、大于、大于或等于和不等于,其运算符依次为
<,<=,=,>,>=,<>
Turbo PROLOG的关系表达式的形式和数学中的也基本一样,例如:
数学中的关系式
Turbo PROLOG中的关系式
X+1≥Y
X+1>=Y
X≠Y
X<>Y 即是说,Turbo PROLOG中的关系式也用中缀形式。当然,这种关系式为Turbo PROLOG中的异体原子。若按Turbo PROLOG中的原子形式来表示,则上面的两个例子为
>=(X+1,Y)和<>(X,Y)
所以上述六种关系运算符,实际上也就是Turbo PROLOG内部定义好了的六个谓词。这六个关系运算符可用来比较两个算术表达式的大小。
例如:
brother(Name1,Name2):-person(Name1,man,Age1),person(Name2,man,Age2),mother(Z,Name1),mother(Z,Name2),Age1>Age2.需要说明的是,“=”的用法比较特殊,它既可以表示比较,也可以表示约束值,即使在同一个规则中的同一个“=”也是如此。
例如:
(例一)
p(X,Y,Z):-Z=X+Y.当变量X、Y、Z全部被实例化时,“=”就是比较符。如:对于问题
Goal:p(3,5,8).机器回答:yes。而对于
Goal:p(3,5,7).机器回答:no。
即这时机器把X+Y的值,与Z的值进行比较。
(例二)但当X,Y被实例化,为Z未被实例化时,“=”号就是约束符。如:
Goal:p(3,5,Z).机器回答:Z=8 这时,机器使Z实例化为X+Y的结果。2.4.3 输入与输出
虽然PROLOG能自动输出目标子句中的变量的值,但这种输出功能必定有限,往往不能满足实际需要;另一方面,对通常大多数的程序来说,运行时从键盘上输入有关数据或信息也是必不可少的。为此每种具体PROLOG一般都提供专门的输入和输出谓词,供用户直接调用。例如,下面就是TorboPROLOG的几种输入输出谓词:
(1)readln(X)。
这个谓词的功能是从键盘上读取一个字符串,然后约束给变量X。
(2)readint(X)。
这个谓词的功能是从键盘上读取一个整数,然后约束给变量X,如果键盘上打入的不是整数则该谓词失败。
(3)readreal(X)。
这个谓词的功能是从键盘上读取一个实数,然后约束给变量X,如果键盘上打入的不是实数则该谓词失败。
(4)readchar(X)。
这个谓词的功能是从键盘上读取一个字符,然后约束给变量X,如果键盘上打入的不是单个字符,则该谓词失败。
(5)write(X1,X2,… Xn)。
这个谓词的功能是把项Xi(i=1,2,…n)的值显示在屏幕上或者打印在纸上,当有某个Xi未实例化时,该谓词失败,其中的Xi可以是变量,也可以是字符串或数字。
(6)nl换行谓词。它使后面的输出(如果有的话)另起一行。另外,利用write的输出项“n”也同样可起换行作用。例如:
write(“name”), n l ,write(“age”)
与write(“name”,“n”,“age”)的效果完全一样。例2.4用上面的输入输出谓词编写一个简单的学生成绩数据库查询程序。
PREDICATES student(integer,string,real)grade GOAL grade.CLAUSES student(1,“张三”,90.2).student(2,“李四”,95.5).student(3,“王五”,96.4).grade:-write(“请输入姓名:”),readln(Name), student(-,Name,Score), nl,write(Name,“的成绩是”,Score).grade:-write(“对不起,找不到这个学生!”).grade:-write(“对不起,找不到这个学生!”).下面是程序运行时的屏幕显示: 请输入姓名: 王五
王五的成绩是96.4。
2.4.4 分支与循环
PROLOG中并无专门的分支和循环语句,但PROLOG也可实现分支和循环程序结构。1.分支
对于通常的IF-THEN-ELSE分支结构,PROLOG可用两条同头的并列规则实现。例如,将
IF x>0THENx:=1
ELSE x:=0 用PROLOG实现则是 Br :-x>0,x=1.Br :-x=0.类似地,对于多分支,可以用多条规则实现。例如: Br :-x>0,x=1.Br :-x=0,x=0.Br :-x<0,x=-1.2.循环
PROLOG可以实现计循环次数的FOR循环,也可以实现不计循环次数的DO循环。例如下面的程序段就实现了循环,它使得write语句重复执行了三次,而打印输出了三个学生的记录。
student(1,“张三”,90.2).student(2,“李四”,95.5).student(3,“王五”,96.4).print:-student(Number,Name,Score),write(Number,Name,Score),n l ,Number=3.这个例子可以看作是计数循环。当然,也可以通过设置计数器而实现真正的计数循环。下面的程序段实现的则是不计数的DO循环。
student(1,“张三”,90.2).student(2,“李四”,95.5).student(3,“王五”,96.4).print:-student(Number,Name,Score),write(Number,Name,Score),nl,fail.print:-.这个程序段中的fail是一个内部谓词,它的语义是恒失败。这个程序段与上面的程序段的差别仅在于把原来用计数器(或标记数)循环控制语句变成了恒失败谓词fail,另外再增加了一个print语句。增加这个语句的目的是为程序设置一个出口。因为fail是恒失败,下面若无出口的话,将引起print本身的失败。进而又会导致程序中的连锁失败。
2.4.5 动态数据库
动态数据库就是在内存中实现的动态数据结构。它由事实组成,程序可以对它操作,所以在程序运行期间它可以动态变化。Turbo PROLOG提供了三个动态数据库操作谓词: asserta(
asserta(
assertz(
retract(
例如语句
asserta(student(20,“李明”,90.5)).将在内存的谓词名为student的事实前插入一个新事实:
student(20,“李明”,90.5)
如果内存中还没有这样的事实,则它就是第一个。又如语句
retract(student(20,-,-)).将从内存的动态数据库中的删除事实
student(20,-,-)它可解释为学号为20的一个学生的记录。注意,这里用了无名变量-。
可以看出,PROLOG提供的动态数据库机制,可非常方便地实现堆栈、队列等动态数据结构,提供的数据库操作谓词大大简化了编程。
另外,PROLOG还提供了谓词
save(
2.4.6 表处理与递归
表是PROLOG中一种非常有用的数据结构。表的表述能力很强,数字中的序列、集合,通常语言中的数组、记录等均可用表来表示。表的最大特点是其长度不固定,在程序的运行过程中可动态地变化。具体来讲,就是在程序运行时,可对表施行一些操作,如给表中添加一个元素,或从中删除一个元素,或者将两个表合并为一个表等等。用表还可以方便地构造堆栈、队列、链表、树等动态数据结构。
表还有一个重要特点,就是它可分为头和尾两部分。表头是表中第一个元素,而表尾是表中除第一个元素外的其余元素按原来顺序组成的表。例如下面的例子:
表
表头
表尾
[1,2,3,4,5]
[2,3,4,5]
[apple,orange,banana]
apple
[orange,banana]
[[a,b],[c],[d,e]]
[a,b]
[[c],[d,e]]
[“PROLOG”]
“PROLOG“
[]
[]
无定义
无定义
在程序中是用竖线“|”来区分表头和表尾的,而且还可以使用变量。例如一般地用[H|T]来表示一个表,其中H、T都是变量,H为表头,T为表尾。注意,此处H是一个元素(表中第一个元素),而T则是一个表(除第一个元素外的表中其余元素按原来顺序组成的表)。表的这种表示法很有用,它为表的操作提供了极大的方便。下面我们就给出用这种表示法通过匹配合一提取表头和表尾的例子。
表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]]
还需说明的是,表中的竖杠“|”后面只能有一个变量。例如写法[X|Y,Z]就是错误的。但竖杠的前面的变量可以多于一个。例如写法[X,Y|Z]是允许的。这样,这个表同[a,b,c]匹配合一后,有
X=a,Y=b,Z=[c]
另外,竖杠的前面和后面也可以是常量,例如[a|Y]和[X|b]都是允许的,但注意,后一个表称为无尾表,如果它同表[a|Y]匹配,则有
X=a,Y=b
(而不是Y=[b])
如果无竖杠“|”,则不能分离出表尾。例如,表[X,Y,Z]与[a,b,c]合一后得X=a,Y=b,Z=c。其中变量Z并非等于[c]。
例2.5 设计一个能判断对象X是表L的成员的程序。
我们可以这样设想:
(1)如果X与表L中的第一个元素(即表头)是同一个对象,则X就是L的成员;
(2)如果X是L的尾部的成员,则X也就是L的成员。
根据这种逻辑关系,于是有下面的PROLOG程序:
member(X,[X|Tail]).member(X,[Head|Tail]):-member(X,Tail).
其中第一个子句的语义就是上面的第一句话,第二个子句的语义就是上面的第二句话。可以看出,这个程序中使用了递归技术,因为谓词member的定义中又含有它自身。利用这个程序我们就可以判定任意给定的一个对象和一个表之间是否具有member(成员)关系。
例如,我们取表L为[a,b,c,d],取X为a,对上面的程序提出如下询问:
Goal:member(a,[a,b,c,d]).
则有回答:yes
同样对于询问:
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,它是该表的成员,这时系统返回X的值,即
X=a
如果需要的话,系统还会给出X的其他所有值。
例2.6 表的拼接程序,即把两个表连接成一个表。
append([],L,L).append([H|T],L2,[H|Tn]):-append(T,L2,Tn).
程序中第一个子句的意思是空表同任一表L拼接的结果仍为表L;第二个子句的意思是说,一个非空的表L1与另一个表L2拼接的结果L3是这样一个表,它的头是L1的头,它的尾是由L1的尾T同L2拼接的结果Tn。这个程序刻划了两个表与它们的拼接表之间的逻辑关系。
可以看出,谓词append是递归定义的,子句append([],L,L).为终结条件,即递归出口。
对于这个程序,如果我们询问
Goal:append([1,2,3],[4,5],L).
则系统便三次递归调用程序中的第二个子句,最后从第一个子句终止,然后反向依次求出每次的拼接表,最后输出
L=[1,2,3,4,5]
当然,对于这个程序也可以给出其他各种询问,如: Goal:append([1,2,3],[4,5],[1,2,3,4,5]). 系统回答:yes Goal:append([1,2,3],[4,5],[1,2,3,4,5,6]). 系统回答:no Goal:append([1,2,3],Y,[1,2,3,4,5]). 系统回答:Y=[4,5]
Goal:append(X,[4,5],[1,2,3,4,5]).
系统回答:X=[1,2,3]
Goal:append(X,Y,[1,2,3,4,5]). 系统回答: 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 表的倒置,即求一个表的逆序表。
reverse([],[]).reverse([H|T],L):-reverse(T,L1),append(L1,[H],L).
这里,reverse的第一个项是输入,即原表,第二个项是输出,即原表的倒置。2.4.7 回溯控制
PROLOG在搜索目标解的过程中,具有回溯机制,即当某一个子目标Gi不能满足时,就返回到该子目标的前一个子目标Gi-1,并放弃Gi-1的当前约束值,使它重新匹配合一。在实际问题中,有时却不需要回溯,为此PROLOG中就专门定义了一个阻止回溯的内部谓词——“!”,称为截断谓词。
截断谓词的语法格式很简单,就是一个感叹号“!”。!的语义是:
(1)若将“!”插在子句体内作为一个子目标,它总是立即成功;
(2)若“!”位于子句体的最后,则它就阻止对它所在子句的头谓词的所有子句的回溯访问,而让回溯跳过该头谓词(子目标),去访问前一个子目标(如果有的话);
(3)若“!”位于其他位置,则当其后发生回溯且回溯到“!”处时,就在此处失败,并且“!”还使它所在子句的头谓词(子目标)整个失败(即阻止再去访问头谓词的其余子句(如果有的话),即迫使系统直接回溯到该头谓词(子目标)的前一个子目标(如果有的话))。
例2.9考虑下面的程序:
p(a).(2─1)
p(b).(2─2)
q(b).(2─3)
r(X):-p(X),q(X).(2─4)
r(c).
对于目标:r(Y).
可有一个解
Y=b
但当我们把式(2─4)改为
r(X):-p(X),!,q(X).(2─4′)
时,却无解。
这是由于添加了截断谓词“!”。因为式(2─4′)中求解子目标p(X)时,X被约束到a,然后跳过“!”,但在求解子目标q(a)时遇到麻烦,于是又回溯到“!”,而“!”阻止了对p(X)的下一个子句p(b)和r的下一个定义子句r(c)的访问。从而,导致整个求解失败。
例2.10 设有程序:
g0:-g11,g12,g13.(2─5)g0:-g14.(2─6)g12:-g21,!,g23.(2─7)g12:-g24,g25.(2─8).........
给出目标:g0.假设运行到子目标g23时失败,这时如果子句(2─7)中无!的话,则会回溯到g21,并且,如果g21也失败的话,则会访问下面的子句(2─8)。但由于有!存在,所以不能回溯到g21,而直接宣告g12失败。于是,由子句(2─5),这时则回溯到g11。如果我们把子句(2─7)改为
g12:-g21, g23,!.(2─9)当然这时若g23失败时,便可回溯到g21,而当g21也失败时,便回溯到g12,即子句(2─8)被“激活”。但对于修改后的程序,如果g13失败,则虽然可回溯到g12,但对g12不做任何事情,便立即跳过它,而回溯到g11,如果子句(2─9)中无!,则当g13失败时,回溯到g12便去考虑子句(2─8),只有当子句(2─8)再失败时才回溯到g11。2.4.8 程序举例
下面我们给出几个简单而又典型的例子程序。通过这些程序,读者可以进一步体会和理解PROLOG程序的风格和能力,也可以掌握一些基本的编程技巧。
例2.11 下面是一个简单的路径查询程序。程序中的事实描述了如图2─2所示的有向图,规则是图中两节点间有通路的定义。
图2─2
有向图
predicates
road(symbol,symbol)
path(symbol,symbol)clauses
road(a,b).road(a,c).road(b,d).road(c,d).road(d,e).road(b,e).path(X,Y):-road(X,Y).path(X,Y):-road(X,Z),path(Z,Y).程序中未含目标,所以运行时需给出外部目标。例如当给目标:
path(a,e).
系统将回答:yes
但当给目标:
path(e,a).
时,系统则回答:no
如果给出目标:
run. 且在程序中增加子句
run:-path(a,X),write(”X=“,X),nl,fail.run. 屏幕上将会输出:
X=b
X=c
X=d
X=e
X=d
X=e
X=e
即从a出发到其他节点的全部路径。
例2.12 下面是一个求阶乘程序,程序中使用了递归。
/*aFactorialProgram*/
domains
n,f=integer
predicates
factorial(n,f)
goal
readint(I),factorial(I,F),write(I,”!=“,F).clauses
factorial(1,1).factorial(N,Res):-
N>0,N1=N-1,factorial(N1,FacN1),Res=N*FacN1.程序运行时,从键盘输入一个整数,屏幕上将显示其阶乘数。
例2.13 下面是一个表的排序程序,采用插入排序法。
/*insertsort*/
domains
listi=integer*
predicates
insert-sort(listi , listi)
insert(integer,listi,listi)
asc-order(integer,integer)
clauses
insert-sort([],[]).insert-sort([H|Tail],Sorted-list):-insert-sort(Tail,Sorted-Tail),insert(H,Sorted-Tail,Sorted-list).insert(X,[Y|Sorted-list],[Y|Sorted-list1]):-asc-order(X,Y),!,insert(X,Sorted-list,Sorted-list1).insert(X,Sorted-list,[X|Sorted-list]).asc-order(X,Y):-X>Y.程序中对表处理使用了递归。程序中也未给出目标,需要在运行时临时给出。例如当给目标:
insert-sort([5,3,4,2,6,1,7,8,9,0],L).系统将输出:
L=[0,1,2,3,4,5,6,7,8,9]
例2.14下面是一个简单的通信录管理程序,其中用到输入输出、动态数据库等。通过阅读这个程序,我们还可以掌握循环结构和简单的菜单程序编写方法。
/*通信录*/
database
person(string,integer)
predicates
address-book
chose(integer)
input query
repeat goal
address-book.clauses
address-book:-repeat,clearwindow,write(”==============“),nl,write(”1--录入“),nl, write(”2--查询“),nl, write(”3--退出“),nl,write(”==============“),nl, write(”请选择:-“), readint(N), chose(N).chose(1):-input,fail.chose(2):-query,fail.chose(3):-clearwindow,!.input:-clearwindow,write(”姓名:“),readln(Name),write(”电话:“),readint(Tel),assertz(person(Name,Tel)),!.query:-clearwindow,write(”姓名:“),readln(Name),person(Name,Tel),write(”电话:“,Tel),readchar(-),!.repeat.repeat:-repeat.程序中的repeat恒成功。它与内部谓词fail配合实现了循环。
需说明的是,这仅是一个演示性程序,还不能实用。因为这里的通信录并未存入磁盘文件。用谓词save就可方便地把通信录存入磁盘文件。例如用语句
save(”addrbook.dat“)
就可把已插入内存的person事实存入文件addrbook.dat中。而语句
consult(”addrbook.dat“)
则可又将该文件中的事实装入内存。
2.4 函数型程序设计语言LISP
LISP语言的主要特点是:
(1)LISP程序由一组函数组成,程序的执行过程是函数的调用过程。
(2)程序和数据在形式上是相同的,即都是符号表达式,简称为S─表达式。
(3)递归是LISP语言的主要控制结构。
(4)程序以交互方式运行。
2.2.1 LISP的程序结构与运行机制
LISP的程序一般由函数的定义和函数的调用两部分组成。其一般格式为:
(DEFUN(<函数名>(<形参表>)<函数体>)
(<函数名>(〖WB〗<形参表>)<函数体>)
…
(<函数名>(<形参表>)<函数体>))
(<函数名><实参表>)
(<函数名><实参表>)
…
(<函数名><实参表>)
其中的“DEFUN”是定义函数的关键字,“函数名”可以是系统的内部函数(名),也可以是用户用DEFUN定义的函数(名)。例如下面就是一个LISP程序。
(DEFUNHANOI(a b c n)
(COND((=n1)(MOVE-DISK a c))
(T(HANOI a c b(-n1))
(MOVE-DISK a c)
(HANOI b a c(-n1))))(DEFUNMOVE-DISK(from to)(TERPRI)(PRINC″Move Disk From″)(PRINC from)(PRINC”To“)(PRINC to))
(HANOI′a′b′c3)2.2.2 S─表达式
从语法上看,LISP程序的基本单位是S─表达式。S─表达式又可分为原子和表两大类。原子(atom)是由字母和数字组成的字符串,是S─表达式的最简单情况。原子又可分为文字原子、串原子和数字原子三种。
文字原子又称符号(symbol),是以字母开头的字母数字串,用来表示常量、变量和函数的名字等。例如:ABC、X1等。
串原子是由双引号括起来的一串字符。如”LISP Program"。
数字原子由数字串组成。在其前面可以有符号“-”或“+”,中间可出现“.”,用来表示整数和实数。例如:256、-66、3.14159等。
S─表达式可以递归定义如下:
(1)原子是S─表达式。
(2)若S1和S2是S─表达式,则(S1·S2)也是S─表达式。由定义,下面的式子都是S─表达式:
X2
123
(A·B)
(A·(B·C))
表(list)是LISP语言中最常用的数据类型,也是主要的处理对象。表是由圆括号括起来的由空格分开的若干个元素的集合。
表的一般形式为:
(…)
例如:
(X Y Z),(+12),(A(B C))
左括号后面的第一个元素称为表头,其余的元素组成的表称为表尾。例如,对于表
(+12)的头为+,尾为(12)。
特别地,元素个数为零的表为空表,记为()或NIL。
表是一种特殊的S─表达式,每一个表都对应着一个S─表达式。二者的关系由下面的例子说明。
表←——————————————→S-表达式
(A)
(A·NIL)
(AB)
(A·(B·NIL))
(ABC)
(A·(B·(C·NIL)))
((AB)CD)
((A·(B·NIL))·(C·(D·NIL)))
可以看出,表的S─表达式的结构实际是一棵二叉树。
2.2.3 基本函数
LISP的函数都以表的形式出现,并一律使用前缀表示方式,即表头为函数名,并且每个函数都有一个返回值。LISP的函数可分为语言自身提供的内部函数(称为基本函数或系统函数)和用户自定义函数两类。基本函数的种类有十多个,下面仅给出其中主要的几类。
1.表处理函数
表处理是LISP的主要特色,表处理的函数也很多,下面仅给出最常用的几个。1)CAR函数
格式(CAR<表>)
其中CAR为函数名,它是一个保留字(下同)。功能取出表中的表头。
例如:(CAR′(LISP Language Program))返回值为:LISP 2)CDR函数
格式(CDR<表>)
功能取出表中的表尾。
例如:(CDR′(LISP Language Program))
返回值为:(Language Program)
3)CONS函数
格式(CONS<表>)
功能将S─表达式作为一个元素加到表中去,并作为所构成新表中的第一个元素。
例如:(CONS′My′(LISP Language Program))
返回值为:(My LISP Language Program)4)APPEND函数
格式(APPEND<表1><表2>…<表n>)功能
将n个表中的元素合并成一个新表。例如:(APPEND′(TIGER LION)′(DOG CAT))返回值为:(TIGER LION DOG CAT)5)LIST函数
格式(LIST…)功能把n个S─表达式作为元素括在一起构成一张新表。例如:(LIST′YELLOW′RED′BLUE)返回值为:(YELLOW RED BLUE)
2.算术函数
LISP的算术表达式也是用函数表示的,称为算术函数。下面我们仅举例说明。
(+25)
表示2+5,返回值为7。
(-(*48)(/105))表示4×8-10/5,返回值为30。3.求值与赋值函数
在上面的函数中多次出现撇号′,它的意思是禁止求值。为什么要禁止求值呢?原来,LISP总是试图对一切S─表达式求值。表的值是通过函数运算而得到的,原子的值则是通过赋值函数实现的。撇号′也是一个函数,它实际是禁止求值函数QUOTE的简写形式。
赋值函数有多个,其中SET函数是一个最基本的赋值函数。
格式(SET<变量>)
功能把S─表达式赋给变量。
例如:
(SET′X′8);
X 得到值8
(SET′Y′(a b c));
Y 得到值(a b c)
(SET′Z(CDRY);
Z 得到值(b c)
另外,赋值函数还有SETQ、SETF(COMMON LISP),其功能是类似的。
4.谓词函数
返回值为逻辑值真或假的函数称为谓词函数,简称谓词。LISP中真和假分别用T和NIL表示,当函数的返回值为非NIL时,也表示为真。另外,NIL也表示空表。谓词函数也有多个,下面我们仅给出常用的几个。(1)原子谓词ATOM
格式(ATOM<参数>)
功能检测其参数是否为原子,是则返回T,否则返回NIL。
例如:
(ATOM′a);返回T
(ATOM′(a b));返回NIL(2)相等谓词EQUAL
格式(EQUAL<参数><参数>)
功能判断两个参数是否逻辑相等。
例如:
(EQUAL′a′a);
返回T
(EQUAL′(a b)′(ac));
返回NIL
(EQUAL′(a b)(CONS′a′(b)));
返回T
还有一种相等谓词,其格式为:(EQ<参数><参数>),但它只是用来判断两个原子是否相等。例如:(EQ′a′a),则返回T(3)判空表函数NULL
格式(NULL<参数>)
功能判断参数是否为空表,是则返回T,否则返回NIL。
5.条件函数
条件函数也称分支函数,类似于其他语言中的分支语句,其作用是控制程序的流程。
格式
(COND(P1 e1)
(P2e2)
…
(Pnen))
其中Pi(i=1,...,n)为谓词,ei(i=1,...,n)为一个或多个S─表达式。
功能如果P1为真,则COND函数的值为e1(当e1为多个S─表达式时,取最后一个S─表达式的值,下同)。否则,判断P2,……直到某个Pi真为止,然后将对应的ei作为函数值。若没有一个Pi的值为非NIL,则COND的返回值为NIL。特别地,Pi也可以为逻辑常量T,这时则对其对应的各表达式求值,并把最后一个表达式的值作为COND的返回值。
例如:
(COND((NULL x)0)
((ATOM x)1)
((LISTP x)(LENGTH x)))
其语义是,若x的值为NIL,则COND的返回值为0;若x为原子,则COND的返回值为1;若x的值为表,则COND的返回值为表的长度。
2.2.4 自定义函数
基本函数是LISP提供的基本处理功能,要用LISP编程解决实际问题,仅有基本函数还是不够的,用户还必须根据问题的需要,利用基本函数自定义所需的函数。
自定义函数的格式为:
(DEFUN<函数名>(<形参表>)<函数体>)其中函数体,又可能是用户自定义的函数或LISP基本函数的某种组合。所以,一般来讲,LISP自定义函数就是由其基本函数组合而成的。常用的组合方法有复和、分支、递归、迭代等。其中最具特色的构造方法是递归。
例2.1 定义求N!的LISP函数。
阶乘的公式是
n!=n×(n-1)!
1!=1
0!=1
由此我们给出其LISP函数如下:
(DEFUNN!(n)
(COND((=n 0)1)
((=n 1)1)
(T(* n(N!(-n 1))))))可以看出,该函数的最后一行中又调用了它自己。所以,这个函数N!是递归定义的。
需说明的是,一个函数是否能递归定义,要取决于以下两条:
(1)函数的求值存在最简的情形,在这种情形下函数值是显然的或已知的;
(2)该函数对于其参数的求值,可以归结为对另一些参数的求值,而且后者比前者更容易求值,即使问题朝最简情形逼近了一步。
2.2.5 程序举例
例2.2 符号微分程序。
这里是指数学上的一元函数求导。我们用D(ex)表示数学上的de/dx,这里e为需求导的函数表达式,x为自变量。程序如下:
(DEFUND(ex)
(COND((ATOM e)(IF(Eq e x)1 0))
(T(APPLY(D-RULE(CAR e))
(APPEND(CDR e))
(LIST x)))))其中D-RULE是一个获取给定操作符的微分规则的LISP函数。微分规则的存放,是通过为相应操作符建立d特性的方法完成的。D-RULE的定义为
(DEFUN D-RULE(operator)
(GET operator′d))其中操作符d的特性值需事先用SETF函数建立好。例如对于操作符加+和乘·,在数学上有
d(u+v)/dx=du/dx+dv/dx
d(u·v)/dx=v·du/dx+u·dv/dx
用LISP表示就是
(SETF(GET′+′D)′(LAMBDA(u v
x)′(+,(Dux),(D v x))))
(SETF(GET′*′D)′(LAMBDA(u v
x)′(+(*,(Dux),v)(*,(D v x),u)))))有了这些函数,我们就可以用机器求符号微分了。例如,给出如下的函数调用(D′(+(*2x)(*x x))′x);即求一元函数2x+x2关于x的导函数则得到返回值为
(+(+(* 0 x)(* 1 2))(+(* 1 x)(*1 x)))
即2+2x,结果正确。
由于篇幅所限,上面我们对LISP语言仅做了简要介绍。需进一步学习的读者,可参阅有关专门著作。实际上,以此为入门和基础,读者就可以参照某一具体的LISP语言资料,进行LISP程序设计了。经过30多年的发展,LISP的方言和版本也很多。目前比较流行的有INTERLISP、MACLISP、COMMONLISP。其中COMMONLISP将成为一种标准,以统一各种LISP方言。
http://www.xiexiebang.com/tags/Prolog/
第二篇:Excel函数教程:AND、OR、NOT逻辑函数
Excel函数教程:AND、OR、NOT逻辑函数
用来判断真假值,或者进行复合检验的Excel函数,我们称为逻辑函数。在Excel中提供了六种逻辑函数。即AND、OR、NOT、FALSE、IF、TRUE函数。
AND、OR、NOT这三个函数都用来返回参数逻辑值。详细介绍见下:
(一)AND函数
所有参数的逻辑值为真时返回 TRUE;只要一个参数的逻辑值为假即返回 FALSE。简言之,就是当AND的参数全部满足某一条件时,返回结果为TRUE,否则为FALSE。
语法为AND(logical1,logical2,...),其中Logical1, logical2,...表示待检测的 1 到 30 个条件值,各条件值可能为TRUE,可能为FALSE。参数必须是逻辑值,或者包含逻辑值的数组或引用。举例说明:
1、在B2单元格中输入数字50,在C2中写公式=AND(B2>30,B2<60)。由于B2等于50的确大于30、小于60。所以两个条件值(logical)均为真,则返回结果为TRUE。
2、如果 B1-B3 单元格中的值为 TRUE、FALSE、TRUE,显然三个参数并不都为真,所以 在B4单元格中的公式=AND(B1:B3)等于 FALSE
(二)OR函数
OR函数指在其参数组中,任何一个参数逻辑值为 TRUE,即返回 TRUE。它与AND函数的区别在于,AND函数要求所有函数逻辑值均为真,结果方为真。而OR函数仅需其中任何一个为真即可为真。比如,上面的示例2,如果在B4单元格中的公式写为=OR(B1:B3)则结果等于TRUE
(三)NOT函数
NOT函数用于对参数值求反。当要确保一个值不等于某一特定值时,可以使用 NOT 函数。简言之,就是当参数值为TRUE时,NOT函数返回的结果恰与之相反,结果为FALSE.比如NOT(2+2=4),由于2+2的结果的确为4,该参数结果为TRUE,由于是NOT函数,因此返回函数结果与之相反,为FALSE。
第三篇:规范求职信写作详细教程
什么事求职信?求职信就是专门为某一职位的求职申请而写,区别于求职简历,所以必须要有针对性,一般应在信中提到所申请的公司名称和职位名称等信息。因为针对性强所以不可太长,这主要是考虑用人单位的时间问题,只要一页就可以了。主要目的是向对方表明你对对方招聘广告中的某个职位感兴趣,极其概括陈述你的工作经历和经验合适你所申请的职位。
求职信的内容写法?
第一段引子,应该说明你所应聘的具体职位和得到职位信息的途径,通常是简短的一两句话。对于一个大公司来讲,每天收到的求职信会比较多,信的开头就表明求职意向会给对方工作带来方便。例如:
第二段描述部分,可以写上求职者对所申请职位性质的理解,对招聘公司的了解,可以展开说明你的应聘优势。比如挑选 简历 中于所应聘职位最相关的部分,促使招聘者想进一步阅读你的简历并有较强的针对性。描述部分的长度可以控制在两到三个长句。例如:
“我是一个成功的销售人员。在______公司任____ 职位的3年期间,曾数次因工作的主动性与创造性而受到奖励。我负责的_____区域的___产品销售市场占有率一直保持在__以上。我相信我在____领域里的市场销售经验完全能够胜任贵公司 一职。”
第三部分总结,表明自己希望加入公司的诚意,礼貌的提出希望参加 面试 的请求。标明与你联系的最佳方式和预约 面试 的可能时间范围。结尾亦可以礼节性的感谢对方花时间浏览简历并对你关注。
求职信写作注意事项:
长度控制在400字以内,否则招聘人员没有耐心阅读。
通篇应该没有打字,拼写,语法错误。
选择质量好的纸张,打印精美。
求职信是针对某一职位专门书写得,不可随意复印任意发送。
第四篇:DedeCMS专题功能使用详细教程
爱雅逸整理http://2text(@me)'/}“ /> 这个代码就是将你在添加专题时候设置的关键字以及专题说明添加进页面。
接下来最重要的就是专题节点部分的添加了,因为节点部分主要是列表,所以涉及到一个底层模板(innertext)的概念,底层模板在织梦的标签语法简介中已经有相关说明。(模板标签语法简介:http://help.dedecms.com/v53/archives/templets/start/)因为我们从模板文件中可以找出单挑记录循环的内容为:
爱雅逸整理http://www.xiexiebang.com
DEDECMS 专题详解
接下来我们在节点部分加入节点标签{dede:field.notenoteid=„标识‟/},因为我们这里有2个节点名称,标识ID分别为: use(使用介绍)、exp(体验说明),所以我们替换模板页面中循环部分:
使用介绍 |
在我们上面设计的模板中,有2个节点,因为我们其中有一部分内容已经固化在模板中,所以如果直接发布内容,会出现多出了节点标题的情况,一个节点生成为页面的时候,DedeCMS会读取他的节点容器模板,所以我们需要对节点容器模板进行一些修改,我们打开/templets/system/channel_spec_note.htm这是默认的节点容器模板。
- ~notename~
-
- ~spec_arclist~
~spec_arclist~ 节点内容列表,系统读取底层模板文件,并解析成节点设置的内容同这个标记进行替换
这个节点容器解析后的内容再同{dede:field.notenoteid=„标识‟/}标记进行替换,完成模板的解析,所以我们在这里需要对其进行一些修改,因为前面设计时候的节点名称已经固化在模板文件中,所以这里不涉及到这部分的内容。我们只要将冗余部分的代码去除,直接使之变为: ~spec_arclist~
如果不想影响到其他模板文件的使用我们将其另存为: /templets/system/channel_spec_note_dedecms.htm 我们在添加专题时候可以独立设置为:
爱雅逸整理http://www.xiexiebang.com
DEDECMS 专题详解
至此我们完成了专题页面模板文件的制作,接下来做的只需要像上面所说的一样,直接选取相应的内容添加节点发布即可。
织梦的专题功能还有更为强大的功能,需要我们织梦的用户去用心体会,本文中已经较为全面介绍了如何使用专题功能,文章中设计到的一些文件可以在附件中下载。
-------------专题中的文章是你从栏目中选择出来的。如果要在栏目A中不显示专题,那么需要在栏目A的列表htm模板中,将专题调用标签删除,即可。织梦dedecms网站专题调用标签的使用方法:
dede织梦cms模板网站专题调用标签就是是用的arclist标签,只不过在里面用了一个spec的类型而已,下面模板团给出三种调用方式,可以解决全部页面的调用(首页、一级、二级、单页、内容页均有适合的)。
第五篇:小学四年级奥数教程—逻辑问题
逻辑问题(逻辑问题
(一)在日常生活中,有些问题常常要求我们主要通过分析和推理,而不是计算得出正确 的结论。这类判断、推理问题,就叫做逻辑推理问题,简称逻辑问题。这类题目与我们学过 的数学题目有很大不同,题中往往没有数字和图形,也不用我们学过的数学计算方法,而是 根据已知条件,分析推理,得到答案。本讲介绍利用列表法求解逻辑问题。例 1 小王、小张和小李一位是工人,一位是农民,一位是教师,现在只知道:小李比教 师年龄大;小王与农民不同岁;农民比小张年龄小。问:谁是工人?谁是农民?谁是教师? 分析与解: 分析与解:由题目条件可以知道:小李不是教师,小王不是农民,小张不是农民。由此 得到左下表。表格中打“√”表示肯定,打“×”表示否定。
因为左上表中,任一行、任一列只能有一个“√”,其余是“×”,所以小李是农 民,于是得到右上表。因为农民小李比小张年龄小,又小李比教师年龄大,所以小张比教师年龄大,即小 张不是教师。因此得到左下表,从而得到右下表,即小张是工人,小李是农民,小王是教师。
图片点击可在新窗口打开查看
例 1 中采用列表法,使得各种关系更明确。为了讲解清楚,例题中画了几个表,实际解 题时,不用画这么多表,只在一个表中先后画出各种关系即可。需要注意的是:①第一步应 将题目条件给出的关系画在表上,然后再依次将分析推理出的关系画在表上; ②每行每列只 能有一个“√”,如果出现了一个“√”,它所在的行和列的其余格中都应画“×”。在下面的例题中,“√”和“×”的含义是很明显的,不再单独解释。例 2 刘刚、马辉、李强三个男孩各有一个妹妹,六个人进行乒乓球混合双打比赛。事先 规定:兄妹二人不许搭伴。第一盘:刘刚和小丽对李强和小英; 第二盘:李强和小红对刘刚和马辉的妹妹。问:三个男孩的妹妹分别是谁?
分析与解: 分析与解:因为兄妹二人不许搭伴,所以题目条件表明:刘刚与小丽、李强与小英、李 强与小红都不是兄妹。由第二盘看出,小红不是马辉的妹妹。将这些关系画在左下表中,由 左下表可得右下表。
刘刚与小红、马辉与小英、李强与小丽分别是兄妹。例 3 甲、乙、丙每人有两个外号,人们有时以“数学博士”、“短跑健将”、“跳高冠 军”、“小画家”、“大作家”和“歌唱家”称呼他们。此外:(1)数学博士夸跳高冠军跳得高;(2)跳高冠军和大作家常与甲一起去看电影;(3)短跑健将请小画家画贺年卡;(4)数学博士和小画家很要好;(5)乙向大作家借
过书;(6)丙下象棋常赢乙和小画家。你知道甲、乙、丙各有哪两个外号吗? 分析与解: 分析与解:由(2)知,甲不是跳高冠军和大作家;由(5)知,乙不是大作家;由(6)知,丙、乙都不是小画家。由此可得到下表:
因为甲是小画家,所以由(3)(4)知甲不是短跑健将和数学博士,推知甲是歌唱 家。因为丙是大作家,所以由(2)知丙不是跳高冠军,推知乙是跳高冠军。因为乙是跳高 冠军,所以由(1)知乙不是数学博士。将上面的结论依次填入上表,便得到下表:
所以,甲是小画家和歌唱家,乙是短跑健将和跳高冠军,丙是数学博士和大作家。例 4 张明、席辉和李刚在北京、上海和天津工作,他们的职业是工人、农民和教师,已 知:(1)张明不在北京工作,席辉不在上海工作;(2)在北京工作的不是教师;(3)在上海工作的是工人;(4)席辉不是农民。问:这三人各住哪里?各是什么职业? 分析与解: 分析与解:与前面的例题相比,这道题的关系要复杂一些,要求我们通过推理,弄清人 物、工作地点、职业三者之间的关系。三者的关系需要两两构造三个表,即人物与地点,人 物与职业,地点与职业三个表。我们先将题目条件中所给出的关系用下面的表来表示,由条件(1)得到表 1,由条 件(4)得到表 2,由条件(2)(3)得到表 3。因为各表中,每行每列只能有一个“√”,所以表(3)可填全为表(4)。
因为席辉不在上海工作,在上海工作的是工人,所以席辉不是工人,他又不是农民,所以席辉是教师。再由表 4 知,教师住在天津,即席辉住在天津。至此,表 1 可填全为表 5。
对照表 5 和表 4,得到:张明住在上海是工人,席辉住在天津是教师,李刚住在北 京是农民。练习26 1.甲、乙、丙分别是来自中国、日本和英国的小朋友。甲不会英文,乙不懂日语却 与英国小朋友热烈交谈。问:甲、乙、丙分别是哪国的小朋友? 2.徐、王、陈、赵四位师傅分别是工厂的木工、车工、电工和钳工,他们都是象棋 迷。
(1)电工只和车工下棋;(2)王、陈两位师傅经常与木工下棋;(3)徐师傅与电工下棋互有胜负;(4)陈师傅比钳工下得好。问:徐、王、陈、赵四位师傅各从事什么工种? 3.李波、顾锋、刘英三位老师共同担负六年级某班的语文、数学、政治、体育、音 乐和图画六门课的教学,每人教两门。现知道:(1)顾锋最年轻;(2)李波喜欢与体育老师、数学老师交谈;(3)体育老师和图画老师都比政治老师年龄大;(4)顾锋、音乐老师、语文老师经常一起去游泳;(5)刘英与语文老师是邻
邻居。问:各人分别教哪两门课程? 4.A,B,C,D 分别是中国、日本、美国和法国人。已知:(1)A 和中国人是医生;(2)B 和法国人是教师;(3)C 和日本人职业不同;(4)D 不会看病。问:A,B,C,D 各是哪国人,5.小亮、小红、小娟分别在一小、二小、三小读书,各自爱好围棋、体操、足球中 的一项,现知道:(1)小亮不在一小;(2)小红不在二小;(3)爱好足球的不在三小;(4)爱好围棋的在一小,但不是小红。问:小亮、小红、小娟各在哪个学校读书和各自的爱好是什么?