This page contains the description of the following commands date, decr, decr1, decrement, decr-rmargin, defconstant, defarray, defvar, delete, delq, denominator, describe, desetq, directory-namestring, discard_seq, displace, display-flush, display_packages, display-to-list, display-to-string, div, divisors, divisors_and_fact, do, dot, duplstring,
The date function takes no argument. It returns the current date.
[Endymion] (date) Mon Jan 01 1900 00:00:00 [Endymion] (type-of (date)) date
The decr macro takes at least one argument. In the case of one argument, the expansion is (setq var (- var 1)). In the case of two arguments, it is (setq var (- var val)). Note that both decr and - accept more than two arguments. The macro could be defined as follows
(dmd decr (x . y) (if y `(setq ,x (- ,x . ,y)) `(setq ,x (- ,x 1))))
Example
[Endymion] (setq x 10) 10 [Endymion] (decr x) (decr x 3) 9 6 [Endymion] x 6 [Endymion] (setq a '(decr z) b '(decr z 2) c '(decr z 3 4 5)) (decr z 3 4 5) [Endymion] (eval a) eval : undefined variable : z [Endymion] (eval b) eval : undefined variable : z [Endymion] (eval c) eval : undefined variable : z [Endymion] a (setq z (- z 1)) [Endymion] b (setq z (- z 2)) [Endymion] c (setq z (- z 3 4 5))
The macro is defined as decr1(x)::=buildq(x:=x-1);. Since x-- is read as decr1(x), it is the same as x:=x-1. Never say f(x)--: this constructs a function that calls itself, without end.
The macro is defined as decrement(x,y)::=buildq(x:=x-y);.
The (decr-rmargin 10) function call decrement the right margin by 10, it is the same as (setq rmargin (- rmargin 10)). The (eol) function could then be used to fill these 10 characters. See lmargin for further information; in particular, it is said that (eol) is not called if the right margin is beyond the size of the buffer. In this case, (decr-rmargin) leaves the right margin unchanged (because the right margin is considered to be at infinity in such a case). In any case, the function returns its argument.
The defconstant special forma takes two arguments: a name and a value. The value is evaluated, and put in cell value of the name, in the same fashion as setq. The return value is the name. If the name has already a value, and if the new value is not the old one, an error message is printed. The name must be a symbol, but neither a constant like true, not a variable-function like ibase.
[Endymion] (defconstant ibase 18) defconstant : not a variable : ibase [Endymion] (defconstant) defconstant : wrong number of arguments : 0 this should be 2 [Endymion] (defconstant foo (+ 7 8)) foo [Endymion] (defconstant foo (+ 6 9)) foo [Endymion] (defconstant foo (+ 3 4)) ** defconstant badval: foo : 7 foo
The defvar special form takes one two or three arguments. The default value of the second argument is nil. The third argument is ignored. The first argument must be a variable (a symbol, but not a constant, nor a variable funtion). If defvar is called while reading a file, the variable gets as #:system:loaded-from-file propery the name of the file. In any case, it get as #:complice:globalvar property the quantity true. Otherwise defvar behaves like setq: it assigns to the name the result of the evaluation of the second argument; it returns the value.
[Endymion] (defvar) defvar : wrong number of arguments : 0 this should be 2 [Endymion] (defvar foo) foo [Endymion] foo () [Endymion] (defvar foo 'bar) foo [Endymion] foo bar [Endymion] (defvar foo 'gee (some comment "!!")) foo [Endymion] foo gee [Endymion] (plist 'foo) (#:complice:globalvar true) [Endymion] (defvar ibase) defvar : not a variable : ibase
The delete and delq functions take two argument, an item and a list. They remove the item from the list. The delq function uses eq, the delete function uses equal. They return a list that contains the initial list without the argument. The function can modify its second argument. Note: If x is the first element of the list, the return value can differ from the second argument.
The two functions remove and remq return the same value, but they do not modify the list: they return a copy.
[Endymion] (setq x "foo") foo [Endymion] (setq l '(1 2 a b "foo" #.x 1 2 a b "foo" #.x)) (1 2 a b foo foo 1 2 a b foo foo) [Endymion] (remq x l) (1 2 a b foo 1 2 a b foo) [Endymion] (remove x l) (1 2 a b 1 2 a b) [Endymion] (remove 25 l) (1 2 a b foo foo 1 2 a b foo foo) [Endymion] (remq 25 l) (1 2 a b foo foo 1 2 a b foo foo) [Endymion] (delq x l) (1 2 a b foo 1 2 a b foo) [Endymion] (delete x l) (1 2 a b 1 2 a b) [Endymion] l (1 2 a b 1 2 a b) [Endymion] (delq 25 l) (1 2 a b 1 2 a b) [Endymion] (delete 25 l) (1 2 a b 1 2 a b) [Endymion] (delq 1 l) (2 a b 2 a b) [Endymion] l (1 2 a b 2 a b)
The delq function removes an element from a list. See delete above. These functions could be defined as follows
(defun delete (s l) (cond ((atom l) l) ((equal s (car l)) (delete s (cdr l))) (true (rplacd l (delete s (cdr l)))))) (defun delq (s l) (cond ((atom l) l) ((eq s (car l)) (delete s (cdr l))) (true (rplacd l (delete s (cdr l))))))
This function returns the denominator of its argument; see numerator.
Not yet described
The desetq macro takes two arguments. The first argument should be a tree. In the case of (x y . z), the macro is equivalent to (setq x (car b)), (setq y (cadr b)) and (setq z (cddr b)) (but b is evaluated only once). If instead of x there had been something more complicated, like (X Y Z), the result would have been (desetq (X Y Z) (car b)), i.e. (setq X (car (car b))), (setq Y (cadr (car b))), (setq Z (caddr (car b))).
The expansion of desetq has the form (progn XXX true), so that the value is true. The XXX here has the form (let ((acopy b)) assign), where acopy is a copy of a, replacing each element in the tree by a name, say g1, g2, etc. and assign is the sequence of assignments that sets elements of a to the corresponding g1, g2, etc. In the current version, the desetq macro does no checks; if a non-variable is found in the tree, an error is signalled after expansion. The macro could be defined as follows
(dmd desetq (a b) (let ((R (ncons 'setq))) (setq a (desetq-aux a R)) `(progn ((lambda (,a) ,R) ,b) true))) (defun desetq-aux (x R) (cond ((null x) x) ((atom x) (let ((a (gensym))) (nconc1 R x) (nconc1 R a) a)) (true (cons (desetq-aux (car x) R) (desetq-aux (cdr x) R)))))
Example
[Endymion] (defun f (L) (desetq (a (b (c d . e) f) (g h)) L) [Endymion] (list a b c d e f g h)) f [Endymion] (f '(1 (2 (3 4 . 5) 6) (7 8))) (1 2 3 4 5 6 7 8) [Endymion] (f '(1 2 3)) eval : illegal binding : 2 [Endymion] (getdef 'f) (defun f (L) (progn ((#:system:lambda 1 ((g1 (g2 (g3 g4 . g5) g6) (g7 g8))) ( setq a g1 b g2 c g3 d g4 e g5 f g6 g g7 h g8)) L) true) (list a b c d e f g h )) [Endymion] (desetq (1 2) '(3)) eval : illegal binding : () [Endymion] (desetq (1 2) '(3 4)) setq : not a variable : 1
The directory-namestring function takes as argument a pathname (either an object of type pathname, or something that can be converted to a pathname, for instance a string or a symbol), like "foo/bar.gee" and returns the directory part (here `foo'). See pathname for examples.
This function takes a sequence as argument. If the sequence is not exhausted, it is advanced. The return valus is true if the sequence is exhausted, false otherwise. See makeseq for details.
This function replaces the CAR of a by the CAR of b, and the CDR of a by the CDR of b; it could be defined as follows (note the special cases when one of the argument is not a cons).
(defun displace (a b) (if (not (consp a)) (error 'displace $errnla a)) (if (not (consp b)) (setq b (list 'progn b))) (rplaca a (car b)) (rplacd a (cdr b)) a)
This function is used by the symbolic printer. See description of #:display:eol.
The display_packages variable function controls whether or not packages are printed by the symbolic printer. If the variable is nil, they are not printed. Otherwise they are printed.
The display-to-list function takes two arguments, a channel name and a keyword. These arguments are converted to symbols; an error is signaled if this is not possible. The second argument should be `open', `close', `append or `show'; otherwise, the first argument is discarded and nil is returned. An error is signaled in case of `open' if the channel is already open, in case of `close' or `show', if it is not open. In the case of `append', it is an error if the channel is opened, but not as a list. Here are some examples. Notice that (#:display:openfiles) returns the console, all open files, as well as all open lists.
[Endymion] (display-to-list "foo" 1) () : I/O error : 1 [Endymion] (display-to-list 1 "bar" ) () : I/O error : 1 [Endymion] (display-to-list "foo" "bar") () [Endymion] (display-to-list "foo" "open") foo [Endymion] (display-to-list "bar" "close") display-to-list : I/O error : bar [Endymion] (display-to-list "foo" "open") display-to-list : I/O error : foo [Endymion] (display-to-list 'xbar "open") xbar [Endymion] (display-to-list "bar" "show") display-to-list : I/O error : bar [Endymion] (#:display:openfiles) [console foo xbar] [Endymion] (#:display:open "bar" true) true [Endymion] (#:display:openfiles) [console foo xbar bar] [Endymion] (display-to-list 'bar "open") display-to-list : I/O error : bar [Endymion] (display-to-list 'bar "append") display-to-list : I/O error : bar
The effect of (display-to-list "foo" "open") is to add `foo' as a channel (of type list) on which you can display. Replacing `open' by close will remove the channel (the content will be lost). `append' means: do nothing if already open, open the channel otherwise. Finally, `show' will return the value of the channel as a list of strings.
[Endymion] (#:display:outchan 'default 'foo) [foo list] [Endymion] (display '(** x 3)) () [Endymion] (display-to-list 'foo "show") [ 3 x] [Endymion] (display '(index foo bar)) () [Endymion] (display-to-list 'foo "show") [ 3 x index(foo, bar)] [Endymion] (display '(indexed foo bar)) () [Endymion] (let ((#:system:print-for-read true)) [Endymion] (print (display-to-list 'fooo "show"))) [" 3" "x" "index(foo, bar)" "foo" " bar"] [ 3 x index(foo, bar) foo bar] [Endymion] (#:display:outchan 'default '(foo xbar)) [subtchannel [xbar list] [foo list]]
The display-to-string function takes two arguments, an object x and an integer s. If the second argument is not an integer, zero will be used instead. A unique channel name C is constructed. The function display-to-list is used to create a channel, select it, and destroy after use. The function display is used to print on this channel. The four arguments to display are: the object to print is x, the channel is `default', that contains only C, the minor mode is nil, the major mode is s modulo 4 (0 means twodim, 1 means Endymion, 2 means fortran, 3 means TeX). This gives a list of strings, that are concatenated. If m=s/4 is not zero, only the first m elements of the result are taken.
[Endymion] (display '(matrix (0 1 2) (0 3 (** x 2)))) [1 2 ] [ ] [ 2] [3 x ] () [Endymion] (display-to-string '(matrix (0 1 2) (0 3 (** x 2))) 0) [1 2 ][ ][ 2][3 x ] [Endymion] (display-to-string '(matrix (0 1 2) (0 3 (** x 2))) 1) matrix([1, 2], [3, x**2]); [Endymion] (display-to-string '(matrix (0 1 2) (0 3 (** x 2))) 2) matrix([1, 2], [3, x**2]) [Endymion] (display-to-string '(matrix (0 1 2) (0 3 (** x 2))) 283) $${\left(\def\arraystretch{2.}\begin{array}{cc}1&2\\3&\sisindexsup{x}{ [Endymion] (display '(sum (f x) x 1 infinity)) infinity ===== \ > f(x) / ===== x = 1 () [Endymion] (display-to-string '(sum (f x) x 1 infinity) 'foo) infinity ===== \ > f(x) / ===== x = 1
The div function computes the quotient of its two arguments. The effect of (/ 1 2 3) is the same as (div 1 (* 2 3)).
The divisors function takes as argument an integer, and returns the list of divisors; the divisors_and_fact function returns also the factorisation of the divisors. As a particular case, the divisors function accepts the output of ifactor. These functions can be defined as follows. Note the call to sort2, this makes sure that the factors are listed in order.
(defun divisors (n) (let ((R (cons 1 ())) (F (ifactor n)) p k y A) (while (consp F) (setq p (caar F) k (cadar F) F (cdr F)) (setq A R R ()) (while (consp A) (setq y (car A) A (cdr A)) (for (j 0 1 k) (setq R (cons y R)) (setq y (* y p))))) (sort2 R))) (defun divisors_and_fact (n) (let ((R (ncons (cons 1 ()))) (F (ifactor n)) p k y z zp tmp A) (while (consp F) (setq p (caar F) k (cadar F) F (cdr F)) (setq A R R ()) (while (consp A) (setq z (car A) y (car z) zp (cdr z) A (cdr A)) (for (j 0 1 k) (if (eq j 0) (setq R (cons z R)) (setq y (* y p) tmp (cons y (cons (list p j) zp)) R (cons tmp R)))))) (sort2 R)))
Example
[Endymion] (divisors 360) (1 2 3 4 5 6 8 9 10 12 15 18 20 24 30 36 40 45 60 72 90 120 180 360) [Endymion] (divisors_and_fact 360) ((1) (2 (2 1)) (3 (3 1)) (4 (2 2)) (5 (5 1)) (6 (3 1) (2 1)) (8 (2 3)) (9 (3 2)) (10 (5 1) (2 1)) (12 (3 1) (2 2)) (15 (5 1) (3 1)) (18 (3 2) (2 1)) (20 ( 5 1) (2 2)) (24 (3 1) (2 3)) (30 (5 1) (3 1) (2 1)) (36 (3 2) (2 2)) (40 (5 1 ) (2 3)) (45 (5 1) (3 2)) (60 (5 1) (3 1) (2 2)) (72 (3 2) (2 3)) (90 (5 1) ( 3 2) (2 1)) (120 (5 1) (3 1) (2 3)) (180 (5 1) (3 2) (2 2)) (360 (5 1) (3 2) (2 3))) [Endymion] (divisors 1/2) divisors : not a fixnum : 1/2 [Endymion] (divisors -10) divisors : argument out of bounds : -10 [Endymion] (divisors 1024) (1 2 4 8 16 32 64 128 256 512 1024) [Endymion] (divisors_and_fact 1024) ((1) (2 (2 1)) (4 (2 2)) (8 (2 3)) (16 (2 4)) (32 (2 5)) (64 (2 6)) (128 (2 7 )) (256 (2 8)) (512 (2 9)) (1024 (2 10))) [Endymion] (divisors '((2 3) (3 2))) (1 2 3 4 6 8 9 12 18 24 36 72) [Endymion] (divisors '((1/10 3) (3 2))) divisors : not a fixnum : ((1/10 3) (3 2))
A symbolic loop is defined by its body, preceded by the keyword do or Do. It can be preceded by an initial test (introduced by while) and a final test (introduced by until). There can be some control variables, introduced by for.
The expansion of a loop starts with the control variables. First, vars is expanded (see example 4 below). The result should be of the form v1 and v2 ... and vn. The case n=1 is possible. Each vi is expanded again (note: in some cases, and is considered as a macro, but not in this context). Each vi should be of the form xi in yi, where xi is a variable and yi is a sequence. Instead of x in a...b (or x in a...b step c you can say xi =a...b (or xi =a...b step c). In the case where the upper bound is infinity and the step is one, you can omit them (see example 9, with y=5). Finally, if the initial value is one, you can omit it as well. Thus for x do print(x) prints all positive numbers. We have shown in example (4) the expansion of the loop. The important point is that, for each yi, we construct a variable gi, initialised to makeseq(yi), and let(xi=popseq(gi),...) is added to the body of the loop. We have a test: the loop terminates if any endofseq(gi) returns true. The test is optimised in a case like x in a...b step c if the step is positive and the upper bound is infinity.
(2) Mac()::=buildq( x in [1,2,3]); (2) false (3) L:= []?; (4) for Mac() do L:=cons(x,L); Macro expansion -> for (Mac()) do (L := cons(x, L)) Macro expansion<- let([g11 = makeseq([1, 2, 3])], block(outer-do, loopforever(if endofseq(g11) then BREAK() else let([x = popseq(g11)], block(inner-do, L := cons(x, L)))))) (5) L; (5) [3, 2, 1] (6) L:= []?; (7) for x in 1...3 and y in [a,b,c,d,e,f,h] do L := cons(y,L); (let ((#:gensym:g30 (:makeseq (::... 1 3 1))) (#:gensym:g31 (:makeseq (:[ 'a 'b 'c 'd 'e 'f 'h))) ) (block outer-do (tagbody #:gensym:g32 (if (if (:endofseq #:gensym:g30) true (:endofseq #:gensym:g31)) (return-from outer-do 'done) (let ((x (:popseq #:gensym:g30)) (y (:popseq #:gensym:g31))) (#:ed:symbs:set 'L (:cons y (#:ed:symbs:symeval 'L))) ) ) (go #:gensym:g32) ) ) ) (7) done (8) L; (8) [c, b, a] (9) for x and y=5 and z = 12...13 do print([x,y,z]); [1, 5, 12] [2, 6, 13] (9) done
In a case like for x while (x<A) do print (x) until (x=B); the test x<A is evaluated, and the loop stops if the test is false. In the same fashion, the loop stops if the test x=B becomes true (but x is printed before the test). The loop is exited by evaluating BREAK(); the macro can be used directly, as in for x do { if(x>=A) then break(), print (x), if(x=B) then break()} (for some strange reason, BREAK and break are identical). You can use NEXT() if you want to interrupt the current iteration, but not the loop. In example (3) below, we show the result of expanding the do, the loopforever, the BREAK, and the NEXT.
The macros BREAK and NEXT expand to return(xx) where xx is some block name. In example (4) below, we use a declaration thats says that these commands are not used, and there is no need to create these two blocks. You can control execution via goto(loop_begin) and goto(loop_end) instead of these macros. The operator Do is like do, with an implicit safe_loop declaration.
(1) for x do { if (x>10) then BREAK(), print (x), if(x==3) then BREAK()}; 1 2 3 (1) done (2) for x while (x<3) do print (x) until (x=30); 1 2 (2) done (3) for x =80 while x<100 do { if not(#isprime(x)) then NEXT(), print (x)}; Macro expansion -> for (x = 80) while (x < 100) do ({if not (#isprime(x)) then NEXT() else false, print(x)}) Macro expansion <- let([g25 = makeseq(80 ... Infinity)], block(outer-do, loopforever(let([x = popseq(g25)], if x < 100 then false else BREAK(), block(inner-do, {if not (#isprime(x)) then NEXT() else false, print(x)}))))) Macro expansion -> loopforever(let([x = popseq(g25)], if x < 100 then false else BREAK(), block(inner-do, {if not (#isprime(x)) then NEXT() else false, print(x)}))) Macro expansion <- tagbody(label(g26), let([x = popseq(g25)], if x < 100 then false else BREAK(), block(inner-do, {if not (#isprime(x)) then NEXT() else false, print(x)})), goto(g26)) Macro expansion -> BREAK() Macro expansion <- return(outer-do, done) Macro expansion -> NEXT() Macro expansion <- return(inner-do) (let ((#:gensym:g25 (:makeseq (:... 80 'Infinity 1)))) (block outer-do (tagbody #:gensym:g26 (let ((x (:popseq #:gensym:g25))) (if (#:ed:util:compare x 100 '<) false (return-from outer-do 'done) ) (block inner-do (if (isprime x) false (return-from inner-do 'done)) (:print x) ) ) (go #:gensym:g26) ) ) ) 83 89 97 (3) done (4) for x =80 ...50 do { declare([safe_loop]), print (x)}; Macro expansion -> for (x = 80 ... 50) do ({declare([safe_loop]), print(x)} ) Macro expansion <- let([g32 = makeseq(80 ... 50)], tagbody(label(loop_begin), if endofseq(g32) then goto(loop_end) else let([x = popseq(g32)], {print(x)}), goto(loop_begin), label(loop_end))) (4) false (5) for x = 5...6 Do print (x); Macro expansion -> Do(x = 5 ... 6, true, print(x), false) Macro expansion <- let([g33 = makeseq(5 ... 6)], tagbody(label(loop_begin), if endofseq(g33) then goto(loop_end) else let([x = popseq(g33)], print(x)), goto(loop_begin), label(loop_end))) 5 6 (5) false
In Lisp, (cons 1 2) is the same as (1 . 2), it is called a dotted pair. In symbolic mode the second argument of cons must be a list (it can be the empty list), and in some cases where dotted pairs might be of interest, you can use [1, dot, 2] instead. Fot instance f(x, dot,y)::=buildq(y) defines a macro with variable number of arguments, see macros.
The duplstring function takes two arguments. The result is a string composed by n copies of the string s. The function could be defined as follows (the actual implementation is more efficient, since the argument is converted to a string only once).
(defun duplstring (n s) (unless (integerp n) (error 'duplstring errnia n)) (when (< n 0) (error 'duplstring erroob n)) (apply 'catenate (makelist n s)))
Examples
[Endymion] (duplstring 3 "foo") foofoofoo [Endymion] (duplstring 3 #"foo") foofoofoo [Endymion] (duplstring 3 'foo) foofoofoo [Endymion] (duplstring -3 'foo) duplstring : argument out of bounds : -3 [Endymion] (duplstring 1/2 'foo) duplstring : not a fixnum : 1/2 [Endymion] (duplstring 4 1.5) 1.51.51.51.5 [Endymion] (duplstring 4 '(100 101 102)) defdefdefdef [Endymion] (duplstring 4 1/2) (duplstring : non string argument : 1/2
back to home page © INRIA 2005, 2006 Last modified $Date: 2009/01/08 17:43:30 $