Subject: Re: do loops and idioms
From: Erik Naggum <clerik@naggum.no>
Date: 1997/12/02
Newsgroups: comp.lang.lisp,comp.lang.scheme
Message-ID: <3090081183347904@naggum.no>


* 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.