• chevron_right


    Michał "phoe" Herda · Sunday, 23 December, 2018 - 12:01

(This is a repost of an old blog post of mine from Teknik.)


I had a function that returned multiple values.

I wanted to iterate over it while collecting all of the values, so I avoid losing any data.

And I found out that, welp, MAPCAR only works on primary return values.

And so, with some help from #lisp on Freenode and Bike doing an actual majority of the coding work, MULTIPLE-VALUE-MAPCAR was born.

(defun multiple-value-mapcar (function &rest lists)
  (assert (not (null lists)))
  (let* ((values (loop for l = lists then (mapcar #'cdr l)
                       until (some #'endp l)
                       collecting (multiple-value-list
                                   (apply function (mapcar #'car l)))))
         (max-values (loop for vl in values maximizing (length vl)))
         (lists (make-list max-values)))
    (loop for vl in values
          do (loop for i from 0 below max-values
                   do (push (nth i vl) (nth i lists))))
    (values-list (mapcar #'nreverse lists))))

(multiple-value-mapcar #'values 
                       '(1 2 3 4) 
                       '(a b c d e f) 
                       '(:q :w :e :r :t)) 
;;=> (1 2 3 4)
;;=> (A B C D)
;;=> (:Q :W :E :R)

(let ((hash (make-hash-table))) 
  (setf (gethash 'fuck hash) t 
        (gethash 'shit hash) nil)
  (multiple-value-mapcar (rcurry #'gethash hash) 
                         '(fuck shit stack))) 
;;=> (T NIL NIL)
;;=> (T T NIL)