如何在球拍中直接使用阅读器宏?

  • 本文关键字: macros racket reader-macro
  • 更新时间 :
  • 英文 :


我试图定义一个读取字符串长度的读取器宏。管柱将被密封在竖条(管道)中。例如:

  • |yes|->3
  • ||->0
  • |The quick brown fox|->19
  • |||->1-管道字符可以通过在它前面加上反斜杠来转义。
  • (let ((x |world|)) (+ |hello| x))->10

我设法写了这个:

#lang racket
(define (handle-pipe in [count 0])
(define cur-char (read-char in))
(cond [(eqv? cur-char #|)
count]
[else
(when (and (eqv? cur-char #\)  ; Handle escape ("|").
(eqv? (peek-char in) #|))
(read-char in))  ; Consume |.
(handle-pipe in (+ count 1))]))
(parameterize ([current-readtable
(make-readtable (current-readtable)
#|
'terminating-macro
(lambda (char in src-name line col pos)
(handle-pipe in)))])
(eval (read (open-input-string "(let ((x |world|)) (+ |hello| x))"))
(make-base-namespace)))

返回10,如预期的那样。

现在的问题是:我想在我的球拍代码中直接使用阅读器宏,而不是必须将字符串输入(eval (read (open-input-string ...)))。例如,我想这样使用阅读器宏:

#lang racket
(define (handle-pipe in [count 0])
(define cur-char (read-char in))
(cond [(eqv? cur-char #|)
count]
[else
(when (and (eqv? cur-char #\)  ; Handle escape ("|").
(eqv? (peek-char in) #|))
(read-char in))  ; Consume |.
(handle-pipe in (+ count 1))]))
(current-readtable
(make-readtable (current-readtable)
#|
'terminating-macro
(lambda (char in src-name line col pos)
(handle-pipe in))))
(let ((x |world|))  ; Using the reader macro directly in Racket.
(+ |hello| x))

但是,当我运行上面的程序时,有一个错误消息:

my-program.rkt:20:9: world: unbound identifier
in: world
location...:
my-program.rkt:20:9
context...:
do-raise-syntax-error
for-loop
[repeats 1 more time]
finish-bodys
lambda-clause-expander
for-loop
loop
[repeats 3 more times]
module-begin-k
expand-module16
expand-capturing-lifts
temp118_0
temp91_0
compile15
temp85_0
standard-module-name-resolver

我做错了什么?如何在代码中使用读取器宏?

那不可能。在Racket中编译/求值的管道是:

  1. 扩展宏
  2. 评估扩展程序

您的current-readtable的配置是在步骤3中完成的,因此它不会影响步骤1中已经发生的事情。

你的第一个代码工作的原因是eval在你提供给它的数据上再次启动管道。

请注意,阅读器宏实际上是在创建新的#lang时使用的。但是因为你想让它与#lang racket一起工作,所以它不适用。

相关内容

  • 没有找到相关文章

最新更新