我正在写一个简单的解释器 输出:+ inf或-inf用于以下计算:
(/ 0)
(/ 1 0)
(/ -0)
我注意到用0替换0可以给我我想要的行为。
但是我还没有想到将-0
转换为-0.0
。
exact->inexact
失去了负号。
(exact->inexact -0)
给出0.0
。
答案 0 :(得分:5)
要执行此操作,必须使用原义文本-0
更改Reader,以使-0
读取的内容等于-0.0
(不精确的版本)。为了保持一致,您可能希望将每个数字都读为不精确的数字,无论它是否有小数点。
值得注意的是,您可以通过在数字#i
前面加上前缀来完成此操作,例如#i-0
读为等于-0.0
。但是,听起来您可能想要更改阅读器,以使每个数字的读取方式都与在其前面加上#i
的{{1}}相同,包括-0
。
使用readtable是扩展阅读器的更简单方法之一。您可以创建一个扩展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
中。这里是inexact-number/lang/reader.rkt
,其中inexact-number
目录是作为单个集合软件包(raco pkg install path/to/inexact-number
)安装的。
inexact-number / 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 'inexact-number
"language path"
lang-reader-module-paths
wrap-reader
wrap-reader
identity))
主要工作是填充....
函数中的extend-readtable
孔。在rt-proc
中,可以将其“窥视”到输入端口in
中以查看其是否为数字,如果是,请在具有#i
的端口上调用Racket阅读器附加到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
作为inexact-number-lang
的软件包在Racket软件包服务器上提供了。顺便说一句,还有#lang exact-decimal
,它的影响与将5.2
之类的数字变成精确的有理数相反。
答案 1 :(得分:2)
这是因为球拍中的-0
是相同的文字数据,也可以写成0
,+0
,0000000
,#e0
,{{ 1}},#e-0/1
或其他各种方式。所有这些语法从阅读器产生的值都非常相同,这是一个精确的整数。与浮点数不同,确切的数字没有带符号的零。为了说明:
-00000/1
要获得所需的行为,您需要调整阅读器层,以使> (exact-integer? 0)
#t
> (exact-integer? +0)
#t
> (exact-integer? -0)
#t
> (eq? +0 -0)
#t
> (eq? -0 0)
#t
和0
不会产生相同的值。我认为没有内置参数可以执行您想要的操作(许多其他阅读器自定义功能),但是您可以通过创建自定义readtable来实现。
我需要更多的上下文信息来为您提供进一步的指导(例如,您说您正在编写“解释器”,这不是在Racket中制作DSL的常用方法),但是我的第一个倾向是,而不是重新实现数字解析,您可以将-0
映射到“非终止宏”,并在扩展器(或解释器)层中处理其余部分。
答案 2 :(得分:1)
-0
不存在!如果您输入诸如(define x -0)
之类的愚蠢内容,然后按 Macro stepper#'> (宏步进器#'> ),则在进行任何转换之前,您会看到它已被读为(define x 0)
。由于整数不像IEEE754那样具有正零和负零,因此读者会截断该符号。因此,除非您用自己的阅读器来创建自己的语言,该语言可以区分映射到支持该符号的数据结构的带符号零,否则您将无法解决此问题。
IEEE754浮点数具有符号,因为它是自己的位,因此每个数字(包括0)都可以为正和负。
关于计划标准:在R6RS之前,没有完整的数字塔的要求,该报告甚至提到仅浮点的计划可能有用。因此,我相信R5RS的某些实现实际上可能会将-0
读为-0.0
。