Scheme 球拍范围内[S:N]的宏

Scheme 球拍范围内[S:N]的宏,scheme,racket,Scheme,Racket,如何创建宏,使S:N或[S:N]返回以S开头、以N结尾的一系列数字(步骤1)。基本上,它应该能够使用它来代替“范围内”。我试图创造类似的东西,但没有成功 编辑:我按照@soegaard的建议尝试了以下内容: my-top.rkt: #lang racket (define-syntax-rule (my-top S:N) (range S N) ) (provide (rename-out [my-top #%top])) test.rkt: #lang racket (requi

如何创建宏,使S:N或[S:N]返回以S开头、以N结尾的一系列数字(步骤1)。基本上,它应该能够使用它来代替“范围内”。我试图创造类似的东西,但没有成功

编辑:我按照@soegaard的建议尝试了以下内容:

my-top.rkt:

#lang racket
(define-syntax-rule (my-top S:N)
    (range S N) )

(provide (rename-out [my-top #%top]))
test.rkt:

#lang racket
 (require "my-top.rkt")

 (1:42)
但它没有运行。错误是:

 #%top: use does not match pattern: (#%top S:N) in: (#%top . 1:42)

[1:42]和1:42也不起作用。

以下是使
S:N
扩展到
(范围sn)
的步骤,其中
S
N
是数字

请注意,
S:N
是一个标识符。因此,未绑定的
S:N
是未绑定的标识符。对未绑定标识符的引用
n
扩展到
(#%top.n)
。 因此
1:42
扩展为
(#%top 1:42)

  • 制作一个宏
    my-top
    ,使
    (my-top S:N)
    扩展到
    (范围sn)
  • 将宏保存在文件
    my top.rkt
    中,并使用
    将其导出(提供(重命名为[my top#%top])
  • 像这样使用您的新构造:
  • 步骤1:

    #lang racket
    (require syntax/parse (for-syntax racket/match syntax/parse))
    
    (begin-for-syntax  
      ; contains-colon? : string -> boolean
      ;   does the string str contain a colon?
      (define (contains-colon? str)
        (regexp-match ".*:.*" str))
    
      ; split-colon-string-into-numbers : string -> (list number number)
      ;    for a string of the form N:S return a list consisting of the
      ;    numbers corresponsing to the substrings N and S
      (define (split-colon-string-into-numbers str)    
        (match (regexp-match "(.*):(.*)" str)
          [(list _ S-str N-str)
           (list (string->number S-str) (string->number N-str))]
          [_else
           (error 'split-colon-string-into-numbers
                  "expected string of the number <number>:<number>")])))
    
    ; SYNTAX (my-top . id)
    ;   (my-top . id)  behaves the same as (#%top . id)
    ;   except when id has the form N:S in which case
    ;   (my-top . id) behaves as (range N S)
    (define-syntax (my-top stx)
      (syntax-parse stx
        [(_my-top . identifier:id)     
         (define str (symbol->string (syntax-e #'identifier)))
         (cond
           [(contains-colon? str)
            (with-syntax ([(S N) (split-colon-string-into-numbers str)])
              (syntax/loc stx
                (range S N)))]
           [else
            #'(#%top . identifier)])]))
    
    ;;; Tests
    
    (my-top . 1:5)    ; evaluates to (1 2 3 4)
    (define foo 42)
    (my-top . foo)    ; evaluates to 42
    
    #朗球拍
    (需要语法/解析(用于语法敲打/匹配语法/解析))
    (从语法开始
    ;包含冒号?:字符串->布尔值
    ;字符串str是否包含冒号?
    (定义(包含冒号?str)
    (regexp匹配“.*:.*”str))
    ;将冒号字符串拆分为数字:字符串->(列表编号)
    ;对于形式为N:S的字符串,返回由
    ;对应于子字符串N和S的数字
    (定义(将冒号字符串拆分为数字)
    (匹配(regexp匹配“(.*):(.*)”str)
    [(列表us-str N-str)
    (列表(字符串->编号S-str)(字符串->编号N-str))]
    其他的
    (错误“将冒号字符串拆分为数字”
    “应为数字字符串:”)]))
    ; 语法(my top.id)
    ;   (my top.id)的行为与(#%top.id)相同
    ;   除非id的形式为N:S,在这种情况下
    ;   (my top.id)的行为方式为(范围N-S)
    (定义语法(我的顶级stx)
    (语法解析stx)
    [(_my-top.identifier:id)
    (定义str(符号->字符串(语法-e#'标识符)))
    (续)
    [(包含冒号?str)
    (使用语法([(sn)(将冒号字符串拆分为数字str)])
    (语法/loc stx)
    (范围S-N))]
    [其他
    #“(#%top.identifier)])])
    ;;; 测验
    (我的头像1:5);计算结果为(1 2 3 4)
    (定义foo 42)
    (我的top.foo);评估结果为42
    
    以下是将
    S:N
    扩展到
    (范围sn)
    的步骤,其中
    S
    N
    是数字

    请注意,
    S:N
    是一个标识符。因此,未绑定的
    S:N
    是未绑定的标识符。对未绑定标识符的引用
    n
    扩展到
    (#%top.n)
    。 因此
    1:42
    扩展为
    (#%top 1:42)

  • 制作一个宏
    my-top
    ,使
    (my-top S:N)
    扩展到
    (范围sn)
  • 将宏保存在文件
    my top.rkt
    中,并使用
    将其导出(提供(重命名为[my top#%top])
  • 像这样使用您的新构造:
  • 步骤1:

    #lang racket
    (require syntax/parse (for-syntax racket/match syntax/parse))
    
    (begin-for-syntax  
      ; contains-colon? : string -> boolean
      ;   does the string str contain a colon?
      (define (contains-colon? str)
        (regexp-match ".*:.*" str))
    
      ; split-colon-string-into-numbers : string -> (list number number)
      ;    for a string of the form N:S return a list consisting of the
      ;    numbers corresponsing to the substrings N and S
      (define (split-colon-string-into-numbers str)    
        (match (regexp-match "(.*):(.*)" str)
          [(list _ S-str N-str)
           (list (string->number S-str) (string->number N-str))]
          [_else
           (error 'split-colon-string-into-numbers
                  "expected string of the number <number>:<number>")])))
    
    ; SYNTAX (my-top . id)
    ;   (my-top . id)  behaves the same as (#%top . id)
    ;   except when id has the form N:S in which case
    ;   (my-top . id) behaves as (range N S)
    (define-syntax (my-top stx)
      (syntax-parse stx
        [(_my-top . identifier:id)     
         (define str (symbol->string (syntax-e #'identifier)))
         (cond
           [(contains-colon? str)
            (with-syntax ([(S N) (split-colon-string-into-numbers str)])
              (syntax/loc stx
                (range S N)))]
           [else
            #'(#%top . identifier)])]))
    
    ;;; Tests
    
    (my-top . 1:5)    ; evaluates to (1 2 3 4)
    (define foo 42)
    (my-top . foo)    ; evaluates to 42
    
    #朗球拍
    (需要语法/解析(用于语法敲打/匹配语法/解析))
    (从语法开始
    ;包含冒号?:字符串->布尔值
    ;字符串str是否包含冒号?
    (定义(包含冒号?str)
    (regexp匹配“.*:.*”str))
    ;将冒号字符串拆分为数字:字符串->(列表编号)
    ;对于形式为N:S的字符串,返回由
    ;对应于子字符串N和S的数字
    (定义(将冒号字符串拆分为数字)
    (匹配(regexp匹配“(.*):(.*)”str)
    [(列表us-str N-str)
    (列表(字符串->编号S-str)(字符串->编号N-str))]
    其他的
    (错误“将冒号字符串拆分为数字”
    “应为数字字符串:”)]))
    ; 语法(my top.id)
    ;   (my top.id)的行为与(#%top.id)相同
    ;   除非id的形式为N:S,在这种情况下
    ;   (my top.id)的行为方式为(范围N-S)
    (定义语法(我的顶级stx)
    (语法解析stx)
    [(_my-top.identifier:id)
    (定义str(符号->字符串(语法-e#'标识符)))
    (续)
    [(包含冒号?str)
    (使用语法([(sn)(将冒号字符串拆分为数字str)])
    (语法/loc stx)
    (范围S-N))]
    [其他
    #“(#%top.identifier)])])
    ;;; 测验
    (我的头像1:5);计算结果为(1 2 3 4)
    (定义foo 42)
    (我的top.foo);评估结果为42
    
    @soegaard的回答提供了一个基于
    #%top
    的解决方案,当
    s
    N
    是文字整数且
    s:N
    未定义为标识符时,该解决方案扩展了
    s:N
    。但是,也可以使用读卡器宏执行此操作

    我已经做了两个版本:一个简单的版本只适用于文字整数,另一个版本适用于任意表达式,包括变量

    文本整数版本 这个简单的版本覆盖了
    [
    以开始像
    [S:N]
    这样的范围表达式,其中
    S
    N
    是文字整数。在
    [
    之后,它读取数字字符直到找到一个
    ,然后读取更多的数字字符直到找到一个
    ]
    。它将数字字符字符串转换为整数,并将这些整数放入表示调用
    range
    函数的列表中

    它的用法如下:

    #lang colon-range
    ;; simple range by itself
    [1:42]
    ;; using a range within a more complicated expression
    (for/list ((i [2:42])
               #:when
               (for/and ((j [2:41]) #:when (< j i))
                 (not (= 0 (remainder i j)))))
      i)
    
    #lang colon-range
    ;; simple range by itself
    [1:42]
    ;; using a range within a more complicated expression
    (for/list ([i [2:42]]
               #:when
               (for/and ([j [2:i]]) ; can refer to a variable
                 (not (= 0 (remainder i j)))))
      i)
    (define two 2)
    (for/list ([i [two:42]] ; can refer to a variable for the start
               #:when
               (for/and ([j [two:(+ 1 (exact-floor (sqrt i)))]]) ; can use arbitrary expressions
                 (not (= 0 (remainder i j)))))
      i)
    
    任意表达式版本 这个版本覆盖了
    [
    。它将
    定义为一个分隔符,这样
    a:b
    读取的内容与
    a:b
    读取的内容相同,它将
    [
    定义为一个读取普通列表并随后进行处理的读卡器宏。因此它将首先将
    [a:b]
    作为三个元素的列表
    #lang colon-range
    ;; simple range by itself
    [1:42]
    ;; using a range within a more complicated expression
    (for/list ([i [2:42]]
               #:when
               (for/and ([j [2:i]]) ; can refer to a variable
                 (not (= 0 (remainder i j)))))
      i)
    (define two 2)
    (for/list ([i [two:42]] ; can refer to a variable for the start
               #:when
               (for/and ([j [two:(+ 1 (exact-floor (sqrt i)))]]) ; can use arbitrary expressions
                 (not (= 0 (remainder i j)))))
      i)
    
    ;; s-exp syntax/module-reader is a language for defining new languages.
    #lang s-exp syntax/module-reader
    racket
    #:wrapper1 (lambda (th)
                 (parameterize ([current-readtable
                                 (make-colon-range-readtable (current-readtable))])
                   (th)))
    
    ;; This extends the orig-readtable with entries for `[` and `:` to convert
    ;; `[S:N]` to `(range S N)`.
    (define (make-colon-range-readtable orig-readtable)
      (make-readtable orig-readtable
        #\[ 'terminating-macro colon-range-proc
        #\: 'terminating-macro separator-proc))
    
    ;; This is the function that the new readtable will use when in encounters a `[`
    (define (colon-range-proc char in src ln col pos)
      ;; This reads the list of things ending with the character that closes `char`
      ;; The #f means it uses the racket reader for the first step, so that `[`
      ;; uses the normal behavior, grouping expressions into a reader-level list
      (define lst (read-syntax/recursive src in char #f))
      ;; This matches on that list to determine whether it has the shape `[S : N]`
      (syntax-case lst (:)
        [[S : N]
         ;; if it is, translate it to `(range S N)`
         (list 'range #'S #'N)]
        [_
         ;; otherwise leave it alone
         lst]))
    
    ;; This doesn't read any further and simply returns an identifier containing char,
    ;; so that it can act like a separator
    (define (separator-proc char in src ln col pos)
      (char->identifier char (list src ln col pos 1)))
    
    (define (char->identifier char srcloc)
      (datum->syntax #f (string->symbol (string char)) srcloc))