Common Lisp:首先解构一个列表,其余的,最后(像 Python 可迭代解包)
Common Lisp: Destructure a list in first, rest, last (like Python iterable unpacking)
David Touretzky 的 Common Lisp 书的练习 6.36 要求一个函数 swap-first-last
交换任何列表的第一个和最后一个参数。我现在觉得真的很愚蠢,但我无法用 destructuring-bind
.
解决这个问题
如何在 Python 中执行 first, *rest, last = (1,2,3,4)
(可迭代解包)在 Common Lisp/with destructuring-bind
中?
经过所有尝试,加上@WillNess 的一些评论(谢谢!)我想出了这个主意:
宏bind
这个想法是尝试细分列表并在 destructuring-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 这样优雅的可能性。
destructuring-bind
无法与 lambda 绑定更多不同的方式:lambda 列表仅将整个其余部分视为 &rest <name-for-rest>
。
没有办法直接取出最后一个元素。
(当然没办法,除非你为这种问题额外写一个宏)。
(destructuring-bind (first &rest rest) (list 1 2 3 4)
(let* ((last (car (last rest)))
(*rest (butlast rest)))
(list first *rest last)))
;;=> (1 (2 3) 4)
;; or:
(destructuring-bind (first . rest) (list 1 2 3 4)
(let* ((last (car (last rest)))
(*rest (butlast rest)))
(list first *rest last)))
当然,你是 lisp,理论上你可以写宏来
destructuring-bind
以更复杂的方式...
但是,destructuring-bind
并不比:
更清晰
(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)
此宏允许您为列表的 first
、*rest
和 last
部分指定任何名称,您可以在宏的主体中进一步处理,
希望有助于提高代码的可读性。
David Touretzky 的 Common Lisp 书的练习 6.36 要求一个函数 swap-first-last
交换任何列表的第一个和最后一个参数。我现在觉得真的很愚蠢,但我无法用 destructuring-bind
.
如何在 Python 中执行 first, *rest, last = (1,2,3,4)
(可迭代解包)在 Common Lisp/with destructuring-bind
中?
经过所有尝试,加上@WillNess 的一些评论(谢谢!)我想出了这个主意:
宏bind
这个想法是尝试细分列表并在 destructuring-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 这样优雅的可能性。
destructuring-bind
无法与 lambda 绑定更多不同的方式:lambda 列表仅将整个其余部分视为 &rest <name-for-rest>
。
没有办法直接取出最后一个元素。
(当然没办法,除非你为这种问题额外写一个宏)。
(destructuring-bind (first &rest rest) (list 1 2 3 4)
(let* ((last (car (last rest)))
(*rest (butlast rest)))
(list first *rest last)))
;;=> (1 (2 3) 4)
;; or:
(destructuring-bind (first . rest) (list 1 2 3 4)
(let* ((last (car (last rest)))
(*rest (butlast rest)))
(list first *rest last)))
当然,你是 lisp,理论上你可以写宏来
destructuring-bind
以更复杂的方式...
但是,destructuring-bind
并不比:
(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)
此宏允许您为列表的 first
、*rest
和 last
部分指定任何名称,您可以在宏的主体中进一步处理,
希望有助于提高代码的可读性。