CommonLisp:在first、rest和last中分解列表(如Python iterable解包)

CommonLisp:在first、rest和last中分解列表(如Python iterable解包),lisp,common-lisp,cl,Lisp,Common Lisp,Cl,David Touretzky的公共Lisp手册练习6.36要求使用一个函数swap first-last,该函数交换任何列表的第一个和最后一个参数。我现在觉得自己很愚蠢,但我无法用解构bind解决这个问题 在Python中,如何使用公共Lisp中的first、*rest、last=(1,2,3,4)(iterable unpacking)和解构bind?经过所有的尝试,并通过@WillNess的一些评论(谢谢!),我想到了这个想法: 宏bind 这个想法是试图细分列表,并在解构绑定中使用lam

David Touretzky的公共Lisp手册练习6.36要求使用一个函数
swap first-last
,该函数交换任何列表的第一个和最后一个参数。我现在觉得自己很愚蠢,但我无法用
解构bind
解决这个问题


在Python中,如何使用公共Lisp中的
first、*rest、last=(1,2,3,4)
(iterable unpacking)和
解构bind

经过所有的尝试,并通过@WillNess的一些评论(谢谢!),我想到了这个想法:

bind
这个想法是试图细分列表,并在
解构绑定
中使用lambda列表的
&rest
功能,但是,使用较短的
符号,并使用
butlast
car
-
last
组合

(defmacro bind ((first _rest last) expr &body body)
`(destructuring-bind ((,first . ,_rest) ,last) 
    `(,,(butlast expr) ,,(car (last expr)))
  ,@body)))
用法:

(bind (f _rest l) (list 1 2 3 4) 
  (list f _rest l))
;; => (1 (2 3) 4)
我最初的答案 没有比Python更优雅的可能性了。
解构绑定
的绑定方式与lambda的绑定方式不同:lambda列表仅将整个rest作为
和rest
进行绑定。 没有办法直接取出最后一个元素。 (当然,没有办法,除非为此类问题编写一个额外的宏)

但当然,如果您使用的是lisp,理论上您可以将宏写入
以更复杂的方式解构绑定

但是,
解构绑定
并没有比以下内容更清晰:

(defparameter *l* '(1 2 3 4))

(let ((first (car *l*))
      (*rest (butlast (cdr *l*)))
      (last (car (last *l*))))
  (list first *rest last))

;;=> (1 (2 3) 4)
first-*rest last
为向您展示在common lisp中生成此类宏的速度:

;; first-*rest-last is a macro which destructures list for their 
;; first, middle and last elements.
;; I guess more skilled lisp programmers could write you
;; kind of a more generalized `destructuring-bind` with some extra syntax ;; that can distinguish the middle pieces like `*rest` from `&rest rest`.
;; But I don't know reader macros that well yet.

(ql:quickload :alexandria)

(defmacro first-*rest-last ((first *rest last) expr &body body)
  (let ((rest))
    (alexandria:once-only (rest)
      `(destructuring-bind (,first . ,rest) ,expr
        (destructuring-bind (,last . ,*rest) (nreverse ,rest)
          (let ((,*rest (nreverse ,*rest)))
            ,@body))))))

;; or an easier definition:

(defmacro first-*rest-last ((first *rest last) expr &body body)
  (alexandria:once-only (expr)
    `(let ((,first (car ,expr))
           (,*rest (butlast (cdr ,expr)))
           (,last (car (last ,expr))))
       ,@body))))

用法:

;; you give in the list after `first-*rest-last` the name of the variables
;; which should capture the first, middle and last part of your list-giving expression
;; which you then can use in the body.

(first-*rest-last (a b c) (list 1 2 3 4)
  (list a b c))
;;=> (1 (2 3) 4)
此宏允许您为列表中的
第一部分
*其余部分
最后部分
提供任何名称,您可以在宏的主体中进一步处理这些名称,
希望有助于提高代码的可读性。

太棒了,谢谢你的宏@欢迎光临!祝你的口齿不清之旅充满乐趣!:)<代码>(bind([a,…bs,c]a_list))\u_body___)我想应该很清楚。我的意思是,作为一种模式,从字面上看。(或一些等效物)。@WillNess-我添加了进一步的宏定义。因为
是保留的
…rest
不起作用。所以我用了
\u rest
。这是clojure符号吗?在clojure中,可以像这样分解结构
(let[[a&b]c][(butlast[1 2 3 4])(last[1 2 3 4])](list a b c))
;; you give in the list after `first-*rest-last` the name of the variables
;; which should capture the first, middle and last part of your list-giving expression
;; which you then can use in the body.

(first-*rest-last (a b c) (list 1 2 3 4)
  (list a b c))
;;=> (1 (2 3) 4)