%Progn
Elisp 中的函数隐式地默认各条语句按顺序执行,在while等形式中也是如此,因此实际上需要显式地使用progn形式的场合并不多,只有and or等形式以及if形式的then部分等等。
progn返回列表中最后一个形式的值。与其副作用相同但返回值不同的还有prog1和prog2,分别返回第一个和第二个形式的值。例如,可以用如下代码返回一个列表的第一个值并获得截短后的列表:
(prog1 (car x) (setq x (cdr x)))| ; Write a function similar to `triangle' in which each row has a value which is the square of the row number. Use a `while' loop. | |
| (defun square-triangle (number-of-rows) | |
| "Calculate the total number of pebbles in a triangle where the number of | |
| pebbles in each row is the square of the number of the row." | |
| (let ((total 0) | |
| (row-number 1)) | |
| (while (<= row-number number-of-rows) | |
| (setq total (+ total (* row-number row-number))) | |
| (setq row-number (1+ row-number))) | |
| total)) | |
| ; Write a function similar to `triangle' that multiplies instead of adds the values. | |
| (defun factor-triangle (number-of-rows) | |
| "Calculate the product of number of pebbles in each row of a triangle | |
| with NUMBER-OF-ROWS rows." | |
| (let ((total 1) | |
| (row-number 1)) | |
| (while (<= row-number number-of-rows) | |
| (setq total (* total row-number)) | |
| (setq row-number (1+ row-number))) | |
| total)) | |
| ; Rewrite these two functions recursively. Rewrite these functions using `cond'. | |
| (defun recursive-square-triangle (number) | |
| "Square-triangle in a recursive manner." | |
| (if (= number 1) | |
| 1 | |
| (+ (* number number) (recursive-square-triangle (1- number))))) | |
| (defun recursive-factor-triangle (number) | |
| "Factor-triangle in a recursive manner." | |
| (if (= number 1) | |
| 1 | |
| (* number | |
| (recursive-factor-triangle | |
| (1- number))))) | |
| (defun cond-square-triangle (number) | |
| (cond ((<= number 0) 0) | |
| ((= number 1) 1) | |
| ((> number 1) | |
| (+ (* number number) (cond-square-triangle (1- number)))))) | |
| (defun cond-factor-triangle (number) | |
| (cond ((<= number 0) 0) | |
| ((= number 1) 1) | |
| ((> number 1) | |
| (* number (cond-factor-triangle (1- number)))))) | |
| ; Write a function for Texinfo mode that creates an index entry at the beginning of a paragraph for every `@dfn' within the paragraph. (In a Texinfo file, `@dfn' marks a definition. This book is written in Texinfo.) | |
| (defun make-paragraph-index () | |
| "Create an index entry at the beginning of a paragraph for every `@dfn' within the paragraph." | |
| (interactive) | |
| (save-excursion | |
| (let ((number-of-dfns 0) (resumepos 0)) | |
| (progn | |
| (forward-paragraph) | |
| (setq eop (point)) | |
| (backward-paragraph) | |
| (setq bop (point)) | |
| (goto-char eop) | |
| (while (search-backward "@dfn" nil t) | |
| (setq number-of-dfns (1+ number-of-dfns)) | |
| (setq resumepos (1- (point))) ; the resume position is 1 char before "@dfn" | |
| (forward-char 4) ; go to the beginning of the actual word | |
| (push-mark (point) nil t) | |
| (copy-region-as-kill (mark) (search-forward "}" nil t 1)) | |
| (goto-char resumepos)) | |
| (goto-char bop) | |
| (setq pos 1) | |
| (while (<= pos number-of-dfns) | |
| (setq kill-ring-yank-pointer kill-ring) ; reset the k-r-y-p so the next | |
| ; expression doesn't get confused | |
| (yank pos) | |
| (message "Inserting item %d" pos) | |
| (insert "\n") | |
| (setq pos (1+ pos))))))) ; kill the text in the dfn bracelets | |
| ; TODO: make the last defun work for multiple paragraphs, given as an arg |
| // func_ptr.c -- uses function pointers | |
| // C Primer Plus 5th Edition, Listing 14.16 | |
| #include <stdio.h> | |
| #include <string.h> | |
| #include <ctype.h> | |
| char showmenu(void); | |
| void eatline(void); // read through end of line | |
| void show(void (* fp)(char *), char * str); | |
| void ToUpper(char *); // convert string to uppercase | |
| void ToLower(char *); // convert string to lowercase | |
| void Transpose(char *); // transpose cases | |
| void Dummy(char *); // leave string unaltered | |
| int main (void) | |
| { | |
| char line[81]; | |
| char copy[81]; | |
| char choice; | |
| void (*pfun)(char *); // points a function having a | |
| // char * argument and no return value | |
| puts("Enter a string (empty line to quit):"); | |
| while (gets(line) != NULL && line[0] != '\0') | |
| { | |
| while ((choice = showmenu()) != 'n') | |
| { | |
| switch (choice ) // switch sets pointer | |
| { | |
| case 'u' : pfun = ToUpper; break; | |
| case 'l' : pfun = ToLower; break; | |
| case 't' : pfun = Transpose; break; | |
| case 'o' : pfun = Dummy; break; | |
| } | |
| strcpy(copy, line); // make copy for show() | |
| show(pfun, copy); // use selected function | |
| } | |
| puts("Enter a string (empty line to quit):"); | |
| } | |
| puts("Bye!"); | |
| return 0; | |
| } | |
| char showmenu(void) | |
| { | |
| char ans; | |
| puts("Enter menu choice:"); | |
| puts("u) uppercase l) lowercase"); | |
| puts("t) transposed case o) original case"); | |
| puts("n) next string"); | |
| ans = getchar(); // get response | |
| ans = tolower(ans); // convert to lowercase | |
| eatline(); // dispose of rest of line | |
| while (strchr("ulton", ans) == NULL) | |
| { | |
| puts("Please enter a u, l, t, o or n:"); | |
| ans = tolower(getchar()); | |
| eatline(); | |
| } | |
| return ans; | |
| } | |
| void eatline(void) | |
| { | |
| while (getchar() != '\n') | |
| continue; | |
| } | |
| void ToUpper(char * str) | |
| { | |
| while (*str) | |
| { | |
| *str = toupper(*str); | |
| str++; | |
| } | |
| } | |
| void ToLower(char * str) | |
| { | |
| while (*str) | |
| { | |
| *str = tolower(*str); | |
| str++; | |
| } | |
| } | |
| void Transpose(char * str) | |
| { | |
| while (*str) | |
| { | |
| if (islower(*str)) | |
| *str = toupper(*str); | |
| else if (isupper(*str)) | |
| *str = tolower(*str); | |
| str++; | |
| } | |
| } | |
| void Dummy(char * str) | |
| { | |
| // leaves string unchanged | |
| } | |
| void show(void (* fp)(char *), char * str) | |
| { | |
| (*fp)(str); // apply chosen function to str | |
| puts(str); // display result | |
| } |
%Progn
Elisp 中的函数隐式地默认各条语句按顺序执行,在while等形式中也是如此,因此实际上需要显式地使用progn形式的场合并不多,只有and or等形式以及if形式的then部分等等。
progn返回列表中最后一个形式的值。与其副作用相同但返回值不同的还有prog1和prog2,分别返回第一个和第二个形式的值。例如,可以用如下代码返回一个列表的第一个值并获得截短后的列表:
(prog1 (car x) (setq x (cdr x)))