I want to define a LISP macro like dolist that lets me define an optional output argument. In the following case study, this macro will be called doread. It will read lines from a file and return the number of lines found that way.
(let ((lines 0)) (doread (line file lines) ;; do something with line (incf lines))) The problem is that getting that lines to work in the above macro
I can do what I want with &key , but not with &optional &key (and the &key is needed since I want to control how a file is read; e.g with read or read-line or whatever).
Now the following works BUT to works the wrong way. Here the out argument has to be a &key and not a &optional:
;; this way works... (defmacro doread ((it f &key out (take #'read)) &body body) "Iterator for running over files or strings." (let ((str (gensym))) `(with-open-file (,str f) (loop for ,it = (funcall ,take ,str nil) while ,it do (progn ,@body)) ,out))) ;; lets me define something that reads first line of a file (defun para1 (f) "Read everything up to first blank line." (with-output-to-string (s) (doread (x f :take #'read-line) (if (equalp "" (string-trim '(#\Space #\Tab) x)) (return) (format s "~a~%" x))))) (print (para1 sometime)) ; ==> shows all up to first blank line What I'd like to do is this is the following (note that out has now moved into &optional:
(defmacro doread ((it f &optional out &key (take #'read)) &body body) "Iterator for running over files or strings." (let ((str (gensym))) `(with-open-file (,str f) (loop for ,it = (funcall ,take ,str nil) while ,it do (progn ,@body)) ,out))) and if that worked, I could do something like.
(defun para1 (f) "Print everything up to first blank line. Return the lines found in that way" (let ((lines 0)) (doread (x f lines :take #'read-line) (if (equalp "" (string-trim '(#\Space #\Tab) x)) (return) (and (incf lines) (format t "~a~%" x))))) but it I use &optional out I get
loading /Users/timm/gits/timm/lisp/src/lib/macros.lisp *** - GETF: the property list (#'READ-LINE) has an odd length
fneeds to be,f.