List 正常函数中的反引号、反引号和反引号拼接

List 正常函数中的反引号、反引号和反引号拼接,list,scheme,common-lisp,backquote,List,Scheme,Common Lisp,Backquote,我仍在理解宏的过程中,虽然我认为我理解“反引号”、“反引号”和“反引号拼接”的基本知识,但我认为它们只在宏中使用/有用 然而,我在Rosetta代码(the)中遇到了这个常见的Lisp代码 在这里,反引号、反引号和反引号拼接在普通函数中使用,用于创建字符串列表 虽然我不使用Scheme,但球拍解决方案也有相似之处 (define days (let ([? (if (= mn 12) (λ(x y) y) (λ(x y) x))]) (round (/ (- (find-se

我仍在理解宏的过程中,虽然我认为我理解“反引号”、“反引号”和“反引号拼接”的基本知识,但我认为它们只在宏中使用/有用

然而,我在Rosetta代码(the)中遇到了这个常见的Lisp代码

在这里,反引号、反引号和反引号拼接在普通函数中使用,用于创建字符串列表

虽然我不使用Scheme,但球拍解决方案也有相似之处

(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) "  ")))))))
我没有测试

我的问题是,

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


它与宏有何不同

quasikote、unquote和unquote拼接只是引用数据、
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))))  
这些都是小而琐碎的例子,所以你可以想象右手边可能会变得非常复杂,但是很高兴知道,Quasikote魔法会在需要时生成新的cons,并保持文本的尾部。因此,在第一种情况下,使用准连续表达式的
ncoc
将不起作用,但在第二种和第三种情况下,因为在这些情况下,最后的cons需要是新的

如果您有一个创建列表结构的函数,quasiquote将使代码更加清晰一致,因为表单看起来更像结果。它与宏没有区别,因为两者都创建列表结构。宏与结果的不同之处在于发生了什么。在函数中返回值,在宏代码中替换

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

(macroexpand '`(,a ,b ,@c))
; ==> (cons a (cons b c)) 
; ==> t
准引号(QQ)是Scheme中的列表构造函数

它比引号(')、列表或cons更灵活,因为它允许将符号与表达式求值混合使用

QQ有两种辅助机制:

  • unquote-表示为(,)

  • 不引用拼接-表示为(,@)

  • 使用QQ时,将启动报价上下文。Unquote允许我们立即退出quote上下文,并在Unquote之后计算表达式。取消报价拼接既可以从报价上下文中转义整个列表,也可以“展开”列表。 考虑:

    (define b 5)
    (define s (list 1 2))
    
    请注意以下表达式值的差异:Quote、Quote

    输入:

    '(a b c)
    `(a b c)
    
    输出

    > (a b c)    
    > (a b c)
    
    > (a ,b c)   
    > (a 5 c)
    
    > (a ,s c)   
    > (a (1 2) c)
    
    > (a ,@s c)  
    > (a 1 2 c)
    
    输入

    输出

    > (a b c)    
    > (a b c)
    
    > (a ,b c)   
    > (a 5 c)
    
    > (a ,s c)   
    > (a (1 2) c)
    
    > (a ,@s c)  
    > (a 1 2 c)
    
    输入

    输出

    > (a b c)    
    > (a b c)
    
    > (a ,b c)   
    > (a 5 c)
    
    > (a ,s c)   
    > (a (1 2) c)
    
    > (a ,@s c)  
    > (a 1 2 c)
    
    输入

    输出

    > (a b c)    
    > (a b c)
    
    > (a ,b c)   
    > (a 5 c)
    
    > (a ,s c)   
    > (a (1 2) c)
    
    > (a ,@s c)  
    > (a 1 2 c)
    

    资料来源:我参加的汇编课程,

    Backquote

    请参阅上的CLHS

    示例

    该示例类似于此代码:

    CL-USER 14 > (let ((a 1)
                       (b 2)
                       (c '(3 4 5)))
                   `(,a                ; a gets evaluated and put in
                     ,b                ; b gets evaluated and put in
                     ,@c))             ; c gets evaluated and spliced in
    (1 2 3 4 5)
    
    上述代码的效果类似于使用函数
    list*

    CL-USER 15 > (let ((a 1)
                       (b 2)
                       (c '(3 4 5)))
                   (list* a b c))     
    (1 2 3 4 5)
    
    你使用哪种版本主要取决于你的品味

    list*
    创建第一个值的列表,并将它们放在最后一个值的前面,最后一个值应该是一个列表

    列表创建

    有许多方法和样式可以创建列表。这里有两个:

  • 使用嵌套函数,如
    cons
    list
    list*
    append
    。。。当有许多元素需要计算时,这尤其有用
  • 使用带反引号运算符的列表模板和
    ,@
    ,.
    进行评估。当存在包含固定对象和几个要计算的对象的嵌套列表时,这一点尤其有用
  • 因此,当您想到要填写的列表模板时,倒引号方式非常有用。无论何时,只要您想要创建(嵌套)列表,这些列表都是基于具有丢失常量结构(表示对象和嵌套)的模板的,那么这就是一种方法。这不仅限于宏,它是一种构建列表的通用机制

    您还可以将模板视为反转:

  • 默认情况下,函数求值,需要引用常量元素
  • 默认情况下,反引号模板不会计算,变量元素需要取消引号
  • 警告

    反向引用表达式本身不需要是纯列表。反引号表达式的内部表示形式未定义,实现实际上有所不同

    向量也是

    请注意,这也适用于向量:

    CL-USER 20 > (let ((a 1)
                       (b 2)
                       (c '(3 4 5)))
                   `#(,a
                      ,b
                      ,@c))
    #(1 2 3 4 5)
    

    反引号是生成s表达式(嵌套的基于列表的结构)的语法糖。Lisp源代码由s表达式组成,因此反引号对于宏(输入和输出为代码的函数,其形式为s表达式)非常有用。许多Lisp数据都是由s表达式构成的,因此反引号对于操作数据的函数(当数据是s表达式形式时)非常有用。值得注意的是,尽管问题引用scheme和这些示例在scheme中工作,这个问题还引用了通用的Lisp,因为在反引号外使用逗号是非法的,所以这些都不起作用。1) 我不是匿名的这是我的真名。2) 在scheme中,如果您输入
    ”(a,b)
    ,您将得到
    (a,b)
    ,即
    (a(unquote b))
    的语法糖。如果我在(sbcl)Common Lisp中尝试相同的方法,我会得到一个错误:
    逗号不在反引号内
    ,类型为
    SB-INT:SIMPLE-READER-error
    。我会对陌生人或同事说。我不认为这个短语是猛击或侵略性的。如果问题只是关于计划,那么这将是一个非常好的例子。scheme和Common Lisp在这方面的差异很小,也很微妙,这并不能真正保证对一个问题的新答案,而不是语言之间的差异。
    macroexpand
    东西实际上不起作用,或者通常不有用。由于backquote表单的表示形式未定义,因此未定义应将其读入宏表单。'just syntax sugar'->概念上,而不是字面上。@Rain