Lisp 入门教程
- 格式:pdf
- 大小:415.73 KB
- 文档页数:16
LISP语言教程作者:牛魔王—上次修改时间: 2007-03-22 13:13Scheme 语言是LISP语言的一个方言(或说成变种),它诞生于1975年的MIT,对于这个有近三十年历史的编程语言来说,它并没有象C++,java,C#那样受到商业领域的青睐,在国内更是显为人知。
但它在国外的计算机教育领域内却是有着广泛应用的,有很多人学的第一门计算机语言就是Scheme语言。
Scheme 语言概要Author: 宋国伟吉林省德惠市信息中心Date: 2003 年 12 月 01 日Scheme 语言是LISP语言的一个方言(或说成变种),它诞生于1975年的MIT,对于这个有近三十年历史的编程语言来说,它并没有象C++,java,C#那样受到商业领域的青睐,在国内更是显为人知。
但它在国外的计算机教育领域内却是有着广泛应用的,有很多人学的第一门计算机语言就是Scheme语言。
作为Lisp 变体,Scheme 是一门非常简洁的计算语言,使用它的编程人员可以摆脱语言本身的复杂性,把注意力集中到更重要的问题上,从而使语言真正成为解决问题的工具。
本文分为上、下两部分来介绍 scheme 语言。
一.Scheme语言的特点Scheme 语言是LISP语言的一个方言(或说成变种),它诞生于1975年的MIT,对于这个有近三十年历史的编程语言来说,它并没有象C++,java,C#那样受到商业领域的青睐,在国内更是显为人知。
但它在国外的计算机教育领域内却是有着广泛应用的,有很多人学的第一门计算机语言就是Scheme语言。
它是一个小巧而又强大的语言,作为一个多用途的编程语言,它可以作为脚本语言使用,也可以作为应用软件的扩展语言来使用,它具有元语言特性,还有很多独到的特色,以致于它被称为编程语言中的"皇后"。
下面是洪峰对Scheme语言的编程特色的归纳:∙词法定界(Lexical Scoping)∙动态类型(Dynamic Typing)∙良好的可扩展性∙尾递归(Tail Recursive)∙函数可以作为值返回∙支持一流的计算连续∙传值调用(passing-by-value)∙算术运算相对独立本文的目的是让有编程基础(那怕是一点点)的朋友能尽快的掌握Scheme语言的语法规则,如果您在读完本文后,发现自己已经会用Scheme语言了,那么我的目的就达到了。
第 0 课 <第一篇 基本知识> (第1节)基本知识对话框是现今最流行的人机互动面接口;在早期的AutoCAD版本中巳经使用,但只有在R12版本开始,才提供给使用者自行编程的对话框开发功能.对话框的描述定义在一纯文字文件(扩展名为DCL)内,无须特别的开发环境 定义文件中的对话框描述,均以对话控制语言(Dialog Control Language,简称DCL语言)所建立在AutoLISP程序中,配合可编程对话框(Porgrammable Dialog Box,简称PDB)函数,激活及操控对话框可以在一个定义档(扩展名DCL)中定义多个对话框对话框由方块本身,及包含于其内的组件(或称为控件,构件)所组成每个组件的属性定义均包含在一对大括号{ }中在定义文件中,各组件及其属性均为小写;只有在赋值给属性,或设定对话框名称时才可使用大写字母属性以等号=赋值,并以分号;结束(注意 : 在AutoLISP程序中,分号是作为批注)一般要在组件名称前加上一个冒号:,但若组件并不设定属性,则不需要在组件名称前加冒号,但却要以分号结束空行会被忽若定义档发生严重的错误,会在当前的目录下,产生ACAD.DCE文件,以指明所发生的错误.第 1 课 <第一篇 基本知识> (第2节)定义档BASE.DCL预设在SUPPORT的目录中,它包含了各组件的原型定义,及各类型巳定义的其它基本组件;而所有自行开发的对话框定义文件,都可以使用在BASE.DCL定义文件中的各个组件ACAD.DCL 预设在SUPPORT的目录中,它包含了AutoCAD中所有标准对话框的定义参考定义档可在自行开发的对话框定义文件中,经由include指令,取得指定DCL文件中所定义的组件;其语法如下:@include "对话框定义档"e.g. @include "david.dcl"定义档名称要包含在双引号"中,可以在档名前加上定的目录路径会先在当前的目录中搜寻该定义文件,然后是定义文件所在的目录;若有指定档案的路径,则只会在指定的目录内寻找不可以参考ACAD.DCL所定义的对话框,即不可以使用@include "acad.dcl"预视对话框若在Visual LISP中开启一对话框定义文件,即可使用 :工具 -- 接口工具 -- 预览编辑器DCL在下拉式列示框中,选取该定义文件中所设定的对话框名称,即可预视对话框亦可直接输入该对话框的名称(要注意大小写)第 2 课 <第一篇 基本知识> (第3节)批注//表示其右边(至该行末端)的文字视为注释/* */包括在两个批注符号中间的所有文字(可跨越多行)均视为注释语义检核提供4个等级的检核,该些检核会在对话框载入时完成;可以将下列语句放在定义文件中的任何位置,但不能在任何对话框的定义内.dcl_settings : default_dcl_settings {audit_level = 3;}等级0 不检查 : 只有在该定义档巳被检核且不会再作修改时使用等级1 错误 : 找出可能造成AutoCAD终止的错误,此等级也是默认值等级2 警告 : 找出配置或行为模式的错误,所有定义在修改后,最少应执行此等级的检查一次等级3 提示 : 找出多余的属性定义对话框的设计美观性 颜色配比,组件整齐排列等方便性 相同功能的项目要编排在一起,或使用线框包围使用频繁的项目应设置在最显眼及方便的位置适当设置快速键及默认值(默认值,省缺值)除非对话框中的项目过多,否则应避免使用巢状(嵌套)式对话方框互锁或互换 项目选取(或不选取)时,会否引致其它项目功能的改变(enable或disable...等)第 3 课 <第一篇 基本知识> (第4节)对话框定义文件内容模式对话框名称:dialog{label="对话框标题" ;:组件名称{ 属性名称=属性值;} //组件定义结束} //对话框结束定义说明1对话框名称就是由AutoLISP程序,启动对话框时所呼叫的名称;可以自行设定,要区分大小写字母dialog为对话框中,最外层的组件(即整个对话框),其它的组件均包含在其中一般组件要以冒号:开始,并为小写字母;因为不是属性,所以不须使用分号;结束2开大括号{紧随组件名称之后,以包含该组件的属性或其它组件 label为属性名称,并以等号=赋以其右边的属性值,最后以分号;结束该行叙述3包含在对话框中的其它组件组件要以冒号:开始,并为小写字母;因为不是属性,所以不须使用分号;结束4开大括号{紧随组件名称之后,以包含组件的属性或其它组件 包含在组件中的属性,要以等号=赋以其右边的属性值;最后以分号;结束该行叙述5以关大括号}与第4行的开大括号}对应,以结束该组件(第3行)之定义 双除号//右边的文字即为批注6以关大括号}与第2行的开大括号}对应,以结束该组件之定义(在本例中为整个对话框的定义,即第1行的dialog组件注意:上例中缩排只为方便观察及维护,不作缩排亦可包含在对话框中的组件及组件中的属性可以不只一个第 4 课 <第一篇 基本知识> (第5节)练习 (Exercises)请输入以下的对话框定义,并命名为RECT.DCL(纯文字格式),存在C盘的根目录中RECT:dialog{label="Rectangle" ;:text//文字组件{label="Rectangle width :" ;//组件的属性}ok_only;}定义说明:1设定对话框的名称为RECT,紧接一个以冒号开始的组件dialog2最左边为dialog组件的开大括号,右边是其属性label,并以等号设定其属性值为"Rectangle",以分号结束此行叙述3text为"字符串"组件,其作用是在对话框中显示文字,组件名称前要加冒号4最左边为text组件的开大括号,右边是其属性label,并以等号设定其属性值为"Rectangle width",最后以分号结束此行叙述5关大括号是对应第4行的开大括号,这对大括号同属于第3行的text组件 6ok_only为一"按钮组件",它的作用是在对话框中显示一个"确定(OK)"按钮;在一个对话框中,必需提供最少一个"确定"按钮,或一个"取消"按钮(组件名称为cancel_button),以作为结束对话框之用;本例中不设定按钮之属性,固不需以冒号放在组件名称的前面,但却需要以分号结束7关大括号是对应第2行的开大括号,这对大括号同属于第1行的dialog组件注意:虽然定义档巳经完作,但仍要待学习完第2篇的课程后,才能开启及显示该对话框第 5 课 <第二篇 开启对话框> (第1节) AutoLISP函数加载DCL定义文件函数(LOAD_DIALOG "对话框定义档名称")e.g. (LOAD_DIALOG "C:/RECT.DCL")自变量是要加载的对话框定义文件名称字符串(所以要在前后加双引号);若不设定扩展名则预设为.DCL函数会依资源搜寻路径找寻该定义文件;不在搜寻路径中的档案,要在文件名称前加上指定的路径函数若成功加载该定义档,会传回一正整数值的档案处理码,供其它函数呼叫使用;无法加载时则传回负整数值一般会将传回的档案处理码以SETQ函数存入变量中e.g. (SETQ DCL_ID (LOAD_DIALOG "C:/RECT.DCL"))开启并显示对话框(NEW_DIALOG "对话框名称" 档案处理码 ["预设动作" [对话框位置]])e.g. (NEW_DIALOG "RECT" DCL_ID)对话框名称为字符串,要在前后加双引号;要注意一个定义档中,可包含多个对话框名称及其定义档案处理码是经由LOAD_DIALOG函数取得预设动作为字符串表示式;函数可以不加预设动作,或以空字符串""表示 如果要设定对话框显示时的位置,则必须同时设定预设动作对话框位置为2D的点串行,指定对话框左上角的X,Y坐标如果以 '(-1 -1)为对话框位置,则会在绘图屏幕的中心点开启对话框如果成功开启对话框,函数会传回T,否则传回NIL开始接受使用者输入(START_DIALOG)函数不须提供任何自变量使前一个用NEW_DIALOG函数开启的对话框开始作用,直至动作表示式或回复函数呼叫DONE_DIALOG函数为止一般DONE_DIALOG与关键词accept(一般是按下确定按钮)或关键词cancel(一般是按下取消按钮)相关若传回值为1,表示使用者按下确定钮结束对话框;0表示按下取消钮;-1表示全部对话框都以TERM_DIALOG函数终止;大于1的整数,其意义由应用程序决定释放(卸载)对话框(UNLOAD_DIALOG "档案处理码")e.g. (UNLOAD_DIALOG DCL_ID)从内存释放档案处理码(经由LOAD_DIALOG函数取得)指定的对话框定义档 函数传回值一定是NIL第 6 课 <第二篇 开启对话框> (第2节)对话框开启方式(DEFUN C:函数名称( )(SETQ 变量 (LOAD_DIALOG "对话框定义档"))(NEW_DIALOG "对话框名称" 变量)(START_DIALOG) (UNLOAD_DIALOG 变数))程序说明:1以DEFUN函数定义程序的名称,使用LOAD_DIALOG函数加载指定的对话框定义档使用SETQ函数,将LOAD_DIALOG传回的档案处理码存入变量中,以方便其它函数使用2使用NEW_DIALOG,开启及显示定义文件中(档案处理码),指定的对话框3使用START_DIALOG函数,使对话框开始作用并接受使用者输入 使用UNLOAD_DIALOG函数以结束对话框4关括号是对应第1行DEFUN函数左边的开括号,结束整个程序练习 (Exercises)编写一AutoLISP程序,以开启上一课所定义的对话框;并将该程序命名为RECT.LSP,存在C盘的根目录中,程序代码如下 :(DEFUN C:RECT()(SETQ DCL_ID (LOAD_DIALOG "C:/RECT.DCL"))(NEW_DIALOG "RECT" DCL_ID)(START_DIALOG) (UNLOAD_DIALOG DCL_ID))程序说明:1以DEFUN函数定义程序的名称为RECT,使用LOAD_DIALOG函数将对话框定义文件RECT.DCL载入;使用SETQ函数,将LOAD_DIALOG传回的档案处理码存入变量DCL_ID中,以方便其它函数使用2使用NEW_DIALOG,开启及显示定义文件中(档案处理码)名称为RECT的对话框3使用START_DIALOG函数,使对话框开始作用并接受使用者输入(在本例中只有确定钮可按);使用UNLOAD_DIALOG函数以结束对话框4关括号是对应第1行DEFUN函数左边的开括号,结束整个程序第 7 课 <第二篇 开启对话框> (第3节)编辑框组件(edit_box)可供使用者直接输入字符串的矩形方框;注意在编辑框中所显示及输入的数据均为字符串型态,而数字则要在取得编辑框的字符串内容后(在下一篇中介绍),使用AutoLISP函数将其转为数值型态的数据:edit_box//组件名称{ 属性="属性值" ;}属性label显示在编辑框前面(左边)的提示文字key其属性值即为使用该组件的关键词,使在AutoLISP程序中操控此组件;在同一个对话框定义中,不能有相同名称的关键词定义 edit_limit指定在编辑框中,可输入字符串的最大字符长度edit_width指定编辑框显示时的阔度(通常与fixed_width属性一拼使用) value指定编辑框显示时,当中的默认值(注意显示数值数据时,要先用AutoLISP函数将数据(或变量)转为字符串型态)fixed_width通常与width属性一拼使用,以固定编辑框显示时的阔度(其属性值可设定为true或false)is_enable可设定编辑框是否可以使用(其属性值可设定为true或false,默认值为true)alignment如果组件成水平方向排列,属性值可设定为left,right或centered如果组件成垂直方向排列,属性值可设定为top,bottom或centered(水平方向的默认值为left,垂直方向则为centered)其它属性action allow_accept fixed_height heightis_tab_stop mnemonic width第 8 课 <第二篇 开启对话框> (第4节)练习(Exercises)将上一课的RECT.DCL对话框定义档复制至RECT1.DCL,开启新的定义档并作如下的修改,使其可以输入四边形的阔度及高度;将AutoLISP程序文件RECT.LSP 复制至RECT1.LSP,开启新的程序文件,并将要加载的对话框定义档改为RECT1(程序第1行);完成后即可加载及执行新的程序文件RECT:dialog{label="Rectangle" ;:edit_box//编辑框组件{label="Rectangle width : " ;key="RECT_W" ;edit_limit=16;edit_width=10;fixed_width=true;}:edit_box//编辑框组件{label="Rectangle heigth :" ;key="RECT_H" ;edit_limit=16;edit_width=10;fixed_width=true;}ok_only;}定义说明:1设定对话框的名称为RECT,紧接一个以冒号开始的组件dialog2最左边为dialog组件的开大括号,右边是其属性label,并以等号设定其属性值为 "Rectangle",以分号结束此行叙述3edit_box为"编辑框"组件,组件名称前要加冒号4最左边为edit_box组件的开大括号,右边是其属性label,并以等号设定其属性值为 "Rectangle width : ",最后以分号结束此行叙述5设定属性key的属性值为RECT_W(即设定此编辑框的名称)6设定属性edit_limit的属性值为16(即最多可以在编辑框中输入16个数字) 7设定属性edit_width的属性值为10(编辑框只会显示10个字的长度)8设定属性fixed_width的属性值为true,表示表将编辑框以固定的阔度显示9关大括号是对应第4行的开大括号,这一对大括号同属于第3行的edit_box 组件10至16与3至9行相似,设定另一个编辑框以输入高度的数据;只有属性label 及key的属性值不同17以ok_only组件,在对话框中显示一个确定(OK)按钮,作为结束对话框之用 18关大括号是对应第2行的开大括号,这一对大括号同属于第1行的dialog组件注意1在第一个编辑框(输入四边形的阔度)的label属性值中,在字符串最后的冒号后面,加多了一个空格,目的是方更与下一个编辑框对齐1节)AutoLISP函数设定组件的值(SET_TILE "组件关键词" 设定值)e.g. (SET_TILE "RECT_W" "50.0")组件的初始值可在定义文件中以属性value设定,但在程序文件中则以此函数设定组件关键词即是在对话框定义文件中,以组件属性key所定义的属性值,以赋予该组件一个操作名称组件关键词是有区分大小写的此函数要在START_DIALOG函数之后才能使用取得组件的值(GET_TILE "组件关键词")e.g. (GET_TILE "RECT_W")作用是在AutoLISP程序文件中取得组件(以关键词指定)的设定值组件关键词的说明与SET_TILE函数相同此函数要在DONE_DIALOG函数之前使用(即要在对话框结束前使用)设定组件的状态(MODE_TILE "组件关键词" 状态模式)e.g. (MODE_TILE "RECT_W" 0)作用是在AutoLISP程序文件中设定组件(以关键词指定)的使用状态,其状态模式可以设定为下列任一整数值 :0 使指定的组件成为使用状态1 使指定的组件成为禁用状态(组件以灰色显示)2 使指定的组件成为焦点3 选取指定编辑框组件的内容4 图像高亮度显示的开关组件关键词的说明与SET_TILE函数相同2节)练习 (Exercises)以修改对话框定义档的方式,设定输入阔度的编辑框其初始值为50,输入高度的编辑框其初始值为25定义档 将RECT1.DCL复制至RECT2.DCL,在关键词为RECT_W的组件中,加入value属性并设定其初始值为50;在关键词为RECT_H的组件中,加入value属性并设定其初始值为25程序文件 将RECT1.LSP复制至RECT2.LSP,只须修改其加载的定义档名称为RECT2.DCL即可;完成后存盘,进入AutoCAD并载入RECT2.LSP程序文件,执行RECT2程序RECT:dialog{label="Rectangle" ;:edit_box{"Rectangle width : " ;key="RECT_W" ;edit_limit=16;edit_width=10;fixed_width=true;value="50.0" //注意设定值为字符串型态,要在前后加双引号}:edit_box{"Rectangle height :" ;key="RECT_H" ;edit_limit=16;edit_width=10;fixed_width=true;value="25.0" //注意设定值为字符串型态,要在前后加双引号}}第 11 课 <第三篇 设定及取得对话框组件内的值> (第3节)练习 (Exercises)以修改AutoLISP程序文件的方式,使输入阔度的编辑框其初始值为50,输入高度的编辑框其初始值为25定义档 将RECT1.DCL(不是RECT2.DCL)复制至RECT3.DCL,不作任何修改 程序文件 将RECT1.LSP复制至RECT3.LSP,程序代码如下:(DEFUN C:RECT()(SETQ DCL_ID (LOAD_DIALOG "C:/RECT3.DCL"))(NEW_DIALOG "RECT" DCL_ID)(SET_TILE "RECT_W" "50.0")(SET_TILE "RECT_H" "25.0")(START_DIALOG)(UNLOAD_DIALOG DCL_ID))程序说明:1以DEFUN函数定义程序的名称RECT,使用LOAD_DIALOG函数将对话框定义文件RECT3.DCL载入;使用SETQ函数,将LOAD_DIALOG传回的档案处理码存入变量DCL_ID中,以方便其它函数使用2使用NEW_DIALOG,开启及显示定义文件中(档案处理码)名称为RECT的对话框3,4使用SET_TILE函数,设定输入阔度的编辑框组件RECT_W(组件关键词,在定义文件中key设定的属性值)为50,设定输入高度的编辑框组件RECT_H为25 5使用START_DIALOG函数,使对话框开始作用并接受使用者输入(在本例中只有确定钮可按);使用UNLOAD_DIALOG函数以结束对话框6关括号是对应第1行DEFUN函数左边的开括号,结束整个程序第 12 课 <第三篇 设定及取得对话框组件内的值> (第4节)AutoLISP函数组件指定动作(ACTION_TILE "组件关键词" "指定动作")e.g. (ACTION_TILE "RECT_W" "(SETQ TEMP 1)")当焦点在指定的组件(关键词)上并按下接受键时,即会执行函数所指定的动作指定动作会取代定义文件中,该组件的action属性之预设动作组件关键词"accept"在预设情况下是与确定按钮组件关连(即是确定按钮的预设关键词),"cancel"则与取消按钮组件关连(即是取消按钮的预设关键词)终止对话框(DONE_DIALOG [指定传回值])e.g. (DONE_DIALOG)此函数的传回值为一个2D点串行坐标,为结束对话框时,对话框的所在位置;可作为下次启动同一个对话框的位置自变量,使对话框在之前结束时的位置再次显现练习 (Exercises)将定义档RECT3.DCL复制至RECT4.DCL,但不作任何修改.将程序文件RECT3.LSP复制至RECT4.LSP,并修改为 : 使用ACTION_TILE函数,指定在按下确定钮时,执行一辅助程序;在该辅助程序中,使用GET_TILE函数最得对话框中四边形的阔度及高度,并在使用者选取的位置上绘画出四边形.(DEFUN C:RECT()(SETQ DCL_ID (LOAD_DIALOG "C:/RECT4.DCL"))(NEW_DIALOG "RECT" DCL_ID)(SET_TILE "RECT_W" "50.0")(SET_TILE "RECT_H" "25.0")(ACTION_TILE "accept" "(S_RECT)(DONE_DIALOG)")(START_DIALOG)(UNLOAD_DIALOG)(SETQ PT_0 (GETPOINT "\nSelect rectangle lower leftpoint : "))(SETQ PT_1 (POLAR PT_0 0 TMP_W)PT_2 (POLAR PT_1 (/ PI 2) TMP_H)PT_3 (POLAR PT_2 PI TMP_W))(COMMAND "PLINE" PT_0 PT_1 PT_2 PT_3 "C")(PRINC))(DEFUN S_RECT()(SETQ TMP_W (ABS (ATOF (GET_TILE "RECT_W")))TMP_H (ABS (ATOF (GET_TILE "RECT_H")))))续下一课 ....第 13 课 <第三篇 设定及取得对话框组件内的值> (第5节)续上一课 ....主程序(RECT)说明:1注意将LOAD_DIALOG函数所加载的对话框定义档改为RECT4.DCL2-参阅RECT3程序的说明45使用ACTION_TILE函数设定关键词为accept的组件(预设为确定按钮)的指定动作 : 先执行辅助程序S_RECT,取得输入的数据,再使用DONE_DIALOG函数结束对话框6参阅RECT3程序,第5行的说明7使用GETPOINT函数让使用者选取四边形的左下角位置坐标,存入变量PT_0 8使用POLAR函数取得新坐标点 : 从选取点PT_0开始,向右(角度为0),距离为四边形的阔度(变量TMP_W,在辅助程序中取得),存入变量PT_19使用POLAR函数取得新坐标点 : 从上一点PT_1开始,向上(角度90,等于PI 除2),距离为四边形的高度(变量TMP_H,在辅助程序中取得),存入变量PT_2 10使用POLAR函数取得新坐标点 : 从上一点PT_2开始,向左(角度1800,等于PI),距离为四边形的阔度(变量TMP_W,在辅助程序中取得),存入变量PT_3;注意最右边的关括号,是对应第8行SETQ函数左边的开括号11使用COMMAND函数执行PLINE指令,并分别设定四个坐标变量,最后以"C"选项封闭聚合线12以一个不带参数的PRINC函数,抑制多余的显示及传回值;最右边的关括号是对应第1行DEFUN函数左边的开括号辅助程序(S_RECT)说明:1设定函数名称;使用GET_TILE函数取得指定关键词(RECT_W,代表输入阔度的编辑框组件)的值,并将该值使用ATOF函数由字符串型态转为实数型态(有小数);再使用ABS函数取得实数的绝对值,以防止使用者输入负数;最后将数据存入变量TMP_W2使用GET_TILE函数取得指定关键词(RECT_H,代表输入高度的编辑框组件)的值,转型及取得绝对值后,存入变量TMP_H3用一个关括号,对应第1行DEFUN函数左的开括号第 14 课 <第四篇 按钮及核取框(切换钮)> (第1节)按钮组件(button)一个矩形的按钮,可显示指定的讯息在按钮上:button//组件名称{ 属性="属性值" ;}属性label显示在按钮中的提示文字key其属性值即为使用该按钮组件的关键词width指定按钮的显示阔度height指定按钮的显示高度fixed_width通常与width属性一并使用,以固定按钮的显示阔度fixed_height 通常与height属性一并使用,以固定按钮的显示高度is_enable可设定按钮是否可以使用,其属性值可设定为true(可使用)或false(禁用,按钮中的消息正文变为灰色显示),默认值为true is_default属性值可设定为true或false;当使用者按下接受键(大部份的情况,ENTER被用作接受键)时,本属性设定为true的组件会自动被选取.当使用者在allow_accept属性设为true的编辑框,列表框或图像按钮中.按下接受键或双击鼠标键(只对列表框及图像按钮有效)时,本属性设定为true的组件亦会自动被选取 alignment如果组件成水平方向排列,属性值可设定为left,right或centered(若不设定则预设为left);如果组件成垂直方向排列,属性值可设定为top,bottom或centered(若不设定则预设为centered)其它属性action is_cancel is_tab_top mnemonic第 15 课 <第四篇 按钮及核取框(切换钮)> (第2节)核取框(切换钮)组件(toggle)是一个启用或关闭的切换方框,当方框中没有剔勾符号时,表示该功能为关闭状态,其组件的值为0;当方框中有剔勾符号时,表示该功能为启用状态,其组件的值为1:toggle//组件名称{ 属性="属性值" ;}属性label显示在切换钮后面(右边)的提示文字key其属性值即为使用该按钮组件的关键词is_enable可设定切换钮是否可以使用,其属性值可设定为true(可使用)或false(禁用),默认值为truevalue方框中没有剔勾符号时,表示该功能为关闭状态,其组件的值为0(亦是默认值);相反则为启用状态,组件的值为1alignment如果组件成水平方向排列,属性值可设定为left,right或centered(若不设定则预设为left);如果组件成垂直方向排列,属性值可设定为top,bottom或centered(若不设定则预设为centered)其它属性action is_tab_stop width heigthfixed_width fixed_heigth第 16 课 <第四篇 按钮及核取框(切换钮)> (第3节)练习 (Exercises)在四边形的对话框中,增加一核取框,以确定是否在四边形中加上交叉的对角线;另在对话框的底部增加两个按钮,按下时可使核取框作用或禁用定义档 将RECT4.DCL复制至RECT5.DCL,在新的定义档中增加核取框及按钮定义RECT:dialog{label="Rectangle" ;:edit_box{"Rectangle width : " ;key="RECT_W" ;edit_limit=16;edit_width=10;fixed_width=true;value="50.0"}:edit_box{"Rectangle height :" ;key="RECT_H" ;edit_limit=16;edit_width=10;fixed_width=true;value="25.0"}:toggle //新增的核取框(切换钮)组件{label="X line in rectangle" ;key="RECT_X" ;}:button //新增的按钮组件{label="&Enable" ;key="RECT_E" ;width=10;fixed_width=true;}:button //新增的按钮组件{label="&Disable" ;key="RECT_D" ;width=10;fixed_width=true;}ok_only;}续下一课 ....第 17 课 <第四篇 按钮及核取框(切换钮)> (第4节)续上一课 ....定义说明:第1至第18行的定义,与上一课练习RECT4.DCL定义相同,不再叙述19以冒号开始,定义一个切换钮组件20切换钮的开大括号,以label属性定义切换钮右边的消息正文21以key属性设定切换钮的操作关键词22关大括号是对应第20行的开大括号,此对大括号同属于第19行的切换钮组件23以冒号开始,定义一个按钮组件24按钮的开大括号,以label属性定义按钮上显示的消息正文.注意 : 字符串的&符号,表示设定在该符号右边的一个字母为快捷键;在显示时,&符号不会出现,但&符号右边的一个字符会以加底线显示25以key属性设定按钮的操作关键词26以width属性设定按钮的阔度,否则按钮会自动加长并占用整列的长度 27fixed_width属性设定为true,使按钮以固定的阔度显示28关大括号是对应第24行的开大括号,此对大括号同属于第23行的按钮组件29至34与上个按钮的定义类似(23至28行),但其label及key的属性值不同35定义一个确定按钮,以结束对话框36关大括号是对应第2行的开大括号,此对大括号同属于第1行的dialog组件续下一课 ....第 18 课 <第四篇 按钮及核取框(切换钮)> (第5节)续上一课 ....程序文件 将RECT4.LSP复制至RECT5.LSP,其程序代码如下:(DEFUN C:RECT() (SETQ DCL_ID (LOAD_DIALOG "C:/RECT5.DCL")) (NEW_DIALOG "RECT" DCL_ID)(SET_TILE "RECT_W" "50.0")(SET_TILE "RECT_H" "25.0")(ACTION_TILE "accept" "(S_RECT)(DONE_DIALOG)")(ACTION_TILE "RECT_E" "(MODE_TILE \"RECT_X\" 0)") ;设定使用按钮的动作(ACTION_TILE "RECT_D" "(MODE_TILE \"RECT_X\" 0)") ;设定禁用按钮的动作(START_DIALOG)(UNLOAD_DIALOG)(SETQ PT_0 (GETPOINT "\nSelect rectangle lower left point : ")) (SETQ PT_1 (POLAR PT_0 0 TMP_W)PT_2 (POLAR PT_1 (/ PI 2) TMP_H)PT_3 (POLAR PT_2 PI TMP_W))(COMMAND "PLINE" PT_0 PT_1 PT_2 PT_3 "C")(IF (= TMP_X 1) (COMMAND"LINE" PT_0 PT_2 "" "LINE" PT_1 PT_3 "")) (PRINC))(DEFUN S_RECT() (SETQ TMP_W (ABS (ATOF (GET_TILE "RECT_W"))) TMP_H (ABS (ATOF (GET_TILE "RECT_H")))TMP_X (ATOI (GET_TILE "RECT_X"))) ;取得切换钮的状态)续下一课 ....第 19 课 <第四篇 按钮及核取框(切换钮)> (第6节)续上一课 ....主程序(RECT)说明:1至5 与程序RECT4.LSP相同,主要是加载及显示对话框,并设定其中的组件 6使用ACTION_TILE函数,设定当按下ENABLE按钮(关键词为RECT_E)时,所执行的动作 : 使用MODE_TILE函数,设定切换钮(关键词为RECT_X)的状态为0,使其处于作用状态.注意指定的动作为字符串型态,前后要加上双引号";而包含在字符串中的双引号,则必须以反斜线加双引号\"表示7与第6行相似,设定按下DISABLE按钮(关键词为RECT_D)时,将切换钮的状态设为1,使其处于禁用状态8至13 与程序RECT4.LSP相同,主要是用作绘画出四边形14使用IF函数检查变量TMP_X(在辅助程序中取得,表示切换钮的状态)是否为1;若是则以COMMAND函数,执行两个LINE指令,绘画出四边形的对角线15以一个不带参数的PRINC函数,抑制多余的显示及传回值;最右边的关括号是对应第1行DEFUN函数左边的开括号辅助程序(S_RECT)说明:1,2大致与RECT4.LSP的辅助程序相同,都是用以取得编辑框内的数据并存入变量中3使用GET_TILE函数取得切换钮(关键词为RECT_X)的状态(传回值是字符串,"0"是使用,"1"是禁用),再用ATOI函数将传回的字符串变为整数,存入变量TMP_X,供主程序第14行的IF函数,判断是否需要加上对角线.注意 : 传回值转型后,结果只会是1或0,固不须使用ABS函数取其绝对值4关括号与1行DEFUN函数左边的开括号对应第 20 课 <第五篇 横列,直行,空白及文字组件> (第1节)横列(row)及直行(column)组件其实这两个都不算是实体的组件,只是用作指定后续的其它组件的排列格式指定为横列时,则包含在此组件一对大括号中的所有组件,均作水平左至右排列;直行时则呈垂直上至下排列若不指定组件的排列格式时,则预设为直行格式若有指定其label属性,则会在外围加上一矩形线框(包含在大括号中间的其它组件则显示在线框中);其属性值则为该线框左上角的标题文字;若不设定则没有线框及标题。
Emacslisp入门--------------------------------------------------------------------------------時間:2004/05/21來源:萧永庆在e macs下建立一个属于自己的l isp王国.最近越来越喜欢上emac s了, 所以忍不住再接再厉,写了以下这篇文章.算是我前一篇文章的延伸.本文假设你对emacs的了解具有emacs TUTO RIAL的基本程度.本文介绍 li sp, 特别是它在e macs下的应用.不假设你有任何程式语言的基础.不要害怕,li sp 是很简单的.它跟人工智慧没有什么关系.花一个星期学lisp, 可能你学到的程式设计技巧,会比别人学C/C++/Ja va一整个学期还要多.看完本文,你将会学到如何调整/设定你的e macs,让它更顺心如意.同时也学到相当程度的lisp程式设计的技巧.Emacs有三份手册.第一份是使用手册, 介绍emacs的各种概念与操作.如果你需要某些ema cs 所提供的功能的话, 就要先参考它. info page: ema cs第二份是Eli sp 手册, 定义e lisp语言, 以及它的功能.其实也是一套完整的lisp介绍. in fo pa ge: e lisp第三份是E lisp简介.第三份的程度是入门级,值得看.同一件事会反覆讲好几次. 所以一定看的懂, 除非你不想看英语.inf o pag e: Em acs-l isp-i ntro.因为我lis p没有正式学过,算是半路出家,所以,以下所言, 如有巧合, 那才是真的.如果有错误,也欢迎指正. Chap ter 1l isp -充满括号的世界.以下每一行都是独立的lisp程式:(+ 1 2)(*1 2 3 4)(* 2 (+ 3 4) 5)(+ (* 3 (+ 1 (- 4 2(+ 34)))))一个lisp程式, 就是由数个这样的括号组成的.一对括号,以及括号里面的内容, 称为一个串列,学名叫li st. 括号的内容, 称为元素, 学名为atom.l isp 就是 LIS t Pro cessi ng 的缩写.lisp的语法很简单,一个程式就是由一堆lis t所组成.我们可以把lis t 和铁链作类比.一个list就是一条铁链, 铁链的每个环就是atom.每个 lis t 的头(就是第一个atom)告诉电脑要作什么事.这跟Unix的命令列差不多, 就像ls -l /et c/pas swdlisp只不过是在这样子的命令外面加一对括号而已.所以, 最前面举的例子, 你应该看懂了它们在做什么吧!对了,每个l ist都有传回值.如果lis t是被套起来的, 那它的传回值就可以被上一层的l ist用.最上层的传回值没人要, 所以电脑就会把它印出来给你看.本章介绍了lis t 和a tom 的观念,和一些简单的lisp程式.Chapt er 2 Ch apter 1, 电脑观点.考虑(+ 12 3 (* 4 5) 6)这个程式码好了. 就第一层括号来说,电脑看到的是 (+1 2 3 X 6)其中X = (* 4 5).电脑怎么知道去算 (* 4 5) 然后把20代入X中呢?你说, 括号优先做嘛!不太对.如果你禀持这个信念,到最后就会发现无法自圆其说.正确的事实是:电脑从 + 开始, 决定把list的尾巴通通加起来. 然后看1,发现它只是个整数,大小为1.然后看2,. . .. . . . 2. .. 3, .. . . . ..3.(* 45) 发现它是个li st, 于是又重头来:list头头是*所以要把尾巴乘起来.然后看 4 发现它是个整数,大小是4然后看 5 发现它是个整数,大小是5然后没有了.所以此lis t的值为20.然后看6 发现是大小为6的整数.然后没有了, 于是可以把尾巴通通加起来.为了显示我们的专业,所以要有一些术语. 上述电脑计算的的过程, 称为"求值".英文叫e valua te. 缩写eval.一个可以执行的list,称为ex press ion,中文叫叙述. [*]换句话说, 执行一个 li sp ex press ion,专业的讲法叫对那个e xpres sion求值. ev aluat e the expr essio n.一个lis t, 我们可以把它看成一条蛇,有个头(第一个元素:还记不记得,叫at om) 然后剩下的就是尾巴(t ail).把lis t区分为head+ tai l是很有用的.再过一下子你就会发现了.[*]其实好像应该所有的list都可以称为expre ssion, 只要合文法就好了.还有一个基本的问题尚未解决, 你有想到吗?为什么电脑知道要对所有lis t的尾巴求值,并且知道lis t的头要跳过去,不用求值,它只代表要执行什么功能而已?这就是电脑对li sp ex press ion求值的固定步骤. 就像喝饮料要先把盖子打开一般, 制式化的步骤. 反正电脑看到这种型式就会这样子做就对了. 这是lisp expr essio n最平常的形式. 型式的英文叫for m, 你可以把它翻成样板也没关系. 电脑知道许多的样板, 它就是对照样版来决定怎么样执行你的程式.本章介绍lis t exp ressi on,e valua tion,head & ta il,f orm.Cha pter3List处理我们延续上一章. Ch apter 2结尾提到 for m. 我们现在以介绍一个sp ecial form作为本章的开头. spei cal f orm,特别的样版, 就是特别嘛, 也就是它求值的方法不是平常像(* . . . )(+ .. . )一样的规则.以下就是此s pecia l for m:(q uoteSYMBO L)q uote是括起来的意思. S YMBOL表示符号.电脑遇到quote这个spe cialform不会对它的SYMBO L求值.这有什么用? 可以用来设变数:(set (quo te a) 100)把一个符号a设值为100.符号(SYMB OL)是lisp里基本的资料型别, 跟list具有一样的地位.一个symb ol几乎可以出现在任何一个li st可以出现的地方.比如说:(set (quo te b) (+ 50 50))(set (quo te c) b)此时b和c都是100.(quote . .)这个fo rm实在太常用了.于是就有个缩写, 就是单引号' (se t 'b100)有没有简洁多了.(se t (qu ote . . .) . .. )也很常用, 所以有第二个speci al fo rm:(setqa 100)se tq是s et qu ote的缩写. 在s etq里面, a不会被求值.(因为我们要把a设为100,a在此之前没有定义. 我们靠speci al fo rm告知电脑,不要对a求值, 解决了鸡蛋问题)有了s etq 和 '我们可以为一个list取个名字.(set q a '(1 23 4 5))此时,a就代表(1 2 3 4 5)Bas ic da ta ty pe字串 (st ring) "Hel lo, W orld"字元(char)?a ; 问号开头atom& lis t: (1 2 3 4)是一个l ist,由 4个atom组成.pair:中间是句点. (app le .2)alis t (as socia ted l ist)就是一堆 pa ir的集合,就像pe rl/tc l的ass ociat ive a rray.或者说是一个资料库,一堆 (k ey, v alue) pair.'((Ap ple . 1)(Oran ge. 2) (P ineAp ple . 3))vect or (?)emacs 19用v ector来表示按键(key stro k seq uence)[f1][f2][f1 a]n il就是空的lis t, 或者表示 fa lset tr ueFo rms我们写程式最好有样版让我们填空最简单了.For m 就是样版, 不过意义不太一样.F orm 就是Elis p 可以接受的句型.lis p 解译器预设是对list的每个元素求值(eva luate),除非是 sp ecial form, 有特殊的定义.比如说(def un FU NC (A RG-LI ST)BOD Y ...)就是一个sp ecial form, 用来定义函式,所以FUN C 不会被求值,被当成s ymbol, ...(q uote(LIST))这也是个s pecia l for m, 叫lisp把 (LI ST)当做symbo l就好了,不要evalu ate.quo te 很常用, 所以有个缩写:'(L IST)等于 (q uote(LIST))'Asymb ol 可以表示一个A tom,名称叫As ymbolse t 可以产生/定义新的变数.(set 'hel lo 1); h ello= 1; 注意我们用'hello, 所以l isp不会evalu ate h ello的值.这家伙很常用, 也有简写.(setq hell o 1)setq就是se t quo te 的缩写. 这是个 spe cialform,不会对第二个元素求值.Eva luati on在Emacs下, C-x C-e可以执行(eval uate,求值)游标左边的叙述.结果会出现在m inibu ffer.lis p-int eract ion-m ode中C-j 可以eval uate,并且把结果appe nd到b uffer. li sp 程式由一堆li st 构成.称为ex press ion.每个exp ressi on 都回传回一个值.有些e xpres sion有副作用,如删掉一个字.(这跟C 的int d elete_char() 意思一样, 它传回int,并且删掉某个char)定义函式:(defun NAME (ARG S-LIS T)"注解"; opti onal(i ntera ctive) ; o ption alBODY)定义一个叫NA ME的函式. BOD Y 是一堆expre ssion.注解是用来给C-h f显示的.(i ntera ctive) 表示这个函示会和user/buffe r作用.(inte racti ve "B") 表示执行此函式先问use r一个bu ffer的名字,然后当作参数传给它. (如,当use r透过ke y-bin ding或者M-x 呼叫此函式时)(in terac tive"BApp end t o buf fer:\nr")问u ser b uffer name时, 提示号 App end t o buf fer:此fu nctio n有两个引数,第一个是B, 就是buff er 第二个是r, reg ion用\n隔开.(inter activ e "p") 用C-u 设的p refix把它当作参数传给我.预设值==4. C-u C-f 向右移四个字一些lis p 函式:(li st 12 3 4)产生 '(12 3 4)(ca r '(1 2 34) 1(c dr '(1 2 3 4) '(2 3 4)(con s 1 '(2 34)) '(12 3 4)(co ns 12)(1 . 2)(con s 0 (cons1(co ns 2nil)))等于'(0 1 2){list是用p air 串起来的,用C 表示: pai r: {O bject *fir st, O bject *sec ond}; *(p air[i].fir st) == i; pair[i].s econd == p air[i+1];}(c ons '(1 2) '(34))'((1 2) 3 4)(se tq a1)(1+ a);a+1(+ 2 a); a+2(* 1 2 34)(curr ent-b uffer); 传回目前bu ffer的资料物件(swit ch-to-buff er (o ther-buffe r))(set-b uffer)(bu ffer-size)(set q cur rent-pos (point))(p oint-min)(poin t-max)(me ssage "Hel lo") ; 在m inibu ffer显示Hell o(if (tes t) (the n-par t) (els e-par t))(cond((tes t1) B ODY1)((test2) BO DY2)(t OTHE R-WIS E)(l et ((var1value); l ocalvaria ble va r2; no v alue(var3value)...)BODY...)(lamb da (A RG-LI ST) ...) 同 defu n, 但是没有名字(anon ymous).可以存到变数去:(se tq he llo (lambd a ()(mess age "Hello,Worl d")))(fun callhello)(go to-ch ar (p oint-max))(def var V AR VA LUE "*注解")如果VA R 不存在才定义.有注解可以用C-h v看. 注解打*号表是使用者可以直接改/这个变数本来就是给使用者设定用的.可以用 M-x edit-opti ons 来线上设定(emac s结束就没有了, 不过ed it-op tions可以给你所有可修改的变数的列表,你可以放到.emacs档内.(dire ctory-file s "./" t "\\..*") re turna lis t offiles unde r dir ector y X(load"xxxx.el")同#in clude <std io.h>(set q loa d-pat h (co ns "~/emac s" lo ad-pa th)); loa d的sea rch p ath.(auto load...)不像loa d会直接e valua te 整个档案, 而是需要时再l oad.(loca l-uns et-ke y [(c ontro l c)])(lo cal-s et-ke y [(c ontro l c)a] 'f orwar d-sex p)se xp 就是一个exp essio n, n个expre ssion如果用括号括起来就算一个.(ex press ion的定义随语言的不同而有不同, 在C, lis ptex, html, for tran下皆有差异)。
AutoLISP入门单元一:AutoLISP主角登场 (2)单元二:AutoLISP的关键、基本结构及语法 (4)单元三:快速分类浏览AutoLISP功能函数(一) (10)单元四:快速分类浏览AutoLISP功能函数(二) (13)单元五:轻松快速的掌握AutoLISP设计技巧 (16)单元六:图元数据的取得与活用技巧(一) (21)单元七:图元数据的取得与活用技巧(二) (25)单元八:新手上路-参数设计的关键技巧 (32)单元一:AutoLISP主角登场一. AutoLISP 是何方神圣?1、AutoLISP是AutoCAD的最佳拍檔!2、AutoLISP内含于AutoCAD软件内,不用另外花钱买!3、AutoLISP是强化AutoCAD最好、最直接的『程序语言』!4、AutoLISP易学、易用,即使不会程序设计的AutoCAD使用者,都能在最短的时间内,写出令人惊讶、赞叹的功能!若说AutoLISP的出现,是替 AutoCAD 创造一片天的『最大功臣』,实不为过一点也不夸张!5、AutoLISP希望您去学习它、改善它、发挥它、享受它.真的!它的威力、魅力无穷!二. AutoLISP 程序语言的特质分析:学习AutoLISP是非常容易的,对初学者而言,即使没有学习过任何的程序语言,都能很快的上手,写出精彩漂亮的AutoLISP程序!语法简单:不用特殊的变量宣告,非常富有弹性,比起其它的程序语言,它的语法可说是非常简单而有其独特的风格!功能函数强大:除一般性的功能函数外,又拥有为数不少控制配合AutoCAD的特殊函数,再加上AutoLISP可直接呼叫执行所有AutoCAD的指令,以及掌握运用所有的AutoCAD系统变量,功能之强大令人欣喜不已!撰写的环境不挑剔:只要是一般的文书编辑软件都适用! 如:Windows的记事本、PE2、PE3、DW3、书中仙、汉书、EDIT....等直译式程序:不用再作编译,『即写即测、即测即用』,马上可以在AutoCAD中响应效果,马上就有成就感!横跨各作业平台:悠然自得,虽然AutoCAD有DOS、Windows版本之分但是AutoLISP却可在不改写的原貌下,加载与执行!三.撰写 AutoLISP 的动机?1、欲强化 AutoCAD 原有指令时.2、欲创造更有用的 AutoCAD 新指令.3、欲简化繁琐的环境设定或绘图步骤时.4、欲处理参数式绘图时.5、欲做图面资料读文件、写文件.6、欲做 AutoCAD 简报展示时.7、欲达到真正灵活掌控 AutoCAD 时.8、欲提升自己跨上 AutoCAD 高手列车时.四.AutoLISP 的效益评估?1. 对公司负责人或设计主管而言:A. 也许某员工或干部花了20个小时撰写一个AutoLISP程序,表面上,这将近三天的时间,他连一张图都没有画,甚至可能偶有发呆、沈思,若此程序一天可以替公司绘图部门节省1小时绘图时间,那算一算,只要20天就抵销开发成本,而20天以后都是赚的,『用的愈久,省的愈多』!B. 若员工皆有此动力,在不影响正常工作,『鼓励』都来不及,那有『压抑』的道理,甚至还要派遣优秀人员出去受训,学习更好的设计技巧与创意呢?!C. 千万不要因为您的不懂或压抑,SHOW您的权威与POWER,如此,不但对员工造成打击,甚至您可能成为阻碍了公司计算机化进步的罪魁祸首D. 当然,若要撰写的程序很多,内部设计人员的程序功力距离太远,达成需求的时间反而变得遥遥无期,那倒不如求助于市面上已有的相关 AutoCAD 支持软件。
Lisp入门教程(刘鑫最新翻译)Common LISP HintsGeoffrey J. Gordon<ggordon@>Friday, February 5, 1993Modified byBruno Haible<haible@ma2s2.mathematik.uni-karlsruhe.de>简体中文版翻译:刘鑫<March.Liu@>Note: This tutorial introduction to Common Lisp was written for the CMU environment, so some of the details of running lisp toward the end may differ from site to site.注意:这份 Common Lisp 入门教程是针对 CMU环境编写,所以在其它环境运行LISP时可能会有细节上的区别。
Further Information附:The best LISP textbook I know of isGuy L. Steele Jr. _Common LISP: the Language_. Digital Press. 1984.据我所知最好的 Lisp 书籍是:Guy L. Steele Jr. _Common LISP: the Language_. Digital Press. 1984.The first edition is easier to read; the second describes a more recent standard. (The differences between the two standards shouldn't affect casual programmers.)第一版很容易阅读,第二版介绍了更新的标准。
一.Lisp基础知识二.对话框基础一.基本知识第1节--------------------------------------------------------------------------------基本知识AutoLISP是一种针对扩充及自订AutoCAD函数机能而产生,以LISP为基础的程序设计语言.LISP本身于50年代末期出现,是一种擅于处理串行文字(List of Processing),属第四代「人工智能(Artificial Intelligence)」的计算机语言.目的是令使用者充份利用AutoCAD进行开发,直接增加及修改AutoCAD指令.AutoLisp语言建基于普通的LISP语言上,并扩充了许多适用于CAD的特殊功能而形成.是一种能以直译方式(不须先行编译)亦可于AutoCAD内部执行的直译性程序语言.程序容易学习及撰写,程序即使出错亦不会对操作系统(如DOS,WINDOWS)有不良影响.数据及程序均统一以串行 (List)结构表示.可直接调用几乎全部的AutoCAD命令.既具备一般高级语言的基本结构和功能,亦有一般高级语言没有的强大图形处理能力.内建于AutoCAD应用程序,不须另行购买;亦不须使用特定的编辑器或开发环境.可配合AutoCAD提供的PDB,建立DCL(Dialog Control Language)文件创建对话框.缺点 : 执行速度较ObjectArx(旧称ARX,以C或C++程序开发,取代以前的ADS)程序慢;原程序不易保护;对低阶的硬件数据不易存取.第2节--------------------------------------------------------------------------------函数 (Function)在AutoLISP程序语言中所有的成份都是以函数的形式出现,AutoLISP程序就是顺序执行连串的函数.函数的运行过程就是对函数的求值(结果)过程;函数的基本语法如下:(函数名称参数1 参数2....)e.g. (PRINC "AutoLISP Programming")每一个完整的函数必须包在一对小括号( )内,左边为开括号,右边为关括号;如有若干数量的开括号,则一定有同等数量的关括号对应.左边开括号后紧随函数名称.函数名称与参数之间,或参数与参数之间须最少留一个空格.第3节--------------------------------------------------------------------------------数据型态 (Data Type)整数 (INT)没有小数字的数值,32位有号数,范围从+2,147,483,647到-2,147,483,648实数 (REAL)带小数字的数值,以倍精度浮点格式储存(最少14位小数) e.g. 12.5当数值在1与-1之间时,必须加上前导零 e.g. 0.05可以科学记号表示 : 在E或e后加上次方值 e.g. 4.1e-6字符串 (STR)一般文字,其前后必须加上双引号" e.g. "AutoCAD"控制字符或脱逸码必须为小写,且须在字符前加上反斜线 \ e.g. "\AutoCAD"像素名称 (ENAME)是指定给图文件内对象的指针(Pointer,为16进位的数字卷标)e.g. <Entity name:14e5180>像素名称在图文件内是唯一的,不会重复对象的像素名称只在目前作业中有效,再开启图档时,会指定新的像素名称予该对象档案 (FILE)以OPEN函数所开启档案的指针,作为其它函数(读写该档案)的自变量选集 (PICKSET)用SSGET等函数建立的一个或多个对象的集合或群组转化 (V ARIANT)可将像素名称转换为可与ActiveX配搭使用的VLA-Object对象符号 (SYM)用以储存静态数据的名称;例如内建或使用者定义的函数符号名称不分大小写,可由任意长度的可打印字符组成;但下列的字符除外:左括号( 右括号 ) 句点 . 单引号' 双引号 " 分号 ;表 (LIST)亦称为串行,是放在一对小括号 ( ) 内,一个或多个元素的有序集合e.g. (1.0 "Lisp" ( ) (5.6 7))元素可以是字符串,符号,整数或实数;也可以是另一个表元素与元素之间要用空格隔开,但元素与小括号之间则可以不隔空格为便于存取表内各元素,每个元素均有其序号;从表的左边开始,第一个元素序号为0,依此类推表的大小即为其顶层元素的数量(内层嵌套式的表,视为单一元素)点对(Dotted Pair)亦是表的一种;表内有2个元素,中间以一圆点分隔,且元素与圆点之间亦须以空格分开若表内没有任何元素,称为空串行或空表;以 ( ) 或 (NIL) 表示第4节--------------------------------------------------------------------------------变数 (Variable)为程序执行中动态储存数据的符号名称;主要分为2类:变量名称与符号的限制相同,使用时宜采用有意义及易于辨别的名称变量在赋值或使用前无须先行设定相同的变量可以储存不同型态的数据(但同一时间内只可储存一种型态)在指定新的数据之前,变量储存的内容会保持不变赋值将数据给予指定的变量储存以内建函数SETQ进行(可用于绘图模式的指令行或AutoLISP程序),其语法如下:(SETQ 变量名称1 资料1 [变量名称2 资料2 ....] )e.g. (SETQ NAME "David" AGE 37 WEIGHT 72.5 POINT (LIST 10 20))在函数名称之后,各参数以两个一组,每组左边为变量名称,右边为存入变量的数据亦可将变量名称赋以空值(NIL) :e.g. (SETQ OCCUPATION NIL)要显示变量所储存的数据,可以使用内建函数PRINC(可用于绘图模式的指令行或AutoLISP程序),其语法如下 : (PRINC 变量名称 )e.g. COMMAND : (PRINC NAME) Result : David"David"在绘图模式中,亦可于指令行中使用感叹号 ! 来显示变量内容,或作为指令选项的输入值;语法如下 : !变量名称e.g. COMMAND : !NAME Result : "David"在Visual LISP的主控台窗口中,于提示符号 _$ 后键入要显示的变量名称_$变量名称e.g. _$NAME要检查变量所储存的数据型态,可使用内建函数TYPE;语法如下:(TYPE 变量名称)e.g. COMMAND : (TYPE NAME) Result : STR若检查的变量没有储存数据,则会传回NIL第5节--------------------------------------------------------------------------------练习 (Exercises)将四个坐标分别存入四个变量中,并以LINE或PLINE指令,配合四个坐标变量,画出正四边形.COMMAND : (SETQ POINT1 (LIST 0 0) POINT2 (LIST 0 10) POINT3 (LIST 10 10) POINT4 (LIST 10 0)) COMMAND : LINE ;直线段指令COMMAND : !POINT1 ;第一点(左下角起点)COMMAND : !POINT2 ;第二点(左上角)COMMAND : !POINT3 ;第三点(右上角)COMMAND : !POINT4 ;第四点(右下角)COMMAND : C ;自动联机至起点以关闭四边形画圆 : 将圆心坐标及半径长度分别存入两个变量中(变量名称及数据型态自订)COMMAND : (SETQ CEN (LIST 0 0) RAD 20) ;将圆心点设为坐标0,0;半径为20COMMAND : CIRCLE ;执行划圆指令Specify center.... : !CEN ;在提示后以变量CEN响应输入Specify radius.... : !RAD ;在提示后以变量RAD响应输入将不同型态的数据,分多次存入相同的变数内;每次均以PRINC及TYPE函数显示变量内容及其数据型态COMMAND : (SETQ TEMP 1.2) ;将实数1.2存入变数TEMPCOMMAND : !TEMP Result : 1.2COMMAND : (TYPE TEMP) Result : REALCOMMAND : (TYPE TEMP) Result : STR二数值资料第1节--------------------------------------------------------------------------------基本运算加函数(+ [数值参数1 数值参数2 ....] )e.g. (+ 2.5 4 6) Result : 12.5函数的结果为各参数之总和若仅提供一个参数,则以0加上此参数的结果为返回值若没有提供任何参数则传回0;各参数须为整数或实数型态若所有参数均为整数,结果亦为整数;若其中一个参数为实数型态,结果会转换为实数减函数(- [数值参数1 数值参数2 ....] )e.g. (- 10 2 3) Result : 5结果为第一个(最左边)参数减去其右边各参数的总和若只提供一个参数,返回值为0减去该参数的结果若没有提供任何参数则传回0;各参数须为整数或实数型态若所有参数均为整数,结果亦为整数;若其中一个参数为实数型态,结果会转换为实数乘函数(* [数值参数1 数值参数2 ....] )e.g. (* 2 3 4) Result : 24结果为所有参数的乘积若只提供一个参数,则返回值为该参数乘以1的结果若没有提供任何参数则传回0;各参数须为整数或实数型态若所有参数均为整数,结果亦为整数;若其中一个参数为实数型态,结果会转换为实数除函数(/ [数值参数1 数值参数2 ....] )e.g. (/ 24 2 3) Result : 4结果为第一个(最左边)参数除以其右边各参数的乘积若仅提供一个参数,则返回值为该参数除以1的结果若没有提供任何参数则传回0;各参数须为整数或实数型态若所有参数均为整数,结果亦为整数;若其中一个参数为实数型态,结果会转换为实数注意 : 在本篇教程中,各函数的数值参数,均可以变量(储存值只可以是整数或实数,且不可以是空值 nil)取代第2节--------------------------------------------------------------------------------练习 (Exercises)计算式 (2+4)*3COMMAND : (* 3 (+ 2 4)) Result : 18计算式 (50-8*5)/4COMMAND : (/ (- 50 (* 8 5)) 4) Result : 2注意 : 上式的正确答案应是2.5,因为函数中的各参数均为整数,所以传回的结果亦为整数递增及递减递增(1+ 数值参数 )e.g. (1+ 2) Result : 3递减三角函数 (Trinagular Function)正弦值(SIN 弧度参数)e.g. (SIN 1) Result : 0.841471余弦值(COS 弧度参数)e.g. (COS 1) Result : 0.540302反正切值(ATAN 弧度参数)e.g. (ATAN 1) Result : 0.785398第3节--------------------------------------------------------------------------------其它数值处理次方值(EXPT 数值参数次方值 )e.g. (EXPT 2 4) Result : 16若参数及次方值两个均为整数,返回值亦是整数;若其中一个为实数,结果为实数开方根(SQRT 数值参数 )e.g. (SQRT 30) Result : 5.47723绝对值(ABS 数值参数 )e.g. (ABS -123) Result : 123余数(REM [数值参数1 数值参数2 ....] )e.g. (REM 50 26 5) = (REM (REM 50 26) 5) Result : 4将参数1整除参数2的余数若参数多于2个时,则会将余数再整除下一个参数,再得出余数;依此类推若其中一个参数为实数时,则结果为实数;否则为整数最大公约数(GCD 数值参数1 数值参数2 )e.g. (GCD 81 57) Result : 3两个参数均必须为整数值型态自然对数(LOG 数值参数 )e.g. (LOG 3.5) Result : 1.25276是EXP函数的反函数;传回值为实数型态自然反对数(EXP 数值参数 )e.g. (EXP 1.25276) Result : 3.49999是LOG函数的反函数;传回值为实数型态第4节--------------------------------------------------------------------------------数值资料转型实数转整数只会截去小数部份(小数字不会4舍5入)整数转实数(FLOAT 数值参数 )e.g. (FLOAT 12) Result : 12.0整数转字符串(ITOA 数值参数 )e.g. (ITOA -17) Result : "-17"数值转字符串(RTOS 数值参数[模式[小数字] ] )e.g. (RTOS 17.23333 2 3) Result : 12.266若不设定模式,则依系统变量 LUNITS 的设定值转换数值为字符串若不设定小数字,则依系统变量 LUPREC 的设定值转换模式设定值可以是下列数值之一 :1 = 科学记号2 = 十进制3 = 英呎及十进制英吋4 = 英呎及分数位英吋5 = 分数当选用的模式为3,4或5,则传回的字符串受系统变量UNITMODE影响弪度转字符串(ANGTOS 角度参数[模式[小数字] ] )e.g. (ANGTOS 0.785398 0) Result : "45"e.g. (ANGTOS 0.785398 4) Result : "N 45d E"若不设定模式,则依系统变量AUNITS的设定值转换数值为字符串若不设定小数字,则依系统变量AUPREC的设定值转换模式设定值可以是下列数值之一 :0 = 度1 = 度/分/秒2 = 分度量3 = 弪度4 = 土地测量单位当选用的模式为4,则传回的字符串受系统变量UNITMODE影响反函数为ANGTOF;参阅第5篇教程第5节--------------------------------------------------------------------------------数值资料检查数值(NUMBERP 数值参数 )e.g. (NUMBERP -3.45) Result : Te.g. (NUMBERP "AutoLISP") Result : nil注意 : 在范例的传回值中,T表示函数的结果为真(成立),nil表示结果为假(不成立) 负数值(MINUSP 数值参数 )e.g. (MINUSP -3.45) Result : Te.g. (MINUSP 0) Result : nile.g. (MINUSP 3.45) Result : nil零值e.g. (ZEROP 3.45) Result : nil其它应用最大值(MAX [数值参数1 数值参数2 ....] )e.g. (MAX -88 5 2) Result : 5若没有提供任何参数,则传回值为0最小值(MIN [数值参数1 数值参数2 ....] )e.g. (MIN -88 5 2) Result : -88若没有提供任何参数,则传回值为0第6节--------------------------------------------------------------------------------练习 (Exercises)计算下列算式 :(+ 1234567890 1234567890) Result : -1825831516上式中两个数值参数均为整数,而结果值大于整数型态所能容许之范围;固导致发生溢位问题,产生无效的结果.修正算式如下 : 只要将其中一个参数改为实数型态即可.(+ 1234567890.0 1234567890) Result : 2.46914e+009计算下列算式 :(+ 9876543210 1234567890) Result : 1.11111e+010上式中两个数值参数均为整数,但其中一个(第一个)参数巳大于整数型态所能容许之范围;系统会自动将此参数先行转为实数型态才计算.计算下列算式 :(FIX (SQRT (+ 1 (MAX 20 10 40 30)))) Result : 6---- 最先执行的是最内层的算式(MAX 20 10 40 30) ,求出最大值为40---- 其次执行加函数,将MAX函数所得的最大值加1,结果为41---- 再利函数SQRT,将41开方根,结果为6.4031---- 最后使用FIX函数,截去其小数字,得到最后的结果为6三程序设计第1节--------------------------------------------------------------------------------使用者定义函数是将一群表示式组合成一个函数或指令可应用于绘图模式的指令行提示,Visual LISP主控台,或供其它自定义函数内的表示式呼叫使用AutoLISP原始程序代码均以纯文字格式存盘,扩展名为LSP(2000版可编译成扩展名为FAS的档案可以一般文字编辑器进行开发,如DOS的EDIT,WINDOWS的WORD或WORDPAD等一个自定函数内最少要有一个表达式在原程序文件(LSP)里,自定义函数以DEFUN函数开始;其语法如下 :(DEFUN [C:] 函数名称 ( [自变量串行 ...] [/ 局部变数串行 ...] ) 表达式 ...)在呼叫带有自变量的自定函数时,必须同时提供与定义函数时,同等数量的参数,使各参数传入自定函数的各自变量中自变量被视为一种特殊类型的局部变量,无法用于该自定函数以外的其它函数若自定函数中无须设定任何自变量,亦必须以空串行 ( )加在函数名称之后若有提供局部变量,必须以斜线 / 加在局部变量的开头(即使前面没有自变量串行)各自变量,斜线,局部变量之间要以空格分隔;但与左右小括号之间则不须以空格分开若自变量串行中有相同名称的自变量出现,则会忽略第一个以后的相同自变量;变数亦是一样若在函数名称前没有加上C:,在指令行提示下,必须将函数名称包在一对小括号中才可执行不可以在执行一自定函数时,以通透方式执行另一自定函数第2节--------------------------------------------------------------------------------加载程序自定函数在使用前,都要将其所在的程序文件(扩展名为LSP)加载才可执行ACAD.LSP程序文件(预设在SUPPORT子目录内)会在启动AutoCAD时自动加载(LOAD "程序文件名称" [加载失败] )e.g. (LOAD "TEST")若程序文件之文件名为LSP,则在程序文件名称之后,可以不加上扩展名若有需要,系统会顺序尝试其它的扩展名 : VLX FAS LSP若程序文件不在系统的支持目录下,则需在文件名前加上目录路径注意 : 必须以正斜线 / 或两个反斜线 \\ 作为目录的分隔符可以在加载失败的参数中提供字符串,以供加载失败时显示;亦可提供有效的自定函数,该函数在加载程序文件失败时会被执行e.g. (LOAD "TEST" "Load Fail") 或 (LOAD "TEST" (DOERROR))注意 :在程序文件加载后,在提示行显示的返回值,一般是该程序文件中,最后被定义的函数名称或是在程序文件内没有包含在自定函数中,最后一个表达式的执行结果第3节--------------------------------------------------------------------------------练习 (Exercises)启动文字编辑器,编写一AutoLISP程序作两个同心圆(第1个圆半径为50,第2个圆半径为80),程序代码如下所示 : (DEFUN C: 2CIRCLE () (SETQ CEN (LIST 0 0) RAD 50)(COMMAND CIRCLE CEN RAD)(COMMAND CIRCLE CEN (+ RAD 30)))---- 输入后以纯文字格式存盘(C:\TEST.LSP)---- 在AutoCAD绘图模式的指令行提示后,用LOAD函数将程序文件加载COMMAND : (LOAD "C:/TEST")---- 在指令行提示后,输入程序(函数)名称执行COMMAND : 2CIRCLE程序说明1 使用DEFUN建立自定函数的名称,并用SETQ函数将中心点(LIST 0 0)存入变数CEN,半径(50)存入变数RAD中2 使用COMMAND函数执行AutoCAD内建指令CIRCLE,并以变量CEN(圆的中心点)及变数RAD(圆的半径)回应3 与第2行大致相同,但在指定其半径时,先将储存半径的变量加30,使划出半径为80的圆;注意最右边的关括号,与第1行DEFUN左边的开括号是一对的启动文字编辑器,开启TEST.LSP程序文件,复制2CIRCLE至新程序2C,并改为传入自变量方式执行;程序代码如下 : (DEFUN 2C (CEN RAD) (COMMAND CIRCLE CEN RAD)(COMMAND CIRCLE CEN (+ RAD 30)))---- 输入后以纯文字格式存盘---- 在AutoCAD绘图模式的指令行提示后,用LOAD函数将程序文件重新加载---- 在指令行提示后,输入程序(函数)名称执行COMMAND : (2C (LIST 0 0) 50)第4节--------------------------------------------------------------------------------表示在分号右边(同一行)的字符均为批注,程序执行时会将其忽略多行批注;| |;表示在两个批注符号中间所有字符皆为批注,即使字符跨越多行关系运算在各个关系运算中,都会传回一逻辑值;若关系成立,传回 T,否则会传回 nil各参数可以是字符串,整数或实数型态;若以字符串进行比较,则会以字符串的ASCII码为准若函数中只有一个参数,传回值恒为 T等于函数(= 参数1 [参数2 ....] )会将参数1与其后各个参数比较,若全部相等则传回 T,否则传回 nil e.g. (= 2 2.0) Result : Te.g. (= "A" CHR(65)) Result : T不等于函数(/= 参数1 [参数2 ....] )若参数1不等于其后任何一个参数,即传回T e.g. (/= 1 2.0) Result : Te.g. (/= "a" CHR(65)) Result : Te.g. (/= 10 30 40 10 20) Result : T小于函数(< 参数1 [参数2 ....] )各参数顺序以2个为一组比较,若各组左边的参数均小于右边的参数,即传回 Te.g. (< 1 2) Result : Te.g. (< "a" CHR(65)) Result : T大于函数(> 参数1 [参数2 ....] )各参数顺序以2个为一组比较,若各组左边的参数均大于右边的参数,即传回 Te.g. (> 1 2) Result : nile.g. (> "a" CHR(65)) Result : nil小于或等于函数(<= 参数1 [参数2 ....] )各参数顺序以2个为一组比较,若各组左边的参数均小于或等于右边的参数,即传回 Te.g. (<= 1 2) Result : Te.g. (<= 2 2) Result : Te.g. (<= "a" CHR(65)) Result : T大于或等于函数(>= 参数1 [参数2 ....] )各参数顺序以2个为一组比较,若各组左边的参数均大于或等于右边的参数,即传回 Te.g. (>= 1 2) Result : nile.g. (>= 2 2) Result : Te.g. (>= "a" CHR(65)) Result : nil第5节--------------------------------------------------------------------------------逻辑运算且运算(AND [表达式 ....] )若各表达式的传回值均为 T,函数即返回 T 值;若其中一个传回值为 nil,函数传回 nil(OR [表达式 ....] )若各表达式的传回值均为 nil,函数即返回 nil 值;若其中一个传回值为 T,函数传回 Te.g. (OR (> 1 2) (> 8 5)) Result : T否定运算(NOT 表达式 )若表达式的传回值为 T,函数即返回 nil 值;相反若表达式传回值为 nil,函数传回 T可用于检查传回值是否为 nil另有一NULL函数与NOT函数功能相似e.g. (NOT (< 1 2)) Result : nil练习 (Exercises)试求出50减25,与625的开方根值是否相等COMMAND : (= (- 50 25) (SQRT 625)) Result : T设计一简单程序(名称为AIR),在呼叫程序时,检查传入的数值自变量(为空气污染指数)是否大于200(即严重空气污染)---- 启动文字编辑器,开启TEST.LSP程序文件,输入下列程序代码 :(DEFUN AIR (NUM) (> NUM 200))---- 输入后存盘(纯文字格式)---- 在AutoCAD绘图模式的指令行提示符号后,使用LOAD函数重新加载程序文件COMMAND : (LOAD "C:/TEST")---- 在AutoCAD绘图模式的指令行提示符号后,输入自定函数名称及参数执行COMMAND : (AIR 175) Result : nilCOMMAND : (AIR 215) Result : T四流程控制第1节--------------------------------------------------------------------------------条件判断是利用条件函数,配合关系及逻辑运算所设定的一些准则,令程序自行分析,因应情况作出适当行动.单一条件(IF 条件表达式是表达式[否表达式] )函数先检查条件表达式,若其传回值为 T,便会执行其后的是表达式若有提供否表达式,且条件表达式的传回值为 nil,函数将不会执行(跳过)是表达式而执行否表达式若没有提供否表达式,且条件表达式的传回值为 nil时,函数将不作任何事情IF函数可以巢状方式嵌套,即在是或否的表达式中加入另一个IF函数练习 (Exercises)判断空气污染指数 : 大于100 = Very High, 51至100 = High, 26至50 = Medium, 25或以下 = Low---- 启动编辑器,开启C:/TEST.LSP程序文件;新增AIR-1自定函数,程序代码如下 :(DEFUN AIR-1 (NUM) (IF (> NUM 100) (PRINC "Very High"))(IF (AND (> NUM 50) (<= NUM 100)) (PRINC "High"))(IF (AND (> NUM 25) (<= NUM 50)) (PRINC "Medium"))(IF (<= NUM 25)) (PRINC "Low"))程序说明1 设定函数名称,并将数据存入自变量NUM内;用IF函数判断变量NUM是否大于100;若是则显示字符串Very High 响应2 用IF函数判断变量NUM是否大于50且(AND)小于或等于100;若是则显示High响应3 用IF函数判断变量NUM是否大于25且(AND)小于或等于50;若是则显示Medium4 用IF函数判断变量NUM是否小于或等于25;若是则显示Low5 是一个没有提供任何自变量的PRINC函数;用以抑制显示答案时尾部符加的 nil 或重复的传回值;而最右一个关括号,是用以对应第1行最左边的开括号IF函数的巢状练习 : 修改上一课的程序练习,将多个IF函数合并成巢状嵌套---- 启动文字编辑器,开启C:/TEST.LSP程序文件---- 新增程序AIR-2,其程序代码如下 :(DEFUN AIR-2 (NUM) (IF (> NUM 50) (PRINC (IF (> NUM 100) "Very high" "High"))(PRINC (IF (> NUM 25) "Medium" "Low")))(PRINC))程序说明1 设定函数名称,并将数据存入自变量NUM内;用IF函数判断变量NUM是否大于50;若条件成立(变量NUM大于50)时,再用另一个IF函数判断变量是否大于100;若条件成立(变量NUM大于100)时,使用PRINC函数显示字符串Very High,否则显示High2 若在第1个IF函数判断中,条件不成立(变量NUM不大于50)时;再用另一个IF函数判断变量是否大于25;若条件成立(NUM大于25)时,显示字符串Medium,否则显示字符串Low3 是一个没有提供任何自变量的PRINC函数;用以抑制显示答案时尾部符加的 nil 或重复的传回值;而最右一个关括号,是用以对应第1行最左边的开括号注意 :第1行最后一个关括号是对应前面的PRINC函数,尾2的关括号则是对应IF函数(判断NUM是否大于100) 第2行最后一个关括号是对应第1行的IF函数(判断NUM是否大于50),尾2的关括号则是对应PRINC函数,尾3的关括号则是对应IF函数(判断NUM是否大于25)最右边的关括号是对应第1行最左边的开括号PROGN 函数在以上各范例中,执行的表达式均为单一的函数运算;若要在表达式中顺序执行一连串的函数,便要将各函数包含在一个PROGN函数内;函数的传回值会是该PROGN函数中,最后一个表达式的运算结果---- 修改TEST.LSP程序文件的AIR-1程序,第1个IF函数如下,其余的IF函数请自行修改e.g. (IF (> NUM 100) (PROGN (SETQ DISP "Very High") (PRINC DISP)))注意 : 最后一个关括号是对应前面的IF函数(判断变量NUM是否大于100)尾2的关括号是对应PROGN函数(用以包含SETQ及PRINC函数)尾3的关括号是对应PRINC函数的第2节--------------------------------------------------------------------------------条件判断多重条件(COND [ (条件表达式是表达式) ....] )函数会顺序检查各条件表达式;直到其中一个条件成立(传回 T),即执行该条件式所对应的是表达式每个条件表达式只对应一个是表达式,而没有否表达式若条件式成立且执行对应的是表达式后,则不会再对余下的其它条件表达式进行检查若只有条件表达式而没有对应之是表达式,则只会传回条件表达式的逻辑值若没有提供任何条件表达式及是表达式,函数传回值恒为 nil练习 (Exercises)新增程序AIR-3,以改善上一课AIR-1程序;用一个COND函数判断多个条件表达式DEFUN AIR-3 (NUM) (COND((> NUM 200) (PRINC "Severe"))((> NUM 100) (PRINC "Very High"))((> NUM 50) (PRINC "High"))((> NUM 25) (PRINC "Medium"))((> NUM 0) (PRINC "Low"))(T (PRINC "Cannot Check")))(PRINC))程序说明1 设定函数名称,并将数据存入自变量NUM内;用COND函数进行多重判断2 判断变量NUM是否大于200,若条件成立,则显示 Severe 讯息;第3至6行依此类推7 注意条件式为一个 T 字母,表示条件式恒为真(成立),显示讯息 Cannot Check作用是当以上各条件式均不成立时(变量小于或等于0),即执行此一表达式第3节--------------------------------------------------------------------------------循环 (Loop)配合条件判断,关系及逻辑运算,令程序不断重复一些动作,以提高效率及减少重复动作时的人为错误可以多个循环形成巢状(嵌套式)循环,即在一个循环内嵌套另一个(或多个)循环指定的重复次数必须为正整数,亦可以是储存正整数的变量名称重复指定次数(REPEAT 重复次数[表达式 ....] )e.g. (REPEAT 10 (PRINC "David")) ;重复显示David字符串10次重复(WHILE 条件表达式[是表达式 ....] )若条件表达式的传回值为 T,即会顺序执行函数内各表达式各表达式顺序执行完后,程序会返回函数的开头,重新检查条件表达式的传回值若条件表达式的传回值为 nil,函数内各表达式将不会被执行e.g. (SETQ COUNT 1) ;将1存入变数COUNT(WHILE (<= COUNT 10) ;WHILE函数并检查变量COUNT是否<=10(PRINC "David") ;若条件成立则以PRINC函数显示David字符串(SETQ COUNT (1+ COUNT))) ;变量COUNT递增1,并将新值重新存入变量COUNT中取代原值注意 : 第4行最右边的关括号,是对应第2行WHILE函数的开括号无限循环又称为死循环,即循环的条件判断式传回值恒为 T,令循环不断重复而无法结束;在上例中 :---- 若WHILE函数的条件表达式设定为 (T) ;即条件永远成立---- 不作SETQ函数,或不将变量COUNT递增;变量COUNT储存值恒久不变,导致条件式永远成立第4节--------------------------------------------------------------------------------练习 (Exercises)编写一程序SUM并将自变量存在NUM变量内,计算1+2+3+4 ....至变数NUM的总和(DEFUN SUM (NUM) (SETQ COUNT 1 TOTAL 0)(WHILE (<= COUNT NUM)(SETQ TOTAL (+ TOTAL COUNT)COUNT (1+ COUNT)))(PRINC TOTAL) (PRINC))程序说明1 设定函数SUM并将自变量存入变量NUM,设定变量COUNT以将数目由1开始递增,变量TOTAL(储存总和)初始值为02 WHILE循环函数,并设定进入循环的条件式(变量COUNT小于或等于变量NUM)3 若条件成立即进入循环内部,先将变量TOTAL加上变量COUNT,再用SETQ函数存回变量TOTAL中,覆盖原值4 将变量COUNT递增1,存回变数COUNT并覆盖原值5 关括号与第2行的WHILE函数左边的开括号对应6 循环结束后,用PRINC函数显示变量TOTAL(总和)的内容程序流程假设执行程序时传入变量NUM的数值为10---- 变数初始值 COUNT = 1 TOTAL = 0---- 判断变量COUNT是否<=变量NUM COUNT = 1 TOTAL = 0---- 变量COUNT(现值1)小于NUM,进入循环;将TOTAL(现值0)加上COUNT,存回变数TOTAL COUNT = 1 TOTAL = 1---- 变数COUNT(现值1)递增1变为2,存回变数COUNT COUNT = 2 TOTAL = 1---- 返回WHILE函数的开头,重新判断条件式---- 变量COUNT(现值2)小于NUM,进入循环;将TOTAL(现值1)加上COUNT,存回变数TOTAL COUNT = 2 TOTAL = 3---- 变数COUNT(现值2)递增1变为3,存回变数COUNT COUNT = 3 TOTAL = 3---- 返回WHILE函数的开头,重新判断条件式---- 变量COUNT(现值3)小于NUM,进入循环;将TOTAL(现值3)加上COUNT,存回变数TOTAL COUNT = 3 TOTAL = 6部份过程省略---- 返回WHILE函数的开头,重新判断条件式---- 变量COUNT(现值10)仍等于NUM,进入循环;将TOTAL(现值45)加上COUNT,存回变数TOTAL COUNT = 10 TOTAL = 55---- 变数COUNT(现值10)递增1变为11,存回变数COUNT COUNT = 11 TOTAL = 55---- 返回WHILE函数的开头,重新判断条件式---- 变量COUNT(现值11)巳大于NUM(本范例假设为10),条件判断不成立,循环结束 COUNT = 11 TOTAL = 55---- 显示变量TOTAL的现存值,程序结束尝试用IF函数检查输入的自变量是否小于或等于0;若条件成立则不执行余下的程序(DEFUN SUM (NUM) (IF (<= NIM 0) (PRINC "Input Error")(PROGN略过 WHILE 及 PRINC 函数))(PRINC))程序说明。
Lisp⼊门教程Lisp ⼊门教程作者:Geoffrey J. Gordon 1993/02/05 星期五修订:Bruno Haible翻译:刘鑫整理:张泽鹏 2011/06/24 星期五注意:这份 Common Lisp ⼊门教程是针对 CMU 环境编写,所以在其它环境运⾏ Lisp 时可能会有细节上的区别。
附:据我所知最好的 Lisp 书籍是:Guy L. Steele Jr. 《Common LISP: the Language》 Digital Press. 1984.第⼀版很容易阅读,第⼆版介绍了更新的标准。
(两个标准的差异很⼩,对于粗⼼的程序员没有什么区别。
)我还记得 Dave Touretsky 写了⼀本,不过我从来没读过,所以不能对那本书发表评论。
Symbols符号仅仅是字符串。
你可以在符号中包含字母、数字、连接符等等,唯⼀的限制就是要以字母开头。
(如果你只输⼊数字,最多再以⼀个连接符开头的话,LISP会认为你输⼊了⼀个整数⽽不是符号。
)例如:接下来我们可以做些事情。
(">"标记表⽰你向LISP输⼊的东西,其它的是LISP 打印返回给你的。
";"是LISP的注释符:";"后⾯的整⾏都会被忽略。
)有两个特殊的符号, t 和 nil 。
t 的值总是定义为 t,nil 的值总是定义为 nil 。
LISP⽤ t 和 nil 代表 true 和false。
以下是使⽤这个功能的 if 语句,后⾯再做详细说明:最后⼀个例⼦看起来很怪,但是没有错:nil 代表 false ,其它任意值代表 true。
(为了代码清晰,在没有什么特别原因的情况下,我们⽤t代表true。
)t 和 nil 这样的符号被称为⾃解析符号,因为他们解析为⾃⾝。
⾃解析符号称为关键字;任⼀以冒号开头的符号都是关键字。
(下⾯是⼀些关键字的应⽤)如下所⽰:Numbers数值类型是数字⽂本,可能会以 + 或 - 开头。
Lisp 入门教程作者:Geoffrey J. Gordon <ggordon@> 1993/02/05 星期五修订:Bruno Haible <haible@ma2s2.mathematik.uni-karlsruhe.de>翻译:刘鑫 <March.Liu@>整理:张泽鹏 <redraiment@> 2011/06/24 星期五注意:这份 Common Lisp 入门教程是针对 CMU 环境编写,所以在其它环境运行 Lisp 时可能会有细节上的区别。
附:据我所知最好的 Lisp 书籍是:Guy L. Steele Jr. 《Common LISP: the Language》 Digital Press. 1984.第一版很容易阅读,第二版介绍了更新的标准。
(两个标准的差异很小,对于粗心的程序员没有什么区别。
)我还记得 Dave Touretsky 写了一本,不过我从来没读过,所以不能对那本书发表评论。
Symbols符号仅仅是字符串。
你可以在符号中包含字母、数字、连接符等等,唯一的限制就是要以字母开头。
(如果你只输入数字,最多再以一个连接符开头的话,LISP会认为你输入了一个整数而不是符号。
)例如:接下来我们可以做些事情。
(">"标记表示你向LISP输入的东西,其它的是LISP 打印返回给你的。
";"是LISP的注释符:";"后面的整行都会被忽略。
)有两个特殊的符号, t 和 nil 。
t 的值总是定义为 t,nil 的值总是定义为 nil 。
LISP用 t 和 nil 代表 true 和false。
以下是使用这个功能的 if 语句,后面再做详细说明:最后一个例子看起来很怪,但是没有错:nil 代表 false ,其它任意值代表 true。
(为了代码清晰,在没有什么特别原因的情况下,我们用t代表true。
)t 和 nil 这样的符号被称为自解析符号,因为他们解析为自身。
自解析符号称为关键字;任一以冒号开头的符号都是关键字。
(下面是一些关键字的应用)如下所示:Numbers数值类型是数字文本,可能会以 + 或 - 开头。
实数和整数很相像,但是它带有小数点,还可能写成科学计数法。
有理数就像是两个整数之间带有一个/。
LISP支持复数,写为#c(r i)(r表示实部,i表示虚部)。
以上统称为数值。
下面是一些数值:标准的计算函数包括:+, -, *, /, floor, ceiling, mod, sin, cos, tan, sqrt, exp, expt 等等。
所有这些函数都可以接受任意数值类型参数。
+、-、* 和 / 返回尽可能大的类型:一个整数加一个有理数返回有理数,一个有理数加一个实数是一个实数,一个实数加一个复数是一个复数。
如下所示:对于整数来说,唯一的大小限制就是机器的内存。
当然大数值运算(这会调用大整数)可能会很慢。
(因此我们可以计算有理数,尤其是小整数和浮点数的比较运算)Consescons 就是一个包含两个字段的记录。
出于历史原因,两个字段分别被称为 "car"和"cdr"。
(在第一台实现LISP的机器上,用CAR和CDR代表"地址寄存器的内容"和"指令寄存器的内容"。
Conses的实现主要依靠这两个寄存器。
)Conses很容易使用:Lists你可以构造conses之外的结构。
可能最简单的是链表:每一个cons的car指向链表的一个元素,cdr指向另一个cons或者nil。
我们可以使用list函数构造链表。
需要注意的是 LISP 用一种特殊的方式打印链表:它忽略掉某些分隔和括号。
规则如下:如果某个 cons 的 cdr 是 nil ,LISP 不打印 nil 和段标记,如果 cons A 的 cdr 是 cons B,LISP不打印 cons B 的括号和 cons A 的分隔符。
如下:最后一个例子相当于调用(list 4 5 6)。
要注意的是这里 nil 表示没有元素的空链表:包含两个元素的链表(a b)中,cdr是(b),一个含有单个元素的链表;包含一个元素的链表(b),cdr是nil,故此这里必然是一个没有元素的链表。
如果你把链表存储在变量中,可以将它当作堆栈来使用:Functions前面我们讨论过一些函数的例子,这里还有更多:当我们定义函数的时候,设定了两个参数,x 和 y。
现在当我们调用 foo,需要给出两个参数:第一个在foo 函数调用时成为 x 的值,第二个成为 y 的值。
在LISP中,大部分的变量都是局部的,如果 foo 调用了bar,bar中虽然使用了名字为 x 的引用,但bar 得不到 foo 中的 x。
在调用过程中给一个符号赋值的操作被称为绑定。
我们可以给函数指定可选参数,在符号 &optional 之后的参数是可选参数:bar 函数的调用规则是要给出一个或两个参数。
如果它用一个参数调用,x 将会绑定到这个参数值上,而y 就是 nil;如果用两个参数调用它,x和y会分别绑定到第一和第二个值上。
baaz 函数有两个可选参数。
它为它们分别提供了默认值:如果调用者只给出了一个参数,z会绑定为10而不是nil,如果调用者没有给出参数,x会绑定为3,而z绑定为10。
在参数列表的最后设置一个 &rest 参数,可以使我们的函数接受任意数目的参数。
LISP把所有的附加参数都放进一个链表并绑定到 &rest 参数。
如下:最后,我们可以为函数指定一种被称为关键字参数的可选参数。
调用者可以用任意顺序调用这些参数,因为他们已经通过关键字标示出来。
关键字参数也可以有默认值:Printing某些函数可以用来输出。
最简单的一个是 print,它可以打印参数并且返回它们。
首先打印3,然后返回它。
如果你需要更复杂的输出,可能会用到 format,这里有个例子:第一个参数可以是 t,nil 或者一个流。
t意味着输出到终端;nil意味着不打印任何东西,而是把它返回。
流是用于输出的通用方式:它可以是一个指定的文件,或者一个终端,或者另一个程序。
这里不再详细描述流的更多细节。
第二个参数是个格式化模版,即一个包含格式化设定的字符串。
所有其它的参数由格式化设定引用。
LISP会根据标示所引用的参数,将其替换为合适的字符,并返回结果字符串。
如果format的第一个参数是 nil,它返回一个字符串,什么也不打印,否则它总是返回 nil。
前面的例子中有三种不同的标示:~S,~D和~%。
第一个接受任意LISP对象并且将其替换为这个对象的打印描述(与使用print打印出的描述信息相同)。
第二个接受一个整数。
第三个总是替换为一个回车符。
另一个常用的标示是~~,它替换为单个~。
LISP手册中介绍了其它(很多,很多)的格式化标示。
我们输入到LISP解释器的东西被称为语句;LISP解释器逐条循环读取每条语句,进行解析,将结果打印出来。
这个过程被称为读取-解析-打印循环。
某些语句会发生错误,LISP会引领我们进入调试器,以便我们找出错误原因。
LISP的各种调试器有很多差异,不过使用"help"或":help"命令就会给出一些语句帮助。
通常,一个语句是一个原子(例如,一个符号或者整数,或者字符串)或者一个列表,如果换某个语句是原子,LISP立即解析它。
符号解析为它们的值;整数和字符串解析为它们自身。
如果语句是一个列表,LISP视它的第一个元素为函数名;它递归的解析其余的元素,然后将它们的值作为参数来调用这个函数。
例如,如果LISP遇到语句 (+ 3 4),它尝试将 + 作为函数名。
然后将 3 解析为 3,4 解析为4;最后用3 和 4 作为参数调用 +。
LISP打印出 + 函数的返回值7。
顶级循环还提供了一些其它的便利;一个特别方便的地方就是获取以前输入的语句的结果。
LISP总会保存最近三个结果;它将它们保存在 *,** 和 *** 三个符号的值中,例如:Special forms有几个特殊语句看起来像函数调用,但其实不是。
这里面包括流程控制语句,例如 if 语句和 do loops;赋值语句,例如 setq,setf,push和pop;定义语句,例如 defun 和 defstruct;以及绑定构造,如 let。
(这里没有提及所有的特殊语句。
我们继续。
)一个很有用的特殊语句是 quote:quote取消其参数的绑定状态。
例如:另一个类似的语句是 fuction:function 使得解释器将其参数视为一个函数而不是解析值,例如:当我们需要将一个函数作为参数传递给另一个函数时会用到 function 语句。
后面有些示例函数将函数作为参数。
Binding绑定是词汇作用域赋值(汗,怎么读怎么别扭--译者)。
每当函数调用时,它就发生于函数的参数列变量中:形式参数被取代为调用函数时的实际参数。
你可以在程序中随处绑定变量,就像下面这样:let把val1绑定到var1,把val2绑定到var2,依次类推;然后在它的程序体中执行语句。
let的程序体与函数体的执行规则完全相同。
例如:你可以用 (let (a b) ...) 代替 (let ((a nil) (b nil)) ...) 。
val1,val2 等等。
在 let 内部不能引用 var1,var2 等等let正在绑定的成员。
例如(简而言之,在参数表中,形式参数之间不能互相引用--译者):Error: Attempt to take the value of the unbound symbol X如果符号x已经有了一个全局值,会产生一些奇怪的结果:let* 语句类似于 let,但它允许引用之前在 let* 中定义的变量的值。
例如:语句等价于Dynamic Scoping与我们在 C 或 Pascal 中编写程序不同,let 和 let* 语句提供了词汇作用域。
动态作用域是我们在BASIC 里用的那种:如果我们给一个动态作用域变量赋了值,那么所有对这个变量的访问都会取得这个值,直到给同一个变量赋了另一个值为止。
在LISP中,动态作用域变量被称为特化变量。
你可以用 special 语句 defvar 定义一个特化变量。
这里有一些词汇化和动态作用域变量的示例。
在以下示例中,check-regular 函数引用一个 regular (也就是一个词汇作用域)变量。
因为 check-regular 在绑定 regular 的 let 外部词汇化,check-regular 返回变量的全局值。