[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

OR and Multiple Values



    Date:     Fri, 17 Apr 87 18:27 EDT
    From:     MURRAY%cs.umass.edu@RELAY.CS.NET

    However, I'll take this opportuntiy to again ask for a MULTIPLE-VALUE-OR special
    form, since it cannot be defined without consing in Common-Lisp (I guess it COULD
    be a macro that expands into consing code, but the compiler would know about, but
    that is another discussion).

What are the semantics of MULTIPLE-VALUE-OR?  Does it

a) return all the values returned by the first form with a non-null first value
   (since we're no longer implicitly expecting exactly one value what does it
   do in the case of zero values?)

b) return all the values returned by the first form with all its values non-null
   (if there are zero values does that count as all non-null?)

c) return all the values returned by the first form with any of its values non-null
   (if there are zero values does that count as none non-null?)

d) return the maximum number of values returned by any forms with each slot chosen
   from the first form that returned non-null in that form (this one would require
   always evaluating all the forms, so I'm probably getting bogus here)

e) return all the values returned by the first form that returned the maximum number
   of non-null values (even more bogus)

f) ...

I think more to the heart of the matter is that Common LISP needs a way to grab,
inspect, and pass on an unknown number of multiple values without consing (and yes,
avoiding consing can be crucial for real applications give the current state of the
art for garbage collection on conventional hardware).  It's possible that, using
multiple-value-call, simply having some way of doing non-consing &rest arguments may
be sufficient.  For example, I believe the following gives something close to the
semantics of (a) without consing, if the bogus declaration ensures that the &rest
argument isn't consed (and, of course, if the implementors haven't introduced
gratuitous consing, which is far from a sure thing, especially in
multiple-value-call....).

(defmacro multiple-value-or (&rest forms)		; don't care about this &rest
  `(block #0=#:mv-or-block
     ,@(mapcar
	 #'(lambda (form)
	     `(multiple-value-call
		#'(lambda (&rest #1=#:mv-or-args)	; this &rest musn't cons
	            (declare (dynamic-extent #1#))
		    (when (first #1#)
		      (return-from #0# (apply #'values #1#))))
		,form))
	 forms)
     nil))

For example,

(multiple-value-or (mumble) (shout) (bellow))

->

(block #:mv-or-block
  (multiple-value-call
    #'(lambda (&rest #:mv-or-args)
        (declare (dynamic-extent #:mv-or-args))
	(when (first #:mv-or-args)
	  (return-from #:mv-or-block (apply #'values #:mv-or-args))))
    (mumble))
  (multiple-value-call
    #'(lambda (&rest #:mv-or-args)
        (declare (dynamic-extent #:mv-or-args))
	(when (first #:mv-or-args)
	  (return-from #:mv-or-block (apply #'values #:mv-or-args))))
    (shout))
  (multiple-value-call
    #'(lambda (&rest #:mv-or-args)
        (declare (dynamic-extent #:mv-or-args))
	(when (first #:mv-or-args)
	  (return-from #:mv-or-block (apply #'values #:mv-or-args))))
    (bellow))
  nil)

(B) and (c) can be implemented by replacing "(when (first #1#)" by
"(when (every #'identity #1#)" and "(when (some #'identity #1#)",
respectively.