• person rss_feed

    Michał "phoe" Herda’s feed

    Blog

    • chevron_right

      MULTIPLE-VALUE-MAPCAR

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

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

    #common-lisp

    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)