我试图定义一个读取字符串长度的读取器宏。管柱将被密封在竖条(管道)中。例如:
|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中编译/求值的管道是:
读- 扩展宏
- 评估扩展程序
您的current-readtable
的配置是在步骤3中完成的,因此它不会影响步骤1中已经发生的事情。
你的第一个代码工作的原因是eval
在你提供给它的数据上再次启动管道。
请注意,阅读器宏实际上是在创建新的#lang
时使用的。但是因为你想让它与#lang racket
一起工作,所以它不适用。