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
f
needs to be,f
. – Tankersley