问题描述
我仍在理解宏的过程中,尽管我认为我了解反引号",取消引号"和取消引用的拼接"的基本知识,但我认为它们仅在宏中使用/有用.
I am still in the process of understanding macros and though I think I understand the basics of "backquote" "unquote" and "unquote splicing", I had thought they were only used/useful in macros.
但是我从Rosetta代码中遇到了这个Common Lisp代码(日历任务),
however I came across this Common Lisp code from Rosetta code (the calender task),
(defun month-strings (year month)
"Collect all of the strings that make up a calendar for a given
MONTH and YEAR."
`(,(date-calc:center (month-to-word month) (length *day-row*))
,*day-row*
;; We can assume that a month calendar will always fit into a 7 by 6 block
;; of values. This makes it easy to format the resulting strings.
,@ (let ((days (make-array (* 7 6) :initial-element nil)))
(loop :for i :from (date-calc:day-of-week year month 1)
:for day :from 1 :to (date-calc:days-in-month year month)
:do (setf (aref days i) day))
(loop :for i :from 0 :to 5
:collect
(format nil "~{~:[ ~;~2,d~]~^ ~}"
(loop :for day :across (subseq days (* i 7) (+ 7 (* i 7)))
:append (if day (list day day) (list day))))))))
在这里,在普通函数中使用了反引号,取消引号和取消引号的拼接,它可以创建字符串列表.
here back-quote, unquote, and unquote splicing are used in a normal function, and it works to create a list of strings.
虽然我不使用Scheme,但是Racket解决方案也有类似的情况,
and while I do not use Scheme, the Racket solution had something similar,
(define days
(let ([? (if (= mn 12) (λ(x y) y) (λ(x y) x))])
(round (/ (- (find-seconds 0 0 12 1 (? (+ 1 mn) 1) (? yr (+ 1 yr))) s)
60 60 24))))
(list* (~a mname #:width 20 #:align 'center) "Su Mo Tu We Th Fr Sa"
(map string-join
(nsplit 7 `(,@(make-list pfx " ")
,@(for/list ([d days])
(~a (+ d 1) #:width 2 #:align 'right))
,@(make-list (- 42 pfx days) " ")))))))
我没有测试.
我的问题是
为什么在函数中必须这样做,用例是什么?
Why would this be necessary in a function, what is the use case?
,它与宏有什么不同?
推荐答案
准引用,取消引用和取消引用只是对引用数据, list
和 cons
.想象一下:
quasiquote, unquote and unquote-splicing are just syntax sugar for a combination of quoted datum, list
, and cons
. Imagine this:
`(,a b c) ; == (cons a '(b c))
`(a b ,c) ; == (list 'a 'b c)
`(a b ,@c d) ; == (cons 'a (cons 'b (append c '(d))))
这些都是很小的琐碎示例,因此您可以想象右侧可能变得疯狂起来,但是很高兴知道准引用魔术在需要时会产生新的弊端,并且保持原样不变.因此,在第一种情况下不能使用准引用表达式的 nconc
,而在第二种情况和第三种情况下都无法使用,因为在这些情况下需要最后一个缺点.
These are small trivial examples, so you can imagine the right hand side might become crazy complex, but it is nice to know that the quasiquote magic makes new cons when needed and keep literals as is in the tails. Thus using nconc
of quasiquoted expression would not work in the first case, but in the second and third because the last cons is needed to be fresh in those cases.
如果您具有创建列表结构的函数,则准引用将使代码更加清晰明了,因为该表单看起来更像结果.它和宏没有什么不同,因为它们都创建了列表结构.宏的结果不同.在函数中,将返回该值,而在宏代码中,该值将被替换.
If you have a function that creates a list structure, quasiquote will make the code more clear and consice since the form will look more like the result. It is no different than a macro since both create list structure. A macro differs in what happens with the result. In a function the value is returned and in a macro code gets replaced.
您可以检查将宏与 macroexpand
一起使用后会发生什么情况:
You can check what happens after using the macro with macroexpand
:
(macroexpand '`(,a ,b ,@c))
; ==> (cons a (cons b c))
; ==> t
这篇关于正常功能中的反引号,取消引号和取消引号拆分的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!