Racket 宏将除 s 表达式之外的所有内容字符串化

Racket macro to stringify all but s-expressions

我正在尝试弄清楚如何创建一个 racket 宏,它将简单地将所有内容转换为字符串,除了 s-expressions 之外,它将单独保留。

我已经弄清楚如何将所有内容字符串化

  #+begin_src racket
    (define-syntax (stringify-all stx)
      (syntax-case stx ()
        [(_ args ...)
         #'(begin
             (~s 'args)
             ...)]))

    (stringify-all one 2 (add1 2))
  #+end_src

  #+RESULTS:
  : "one"
  : "2"
  : "(add1 2)"

但是不知道如何测试某个东西是否是 s 表达式。

我该怎么做?

如果我们使用atom?程序的通常定义作为参考:

(defne (atom? exp)
  (and (not (null? exp))
       (not (pair? exp))))

然后我们可以定义一个 s-expression 谓词:

(define (s-exp? exp)
  (or (null? exp)
      (pair? exp)))

当然,您需要将此递归地应用于 s 表达式的每个元素。

"s-expression" 是语法 list/pair,因此您可以对 ()(a . b) 进行模式匹配,如下所示:

#lang racket

(require (for-syntax (only-in racket/format ~s)))

(define-for-syntax (compute stx)
  (syntax-case stx ()
    [() #'null]
    [(a . b) #`(cons #,(compute #'a) #,(compute #'b))]
    [_ (~s (syntax-e stx))]))

(define-syntax (stringify-all stx)
  (syntax-case stx ()
    [(_ args ...)
     #`(begin #,@(map compute (syntax->list #'(args ...))))]))

(stringify-all one 2 (add1 2))

;; "one"
;; "2"
;; '("add1" "2")