CommonLisp:在first、rest和last中分解列表(如Python iterable解包)
David Touretzky的公共Lisp手册练习6.36要求使用一个函数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
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)