В Racket такие вещи, как 10K
, являются идентификаторами , которые обычно относятся к переменным.Есть два способа превратить их в числа:
1: переопределить, что означают «неопределенные» идентификаторы
Вы можете переопределить, что делать с неопределенным идентификатором, определив макрос #%top
.
#lang racket
(require syntax/parse/define
(only-in racket [#%top old-#%top]))
(define-syntax-parser #%top
[(_ . x:id)
#:when (id-has-a-k-at-the-end? #'x)
(transform-id-into-number #'x)]
[(_ . x)
#'(old-#%top . x)])
Однако, здесь есть небольшая проблема.Если в вашей программе есть какие-либо идентификаторы или переменные с K, они могут переопределить любые числа, которые были написаны таким образом.Вы должны быть осторожны, чтобы случайно не переопределить что-то, что должно было быть числом.
2: создать расширение считывателя, которое превращает их в числа вместо идентификаторов
Это займет больше времени, но это ближе к «правильному» способу сделать это, так как он позволяет избежать конфликтов, когда переменные имеют конец К.
Один из самых простых способов расширить читатель - это readtable .Вы можете создать функцию, которая расширяет читабельность следующим образом:
;; Readtable -> Readtable
(define (extend-readtable orig-rt)
;; Char InputPort Any Nat Nat Nat -> Any
(define (rt-proc char in src ln col pos)
....)
...
(make-readtable orig-rt
#f 'non-terminating-macro rt-proc
...))
Чтобы использовать это для определения языка #lang
, вам нужно поместить реализацию читателя в your-language/lang/reader.rkt
.Вот это number-with-k/lang/reader.rkt
, где каталог number-with-k
установлен как пакет с одним набором (raco pkg install path/to/number-with-k
).
number-with-k / lang / reader.rkt
#lang racket
(provide (rename-out [-read read]
[-read-syntax read-syntax]
[-get-info get-info]))
(require syntax/readerr
syntax/module-reader)
;; Readtable -> Readtable
(define (extend-readtable orig-rt)
;; Char InputPort Any Nat Nat Nat -> Any
(define (rt-proc char in src ln col pos)
....)
...
(make-readtable orig-rt
#f 'non-terminating-macro rt-proc))
;; [X ... -> Y] -> [X ... -> Y]
(define ((wrap-reader rd) . args)
(parameterize ([current-readtable (extend-readtable (current-readtable))])
(apply rd args)))
(define-values [-read -read-syntax -get-info]
(make-meta-reader 'number-with-k
"language path"
lang-reader-module-paths
wrap-reader
wrap-reader
identity))
Основная работа заключается в заполнении ....
отверстий в функции extend-readtable
.Например, вы можете заставить его распознавать идентификаторы, оканчивающиеся на K
, например:
;; Readtable -> Readtable
(define (extend-readtable orig-rt)
;; Char InputPort Any Nat Nat Nat -> Any
(define (rt-proc char in src ln col pos)
(define v (read-syntax/recursive src in char orig-rt #f))
(cond
[(and (identifier? v) (id-has-a-k-at-the-end? v))
(transform-id-into-number v)]
[else
v]))
(make-readtable orig-rt
#f 'non-terminating-macro rt-proc))
Как только это будет сделано, и у вас будет установлен каталог number-with-k
в виде пакета, вы сможетеиспользуйте #lang number-with-k
вот так:
#lang number-with-k racket
(+ 12K 15)
; => 12015