Чтобы сделать это, с буквальным текстом -0
вам придется изменить Reader так, чтобы -0
считывалось равным -0.0
, неточной версии. Чтобы быть последовательным, вы можете захотеть прочитать каждое число как неточное, независимо от того, имеет ли оно десятичную точку или нет.
Стоит отметить, что вы можете сделать это, добавив префикс числа #i
, например, #i-0
читает, равный -0.0
. Однако может показаться, что вы захотите изменить читатель так, чтобы каждое число читалось так же, как если бы к нему был добавлен префикс #i
, включая -0
.
Один из самых простых способов расширить читатель - это , читаемый . Вы можете создать функцию, которая расширяет читабельность следующим образом:
;; 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
, вам нужно поместить реализацию reader в your-language/lang/reader.rkt
. Вот это inexact-number/lang/reader.rkt
, где каталог inexact-number
установлен как пакет с одним набором (raco pkg install path/to/inexact-number
).
неточный номер / языки / 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 'inexact-number
"language path"
lang-reader-module-paths
wrap-reader
wrap-reader
identity))
Основная работа заключается в заполнении отверстий ....
в функции extend-readtable
. Внутри rt-proc
вы можете «заглянуть» во входной порт in
, чтобы узнать, является ли он номером, и, если это так, вызвать Racket reader на порт, к которому #i
добавлен в начало in
. Вы могли бы сделать это с помощью чего-то вроде input-port-append
:
(input-port-append #f (open-input-string "#i") in)
В контексте extend-readtable
, вот некоторый код, который выполняет просмотр и перечитывание:
;; Readtable -> Readtable
(define (extend-readtable orig-rt)
;; Char InputPort Any Nat Nat Nat -> Any
(define (rt-proc char in src ln col pos)
(define try-in (peeking-input-port in))
(define try (read/recursive try-in char orig-rt))
(cond
[(number? try)
;; read it as if it had #i on the front
(define prefix (string-append "#i" (string char)))
(define inexact-in
(input-port-append #f (open-input-string prefix) in))
(read-syntax/recursive src inexact-in #f orig-rt)]
[else
;; read normally
(read-syntax/recursive src in char orig-rt)]))
(make-readtable orig-rt
#f 'non-terminating-macro rt-proc))
Как только вы это сделаете, вы сможете использовать его следующим образом:
#lang inexact-number racket
-0
; => -0.0
(/ -0)
; => -inf.0
P.S. Теперь я сделал #lang inexact-number
доступным на сервере пакетов Racket, так как пакет inexact-number-lang
. Кстати, есть также #lang exact-decimal
, который имеет противоположный эффект, превращая числа типа 5.2
в точные рациональные числа.