r{5,6}rs: change letrec
to signal use-before-definition errors
The old `letrec` implementation used the R5RS macro with `undefined`, which differents from Racket's `letrec` in that no variable is initialized until all right-hand sides are evaluated. It turns out to be simpler and produce the same effect to use `letrec-values` with a single clause: `(letrec ([x e1] [y e2]) ....)` -> `(letrec-values ([(x y) (values e1 e2)]) ....)`.
This commit is contained in:
parent
4216f3b666
commit
6112d337b3
|
@ -134,6 +134,13 @@ not allow redefinition of top-level bindings, and expressions
|
|||
evaluated through @racket[load] and @racket[eval] cannot automatically
|
||||
access bindings defined within the module.
|
||||
|
||||
|
||||
@history[#:changed "6.0.1.4" @elem{When an identifier bound by
|
||||
@racket[letrec] is referenced
|
||||
before it is initialized, an
|
||||
exception is raised, instead of
|
||||
producing @|undefined-const|.}]
|
||||
|
||||
@; --------------------
|
||||
|
||||
@subsection{Non-@|r5rs| Bindings from @racketmodname[r5rs]}
|
||||
|
|
|
@ -242,55 +242,18 @@
|
|||
;; None, so just use R5RS quote:
|
||||
#'(r5rs:quote form))]))
|
||||
|
||||
;; Copied from R5rS, but with an added `let' around body,
|
||||
;; and with optimization for precedure letrecs
|
||||
(define-for-syntax (immediate-value? stx)
|
||||
(let ([v (syntax-e stx)])
|
||||
(or (number? v)
|
||||
(boolean? v)
|
||||
(string? v)
|
||||
(syntax-case stx (r5rs:lambda quote r5rs:quote #%datum)
|
||||
[(r5rs:lambda . _rest) #t]
|
||||
[(quote . _) #t]
|
||||
[(r5rs:quote . _) #t]
|
||||
[(#%datum . _) #t]
|
||||
[_ #f]))))
|
||||
;; The difference between R5RS `letrec` and Racket `letrec` (or
|
||||
;; R6RS `letrec*`) is that all right-hand sides are evaluated
|
||||
;; before any binding is initialized. We can get this effect
|
||||
;; by using `letrec-values` and a single clause:
|
||||
(define-syntax (r5rs:letrec stx)
|
||||
(syntax-case stx (r5rs:lambda)
|
||||
((r5rs:letrec ((var1 rhs) ...) body ...)
|
||||
(andmap immediate-value? (syntax->list #'(rhs ...)))
|
||||
(syntax/loc stx (letrec ((var1 rhs) ...) (r5rs:body body ...))))
|
||||
((r5rs:letrec ((var1 init1) ...) body ...)
|
||||
(syntax/loc stx
|
||||
(r5rs:letrec "generate_temp_names"
|
||||
(var1 ...)
|
||||
()
|
||||
((var1 init1) ...)
|
||||
body ...)))
|
||||
((r5rs:letrec "generate_temp_names"
|
||||
()
|
||||
(temp1 ...)
|
||||
((var1 init1) ...)
|
||||
body ...)
|
||||
(syntax/loc stx
|
||||
(let ((var1 undefined) ...)
|
||||
(let ((temp1 init1) ...)
|
||||
(set! var1 temp1)
|
||||
...
|
||||
(let ()
|
||||
(r5rs:body
|
||||
body ...))))))
|
||||
((r5rs:letrec "generate_temp_names"
|
||||
(x y ...)
|
||||
(temp ...)
|
||||
((var1 init1) ...)
|
||||
body ...)
|
||||
(syntax/loc stx
|
||||
(r5rs:letrec "generate_temp_names"
|
||||
(y ...)
|
||||
(newtemp temp ...)
|
||||
((var1 init1) ...)
|
||||
body ...)))))
|
||||
(letrec-values ([(var1 ...)
|
||||
(values init1 ...)])
|
||||
(r5rs:body
|
||||
body ...))))))
|
||||
|
||||
(define-syntax (r5rs:lambda stx)
|
||||
;; Convert rest-arg list to mlist, and use r5rs:body:
|
||||
|
|
|
@ -382,10 +382,6 @@ several known ways:
|
|||
@racket[string-upcase], and @racket[string-titlecase] are not
|
||||
determined as specified by Unicode Standard Annex #29.}
|
||||
|
||||
@item{When an identifier bound by @racket[letrec] or @racket[letrec*]
|
||||
is referenced before it is bound, an exception is not raised;
|
||||
instead, the reference produces @|undefined-const|.}
|
||||
|
||||
@item{A custom textual port must represent positions using integers,
|
||||
and the positions must correspond to bytes in a UTF-8 encoding
|
||||
of the port's data. For custom ports (byte or character) that
|
||||
|
@ -407,9 +403,13 @@ several known ways:
|
|||
@racketidfont{#%top}, and @racketidfont{#%top-interaction} are
|
||||
imported into every library and program, and at every phase
|
||||
level for which the library or program has imports.}
|
||||
|
||||
]
|
||||
|
||||
@history[#:changed "6.0.1.4" @elem{When an identifier bound by
|
||||
@racket[letrec] or @racket[letrec*]
|
||||
is referenced before it is initialized,
|
||||
an exception is raised, instead of
|
||||
producing @|undefined-const|.}]
|
||||
|
||||
@; ----------------------------------------------------------------------
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user