跳过多值绑定中的值

Skip value in multiple-value-bind

一个库函数returns七个值。我只需要前四个和最后一个。有没有更优雅的方式:

(multiple-value-bind (a b c d e f g)
    (library-call)
  (declare (ignore e f))
  (rest-of-code a b c d g))

您可以使用 MULTIPLE-VALUE-LIST and SUBSEQ:

(defun library-call () (apply #'values '(a b c d e f g)))

(defun rest-of-code (&rest rest)
  (print rest))

(let ((lst (multiple-value-list (library-call))))
  (apply #'rest-of-code 
         `(,@(subseq lst 0 4) ,(car (last lst)))))

=> (A B C D G)

我认为在不考虑一些中间结构的情况下做到这一点的唯一方法就是您的建议。当然,如果它经常发生,这很容易定义语法。

作为一个例子,这里有一个叫做 mvb 的东西,它类似于 multiple-value-bind,只是忽略了名称为 "_" 的变量(所以这不依赖于导出符号 _).这依赖于org.tfeb.hax.collecting:它可以重做而不是。

(defmacro mvb (bindings form &body forms)
  (multiple-value-bind (vars ignores)
      (with-collectors (var ignore)
        (let ((i 1))
          (dolist (b bindings)
            (typecase b
              (symbol
               (cond
                ((string= (symbol-name b) "_")
                 (let ((g (make-symbol (format nil "_~D" i))))
                   (incf i)
                   (var g)
                   (ignore g)))
                (t
                 (var b))))
              (t
               (error "mutant binding ~A" b))))))
    `(multiple-value-bind ,vars ,form
       ,@(if ignores `((declare (ignore ,@ignores))))
       ,@forms)))

有了这个,您的电话将是

(mvb (a b c d _ _ g)
    (library-call)
  (rest-of-code a b c d g))

变成

(multiple-value-bind (a b c d #:|_1| #:|_2| g)
    (library-call)
  (declare (ignore #:|_1| #:|_2|))
  (rest-of-code a b c d g))

请注意 my binding macro 现在支持与此类似的内容,使用 nil 作为“不绑定任何内容”占位符:

(binding
  (bind/values (a nil b) (values 1 2 3))
  (print a)
  (bind c (+ a b))
  c)
我认为

nil 是一个不错的选择,因为它不会破坏任何现有程序,因为 nil 无法绑定。

您可以使用 metabang-bind library(类固醇上的 let 允许更多的破坏和绑定)并使用 _ 占位符来保持“mvb”的外观和感觉。

下面,我们用`(:values …):

“绑定”一个多值
(metabang.bind:bind (((:values _ b) (values 1 2)))
           b)
;; => 2