Ракетка / Схема, конвертирующая "-0" в "-0.0" - PullRequest
0 голосов
/ 21 января 2019

Я пишу простой интерпретатор, который должен вывести: + inf или -inf для следующих вычислений:

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

Я заметил, что замена 0 на 0.0 дает мне поведение, которое я хочу.Но я не решил преобразовать -0 в -0.0.exact->inexact теряет отрицательный знак.(exact->inexact -0) дает 0.0.

Ответы [ 3 ]

0 голосов
/ 21 января 2019

Чтобы сделать это, с буквальным текстом -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 в точные рациональные числа.

0 голосов
/ 21 января 2019

-0 не существует!Если вы введете что-то глупое, например (define x -0), и нажмете Macro stepper # '> перед любыми преобразованиями, вы увидите, что оно прочитало это как (define x 0).Знак усекается читателем, поскольку целые числа не имеют положительного и отрицательного нуля, как в IEEE754.Таким образом, если вы не создадите свой собственный язык с вашим собственным считывателем, который может различать нуль со знаком, сопоставленный со структурой данных, которая его поддерживает, вы не сможете решить эту проблему.

IEEE754 с плавающей запятой имеет знак в качестве своего собственного бита, и поэтому каждое число, включая 0, может быть как положительным, так и отрицательным.

Что касается стандарта Схемы: до R6RS не требовалось полной числовой башни, и в отчете даже упоминается, что Схема с плавающей запятой может быть полезной.Таким образом, я считаю, что некоторые реализации R5RS на самом деле могут читать -0 как -0.0.

0 голосов
/ 21 января 2019

Это потому, что -0 в Racket - это тот же буквальный элемент данных, который также может быть записан как 0, +0, 0000000, #e0, #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 и -0 не выдавали одно и то же значение. Я не думаю, что есть встроенный параметр для выполнения того, что вы хотите (есть для многих других настроек считывателя), но вы можете сделать это, создав пользовательский readtable .

Мне понадобится больше контекста, чтобы дать вам дальнейшие указания (например, вы говорите, что пишете «переводчика», что не является обычным способом создания DSL в Racket), но мое первое предположение: вместо того, чтобы повторно реализовывать разбор чисел, вы можете отобразить - на «не-завершающий макрос» и обработать остальное на уровне расширителя (или интерпретатора).

...