有没有办法将解构绑定与&rest一起使用?

问题描述 投票:0回答:2

我有一个使用

&rest
的函数,它返回一个包含不同数量参数的列表给函数。

我经常用

destructuring bind
(db) 来分解列表。但是,当变量数量已知时,db 很有用。

分解值数量大部分时间都在变化的

&rest
列表的最佳方法是什么?

parameters common-lisp sbcl
2个回答
4
投票

这是用于模式匹配的Trivia的简单示例:

(defun foo (&rest rest)
  (trivia:match rest
    ((list* a b c _)
     (values :got-a-b-c a b c))))
CL-USER> (foo :a :b :c :and :foo)
:GOT-A-B-C
:A
:B
:C

list*
允许在不同长度的列表上进行模式匹配。更准确地说:

list
list*
模式都会检查对象是否属于列表类型,是否具有相同的长度,然后将内容与子模式进行匹配。 list* 还根据子模式检查元素,但是最后一个模式与列表的
nthcdr
匹配。

https://lispcookbook.github.io/cl-cookbook/pattern_matching.html


3
投票

如果您不知道要绑定的事物的数量,则不可能解决此问题,因为变量的数量在运行时之前是未知的。

因此,您可以解决的唯一可能的情况是列表中的元素数量以某种方式受到限制:特别是它需要有最大数量的“有趣”元素,您希望一次将变量绑定到这些元素。在这种情况下,您可以使用某种匹配的宏,或者如果您的要求更简单,只需使用

destructuring-bind
:

(defun foo (&rest args)
  (destructuring-bind (&optional (a nil ap) (b nil bp) (c nil cp) &rest extras) args
    (unless (null extras)
      (error "too many args"))
    ... use AP, BP, CP to know if one, two or three arguments were
    ... provided, and A, B, C to know what they were.
    ...))

更一般地,您可能需要一个匹配的宏。另一个答案已经提到了 Trivia,但是

destructuring-match
提供了
case
的类似
destructuring-bind
的变体:

(defun foo (&rest args)
  (destructuring-match args
    ((a &optional (b 0))
     (+ a b))
    ((a b c)
     (+ a (- b c)))
    (otherwise
     (error "need between 1 and 3 arguments"))))

然而,上述版本的

foo
实际上可以通过
destructuring-bind
来愉快地处理:

(defun foo (&rest args)
  (destructuring-bind (a &optional (b 0) (c 0)) args
    (+ a (- b c))))

这里唯一的区别是你无法控制错误情况。

destructuring-match
实际上是为了分解宏中更复杂的结构。

© www.soinside.com 2019 - 2024. All rights reserved.