From ... From: Erik Naggum Subject: Re: do loops and idioms Date: 1997/12/02 Message-ID: <3090081183347904@naggum.no>#1/1 X-Deja-AN: 294612673 References: <881078051.4957@dejanews.com> mail-copies-to: never Organization: Naggum Software; +47 8800 8879; http://www.naggum.no Newsgroups: comp.lang.lisp,comp.lang.scheme * miket@orsi.com | (defun filtered-input (predicate prompt) | "Obtain input that passes the predicate" | (labels ((local-input () | (format t prompt) | (read))) | (do ((j (local-input) (local-input))) | ((funcall predicate j) j)))) : | It bothers me that I have to repeat myself in my do loop in the | definition of j. | Is there another idiom in common usage in common LISP? well, I would do one of these: (loop initially (format t prompt) for local-input = (read) until (funcall predicate local-input) finally (return local-input)) (do () () ;or `loop' (format t prompt) (let ((local-input (read))) (when (funcall predicate local-input) (return local-input)))) or you could use the Lisp reader for a short-hand way of repeating a form. I used this for a while, but then I confused myself, so I stopped. what do others think? (do ((local-input #1=(progn (format t prompt) (read)) #1#)) ((funcall predicate local-input) local-input)) | Of course in scheme I would have written it as a tail recursive function: | | (define (filtered-input predicate prompt) | (let ((local-input (sequence (display prompt) (read)))) | (if (predicate local-input) | local-input | (filtered-input predicate prompt)))) you could do the same in Common Lisp: (defun filtered-input (predicate prompt) (format *query-io* prompt) (let ((local-input (read *query-io*))) (if (funcall predicate local-input) local-input (filtered-input predicate prompt)))) as a matter of user interface design, I think it would make sense to indicate that a value was rejected and to use another prompt for repeats: (defun filtered-input (predicate prompt repeat-prompt) (loop initially (format *query-io* prompt) for local-input = (read *query-io*) until (funcall predicate local-input) do (format *query-io* repeat-prompt) finally (return local-input))) #\Erik -- if you think this year is "97", _you_ are not "year 2000 compliant". see http://sourcery.naggum.no/emacs/ for GNU Emacs 20-related material.