在 Scheme 中定义一个宏来创建花哨的子列表

Defining a macro in Scheme to create fancy sublist

我想解决一个关于宏的问题:

Define this construct: (subl e_1 e_2 ... -> e_i ... e_j <- e_j+1 ... e_n); its evalutation returns the sublist (e_i ... e_j). E.g. (subl 1 -> 2 3 4 <- 5 6) should be (2 3 4).

我尝试解决了(以下是部分解决方案)但是没有用...

(define-syntax subl
  (syntax-rules(> <)
    ((_  x y ... > x ... y < c v )
     (begin
       '(x y)))))

错误是:

syntax-rules: misplaced ellipsis in pattern (follows other ellipsis) in: ...

您需要制作将源代码转换为更易于处理的内容的模式:

(define-syntax subl
  (syntax-rules (-> <-)
    ((_ "build-list" end middle before)
     (subl "execute" before middle end))
    ((_ "build-list" before () () -> . rest)
     (subl "build-list" () () before . rest ))
    ((_ "build-list" middle () before <- . rest)
     (subl "build-list" () middle before . rest ))
    ((_ "build-list" (xs ...) the others x . rest)
     (subl "build-list" (xs ... x) the others . rest))
    ((_ "execute" before middle end)
     ; I guess this is wrong
     'middle)
    ((_ . rest)
     (subl "build-list" () () () . rest))))

(subl a b c -> d e f <- f g) ; == '(d e f) => (d e f)

所做的是将您希望代码具有的格式更改为更简单的格式。 (subl a b c -> d e f <- f g) => (subl "execute" (a b c) (d e f) (f g)) 那么您在 "execute" 的模式中就有了您想要的逻辑。

你不能在一对括号中使用多个省略号,如果你使用关键字 -><- 语言不够聪明,不知道在哪里停止也没关系扩展。

示例:
(_ x ...) 是合法的,x ... 捕获结束括号之前的所有内容。
(_ x y ... z) 是合法的,x 匹配开头的单个元素,y ... 捕获所有内容,但最后一个元素和 z 匹配结尾的单个元素。
(_ (x ...) y ...) 是合法的,x ... 捕获内括号内的所有内容,y ... 捕获外括号内的所有内容。
(_ x ... y ...) 合法,因为您不知道将这两个组扩展到多远。

所以你要分多个步骤解决这个问题:移除->之前的元素,移除<-之后的元素,最后捕获中间的列表。

(define-syntax subl
  (syntax-rules (-> <-)
    ((_ -> x ... <-)
     '(x ...))
    ((_ -> x ... y)
     (subl -> x ...))
    ((_ x y ...)
     (subl y ...))))

您可以使用 Racket 的 syntax-parse (since you included the 标签来实现您的宏 :)),它具有比 syntax-rules.

更具表现力的模式语言
#lang racket
(require (for-syntax syntax/parse))

(define-syntax (subl stx)
  (syntax-parse stx #:datum-literals (-> <-)
    [(_ a b ... -> c ... d <- e ... f)
     #:when (printf "a: ~a\n" (syntax->datum #'a))
     #:when (printf "bs: ~a\n" (syntax->datum #'(b ...)))
     #:when (printf "cs: ~a\n" (syntax->datum #'(c ...)))
     #:when (printf "d: ~a\n" (syntax->datum #'d))
     #:when (printf "es: ~a\n" (syntax->datum #'(e ...)))
     #:when (printf "f: ~a\n" (syntax->datum #'f))
     #''(c ... d)]))

(subl 1 -> 2 3 4 <- 5 6)

产生:

a: 1
bs: ()
cs: (2 3)
d: 4
es: (5)
f: 6
'(2 3 4)