第六章 循环结构
合集下载
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
(foreach x (list 4 5 6 7) (print (+ x 1))) 5 6 7 8 8 最后一个8为调用函数的返回值。 上例中函数foreach执行时,将〈表〉中每一个顶层元素赋给x,并循环执 行最后的〈标准表〉,可见其循环次数,即〈标准表〉重复执行次数取决于 〈表〉中顶层元素的个数,最后标准表可以是多个,例如: (foreach cl /((3 4 4) (4 5 5) (5 6 6) (setq pc (list (car cl) (cadr cl))) (setq r (cadr cl)) (command “circle” pc r) ) 该例是根据表中给出的三个圆的圆心pc及半径r画三个圆。
例4 编程打印一些变量的当前约束值。 (defun fv (/ I) ((setq I (read (getstring “\n输入符号变量表:”))) (foreach v I (print (list v /= (eval v)))) (getstring) ) ;在调试程序时该函数很有用。 例5 在阴影图形中开孔的程序。 (defun kk (/ pt1 bp) ;将图形打碎 (grphscr) ;转换成图形屏幕 (setvar “osmode” 512) ;系统变量设置,最近点咬合 (setq pt1 (getpoint “\n选定打碎目标”)) (command “explode” pt1 “”) (setvar “osmode” 0) ;复原 ;画开孔的轮廓线 (prompt “\n画出开孔的轮廓线:”) (setq bp (getpoint “\n起点:”)) (command “pline” bp) ;连续用鼠标给点绘开孔轮 廓线,最后按C键停止
ቤተ መጻሕፍቲ ባይዱ
;绘坐标线: (command “pline” (polar p1 pi (* 0.3 x1) “w” 0 0 (polar p2 0 2) “”) (command “pline” (polar p1 (* 0.017453 90) (* 0.5 x)) (polar p1 (* 0.017453 270) (*0.3 x)) “”) (command “pline” (polar p1 (* 0.017453 90) 2) “w” 0 0 (polar p1 (*0.017453 270 2) “”) ;绘曲线: (while (< x end) (setq y (+ (sin x) y1) ;求x轴每增加0.2时的y坐标 px (list (+ x x1) y) I (cons px I) ;将点变量构成表赋给I x (+ x 0.2) );setq (command “pline”) ;循环不提取I表中点变量给sin曲线 (foreach p I (command p)) (command ^ c) );while (redraw) );defun
对其余标准表求值 图 6.1
6.1.4 注意 再利用while编写循环程序时,要防止死循环,例如: (setq n 1) (while (<= n 100) (print (* n n)) (setq n (1- n)) ) 或者:(setq n 1) (while (<= n 100) (print (* n n)) ) (setq n (1+ n)) 均是死循环,这是初学者要注意的。
(apply /setq /(a 4.0)) 即〈表〉的奇数位上必须为符号原子。 (2)当执行apply函数时,它要对其函数求值,所以函数名前要加 单撇号,〈表〉若为表常数时也要加单撇号。如: (apply /max /(1 2 3 4)) 亦可写成: (apply /max /(list 1 2 3 4)) 6.4 综合举例 例1 绘制三角函数曲线的程序(图6.2)。 (defun dsin (/ x p1 p2 end 1 px y) (graphscr) (command “limits” /(0 0) /(12 9) “zoom” “a”) (initget 1) (setq p1 (getpoint “\n曲线起点:”)) (initget 1) (setq p2 (getpoint p1“\n曲线终点:”)) (setq x1 (car p1) y1 (cadr p1) x 0 1 /() end (car p2)) (sevar “blipmode” 0)
6.1 WHILE函数 函数
6.1.1 调用格式 (while〈测试表达式〉[〈标准表〉……]) 〈测试表达式〉可以是任意表达式。 6.1.2 功用 while函数是最重要的循环函数。其功能是先对〈测试表达式〉求值,若 其值不为nil,就依次执行下面程序,即各〈标准表〉然后再返回来对〈测试 表达式〉求值,如不为nil,再一次执行各〈标准表〉,如此循环反复,直至 〈测试表达式〉的为nil为止。例如: (setq n 1) (while (<= n 10) (print (* n n) (setq n (1+ n)) )
第六章 循环结构
循环结构在Auto Lisp程序中应用很广,所谓循环结构就是一部分程序在 一定的条件下可以循环反复地执行,Auto Lisp提供的主要循环函数是while和 repeat还有一些与表处理有关的循环函数,如foreach和mapcar函数。本章重点 介绍while和repeat两个函数及其应用。
(while (setq n (getint “enter an initget:”)) (pinc /n) (princ /=) (princ n) ) 该例是循环输入一些整数并打印其值,当对enter an initget提示直接回车或 按空格键时,getint函数返回nil,循环停止。 从以上的四例,我们可以了解到while函数的一般用法,功能及其应用,当 然while函数的用法还有很多,读者再实践中可不断探索。并请参见本章6.4综 合举例。 6.1.3求值结果 求值结果 该函数返回值为 最后一次循环的 最后一个标准表 的求值结果,关 于while结构及求 值过程见图6.1。 测试表达式 返回最后一个标准表的值或nil
6.3.2 MAPCAR函数 函数
1. 调用格式 (mapcar〈函数〉〈表1〉〈表2〉…〈表n〉)
2. 功用及求值结果 该函数的功用是依次循环地把〈表1〉〈表2〉……中的每一 个对应位置上的元素作为〈函数〉的参数,调用〈函数〉进行 求值,并把循环的求值结果,即〈函数〉的返回值,按顺序构 成一个表,作为Mapcar函数的返回值。例如: (mapcar /+ /(1 2 3) /(4 5 6) /(7 8 9)) 返回值(12 15 18) 它等效于 (list (+ 1 4 7) (+2 5 8) (+3 6 9))) (mapcar /cons /(x y) /(1 2)) 返回值(x1)(y2) 3. 注意 (1)〈表1〉〈表2〉……〈表n〉的数目必须与〈函数〉要 求的数目相匹配,例如,“1+”函数要求1个参数,setq函数要 求多个参数。 (mapcar / 1+ /(1 2 3 4)) 返回值(2 3 4 5) (2)每个参数表中元素数据类型应与〈函数〉要求的数目相 匹配,如上例中第一个表中必须为符号原子。 (mapcar /setq /(x y z) /(1 2 3)) 返回值(1 2 3) (3)mapcar函数和foreach函数一样,它不对参数表中的元素
上例是打印1—10的平方的程序,先给n赋初值1,然后对 测试式(<= n 10) 求值,由于其值不为nil。故执行下面程序即打印12,并将(1+ n)的值2赋给n, 再对测试式求值,如此每循环一次n增加1,直到n为11时,测试式的值为nil, 循环停止。该例中(setq n 1)是赋初值,并采用循环计算数函数(setq n (1+ n))。 这是较典型的循环结构。 典型的while函数的结构应用较多,但不限于这一种结构,实际上while函 数的结构是非常灵活的,例如: (setq Loop T) (while Loop (setq a (getint “enter an initget:”)) (if (and (< a 60) (> a 1)) (setq loop nil)) ) 该例是限制输入整数在1—60之间的程序,若输入的整数大于60或小于1 ,循环继续,要求重新输入,直到输入的整数在1<a<60之间,Loop的值为nil ,才停止循环。这个例中的循环结构与前例不同,它没有循环计数函数。又 如: (setq a (getreal “\n a=?”)) (while (zerop (setq b (getreal “\n b=?”)))) (/ a b) 该例是限制除数不能为零的程序,若输入b为零,必须重新输入。这个 循环结构中即无赋初值,也无循环计数。再如:
(setq a 2 b 3) (mapcar /+ /(a b) /(1 2)) error:bad argument type 要改为下式即合理了 (mapcar /+ (list a b) /(1 2)) (4)〈函数〉名前应加禁止求值单撇号,否则出错。 (5)〈表〉的长度决定函数的调用次数,若各表的长度不等,mapcar 只循环其中最小的长度。如: (mapcar /* /(5 6) /(1 2 3)) 返回值(5 12) 6.3.3 APPLY函数 函数 1. 调用格式 (apply)〈函数〉〈表〉) 2. 功用及求值结果 该函数是把〈表〉中元素作为〈函数〉的参数调用〈函数〉,返回求值 结果。例如: (apply /+ /(1 2 3)) 返回值6 上式等效于 (+ 1 2 3) 3. 注意 (1)由于apply函数中的〈表〉中的元素作为〈函数〉的参数,所以〈 表〉中元素的数目、类型与顺序必须和〈函数〉的要求完全一致,例如:
6.2 REPEAT函数 函数
6.2.1 调用格式 (repeat〈次数〉[〈标准表〉]……) 〈次数〉必须是正整数。 6.2.2 功用 该函数用于循环次数为已知的情况,其功能是按给定循环次数对循环体 进行循环,例如:
(repeat 10 (setq n (getint “\n enter an initget:”)) (print n) ) 当然,循环次数不是事先给定的,而是有用户来确定,但与while不同的 是(setq s (getint “\n number:”))。不是每次循环都求一次值,而只是在开始循 环时由求值器求一次值。 6.2.3 求值结果 该函数返回最后一次循环的最后一个标准表的求值结果/ 6.3 其它的循环函数 下面介绍三个与表处理有关的循环函数,也就是对其参数〈表〉进行操 作的循环控制函数。 6.3.1 FOREACH函数 函数 1. 调用格式 (foreach 〈符号原子〉〈表〉〈标准表〉) 〈标准表〉可以有多个。 2. 功用及求值结果 该函数的功用是循环地将表中每一个顶层元素赋给〈符号原子〉去对循 环体中每一个〈标准表〉依次求值,并返回最后一次循环时循环体中最后一 个〈标准表〉求值结果。例如:
例2 编程给一个符号表中诸变量依次赋值。 (defun slget1 (/ n s1 s) (setq l (read (getstring “\n输入符号变量表:”))) (setq n 0) (repeat (length 1) (print (setq s1 (nth n l)) (setq s (getreal “\请赋值:”)) (set s1 s) (setq n (1+ n)) );repeat ) 上例可改写为另一程序: (defun slget2 (/ 1) (setq 1 (read 9getstring “\n输入符号变量表:”))) (foreach n 1 (set n (getreal “\请赋值;”))) ) ;该程序对于参数化绘图很方便。 例3 编程用于多个变量的初始化,即将变量赋空。 (defun fk (/ I) (setq I (read (getstring “\n输入符号变量表:”))) (foreach v I (set v nil)) )