正常函数中的反引号,无引号和非引号拼接

Dii*_*iiP 2 scheme list common-lisp backquote

我仍然在理解宏,虽然我认为我理解"反引号""unquote"和"unquote splicing"的基础知识,但我认为它们只在宏中使用/有用.

但是我从Rosetta代码(日历任务)中看到了这个Common Lisp代码,

(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))))))))
Run Code Online (Sandbox Code Playgroud)

这里,back-quote,unquote和unquote splicing用于普通函数,它可以创建一个字符串列表.

虽然我不使用Scheme,但Racket解决方案有类似的东西,

(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) "  ")))))))
Run Code Online (Sandbox Code Playgroud)

我没有测试过.

我的问题是,

为什么在函数中这是必要的,用例是什么?

它与宏有什么不同?

Syl*_*ter 5

quasiquote,unquote和unquote-sclicing只是引用数据组合的语法糖list,和cons.想象一下:

`(,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))))  
Run Code Online (Sandbox Code Playgroud)

这些都是一些小小的例子,所以你可以想象右手边可能变得疯狂复杂,但很高兴知道quasiquote魔法在需要的时候会产生新的缺点并保持文字在尾巴中.因此,使用nconcquasiquoted表达式在第一种情况下不起作用,但在第二种情况和第三种情况下,因为在这些情况下需要最后的缺点.

如果你有一个创建列表结构的函数,quasiquote会使代码更清晰,更简洁,因为表单看起来更像结果.它与宏没有什么不同,因为它们都创建了列表结构.宏与结果的不同之处不同.在函数中,返回值并在宏代码中替换.

您可以检查使用宏后发生的情况macroexpand:

(macroexpand '`(,a ,b ,@c))
; ==> (cons a (cons b c)) 
; ==> t
Run Code Online (Sandbox Code Playgroud)