Scheme 球拍范围内[S:N]的宏
如何创建宏,使S:N或[S:N]返回以S开头、以N结尾的一系列数字(步骤1)。基本上,它应该能够使用它来代替“范围内”。我试图创造类似的东西,但没有成功 编辑:我按照@soegaard的建议尝试了以下内容: my-top.rkt: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
#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])
#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])
#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))