[S:N]的宏在Racket的范围内

时间:2016-07-15 04:11:17

标签: scheme racket

如何创建宏以使S:N或[S:N]返回以S开头并以N结尾的数字范围(步骤1)。基本上,它应该能够用它来代替范围内的'。我尝试创建类似Curly brackets {} to replace 'begin' in Racket的东西,但不能。

编辑:我尝试按照@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也不起作用。

2 个答案:

答案 0 :(得分:5)

Here are the steps to make S:N expand to (range S N) where S and N are numbers.

Note that S:N is an identifier. Therefore an unbound S:N is an unbound identifier. An reference to an unbound identifiers n expand to (#%top . n). Therefore 1:42 expands into (#%top 1:42).

  1. Make a macro my-top such that (my-top S:N) expands to (range S N).
  2. Save your macro in file my-top.rkt and export it using (provide (rename-out [my-top #%top])).
  3. Use your new construct like this:

.

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

Step 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

答案 1 :(得分:5)

@ soegaard的回答提供了一个基于#%top的解决方案,当S:NS是字面整数且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) 函数调用的列表中。

它会像这样使用:

((i ....))

请注意,我使用的是([i ....])而不是更常见的[,因为我暂时无法使用]#lang colon-range

要实现colon-range/lang/reader.rkt语言,您应该将阅读器实现放在colon-range中,其中;; 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 an entry for `[` to convert ;; `[1:42]` to `(range 1 42)`. In this simplistic implementation, they ;; have to be literal numbers, so it can't refer to a variable. (define (make-colon-range-readtable orig-readtable) (make-readtable orig-readtable #\[ 'terminating-macro colon-range-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) (define S (read-int-until #\: in src)) (define N (read-int-until #\] in src)) (list 'range S N)) ;; This reads until it finds the given char (consuming it), ;; and returns an exact integer (define (read-int-until char in src) (define str (list->string (read-numeric-chars-until char in src))) (define i (string->number str)) (unless (exact-integer? i) (error 'read "expected an exact integer, given `~a`" str)) i) ;; This reads until it finds the given char (consuming it), and returns a list ;; of characters. Each char it reads before that needs to be a numeric char, ;; otherwise it throws an error. (define (read-numeric-chars-until char in src) (define c (read-char in)) (cond [(eof-object? c) (error 'read "end-of-file: expected either a number or a `~a`, given `~a`" char c)] [(char=? char c) (list)] [(char-numeric? c) (cons c (read-numeric-chars-until char in src))] [else (error 'read "expected either a number or a `~a`, given `~a`" char c)])) 作为单一集合包安装。

[

任意表达式版本

此版本会覆盖::。它将a:b定义为分隔符,以便a : b读取与[相同的内容,并将[a : b]定义为读取器宏,读取正常列表并在之后对其进行处理。因此,它会首先将(range 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)

可以像这样使用:

colon-range/lang/reader.rkt

实现看起来像这样(再次在;; 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)) 中)。这些评论解释了它正在做的一些事情。

XPCollection coll = new XPCollection(uow, typeof(HataBildirim), CriteriaOperator.Parse("[HataTespitYeri] = ? and [Tarih] > ? and ([CreatedOn] > ? OR [LastModifiedOn] > ?)",hatatespityeri, convservertarih, senkdate, senkdate));