球拍/方案将“ -0”转换为“ -0.0”

时间:2019-01-20 22:01:21

标签: scheme racket

我正在写一个简单的解释器 输出:+ inf或-inf用于以下计算:

(/ 0)
(/ 1 0)
(/ -0)

我注意到用0替换0可以给我我想要的行为。 但是我还没有想到将-0转换为-0.0exact->inexact失去了负号。 (exact->inexact -0)给出0.0

3 个答案:

答案 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+00000000#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