scheme - 花括号 {} 替换 Racket 中的 'begin'

标签 scheme racket

是否可以有一个宏使用大括号 {} 来表示一个语句 block ,以替换“开始”关键字。因此,而不是:

(if (condition)
    (begin 
        (statement1)
        (statement2)
        (statement3)
        (statement4))
    (else-statement))

我们可以使用:
(if (condition) {
        (statement1)
        (statement2)
        (statement3)
        (statement4) }
    (else-statement))

如何实现?感谢您的回答。

最佳答案

这是完全可能的,并且有几种方法可以做到这一点。 (开始之前的快速说明,我将使用 block 而不是 begin,因为它在内部定义中表现更好。)

方法一:重新定义#%app
一种略显老套的方法是重新定义函数应用程序的含义,以便对花括号进行特殊处理。您可以通过定义 #%app 来做到这一点。宏:

#lang racket
(require racket/block syntax/parse/define (prefix-in - racket))
;; This #%app macro redefines what function application means so that
;; { def-or-expr ... } expands into (block def-or-expr ...)
;; Otherwise it uses normal function application
(define-syntax-parser #%app
  [{_ def-or-expr:expr ...}
   #:when (equal? #\{ (syntax-property this-syntax 'paren-shape))
   ;; group them in a block
   #'(block def-or-expr ...)]
  [(_ f:expr arg ...)
   #:when (not (equal? #\{ (syntax-property this-syntax 'paren-shape)))
   ;; expand to the old #%app form, from (prefix-in - racket)
   #'(-#%app f arg ...)])
;; using it:
(define (f x)
  (if (< 5 x) {
        (define y (- x 5))
        (f y)
      }
      x))
(f 1) ; 1
(f 5) ; 5
(f 6) ; 1
(f 10) ; 5
(f 11) ; 1

方法二:扩展阅读器

另一种方法是定义一个新的 #lang语言并使用 { 的不同条目扩展可读表特点。让我去做吧……

定义 #lang语言,您需要将阅读器实现放在 your-language/lang/reader.rkt .这里是 curly-block/lang/reader.rkt ,其中 curly-block目录安装为单一集合包 ( raco pkg install path/to/curly-block )。

curly-block/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-curly-block-readtable (current-readtable))])
               (th)))

;; This extends the orig-readtable with an entry for `{` that translates
;; { def-or-expr ... } into (block def-or-expr ...)
(define (make-curly-block-readtable orig-readtable)
  (make-readtable orig-readtable
    #\{ 'terminating-macro curly-block-proc))

;; This is the function that the new readtable will use when in encounters a `{`
(define (curly-block-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))
  (cons 'block lst))

使用它:
#lang curly-block
(require racket/block)
(define (f x)
  (if (< 5 x) {
        (define y (- x 5))
        (f y)
      }
      x))
(f 1) ; 1
(f 5) ; 5
(f 6) ; 1
(f 10) ; 5
(f 11) ; 1

关于scheme - 花括号 {} 替换 Racket 中的 'begin',我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38369817/

相关文章:

lisp - 一个基本的 Lisp 程序错误

console - 如何使用控制台作为Guile Scheme的输入和输出?

scheme - 将 lambda 函数传递给 Scheme 中的 lambda 函数

scheme - 哪种方案实现最容易嵌入到 C/C++ 程序中?

racket - Redex 不匹配

string - 计划中的换行符( Racket )

macros - cadr、caddr 等的可变版本

scheme - 从 a 到 b 的所有整数的总和,我的代码有什么问题?

lisp - 元循环评估器,实现环境

struct - 透明结构的缺点?