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
|
evaluated through @racket[load] and @racket[eval] cannot automatically
|
||||||
access bindings defined within the module.
|
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]}
|
@subsection{Non-@|r5rs| Bindings from @racketmodname[r5rs]}
|
||||||
|
|
|
@ -242,55 +242,18 @@
|
||||||
;; None, so just use R5RS quote:
|
;; None, so just use R5RS quote:
|
||||||
#'(r5rs:quote form))]))
|
#'(r5rs:quote form))]))
|
||||||
|
|
||||||
;; Copied from R5rS, but with an added `let' around body,
|
;; The difference between R5RS `letrec` and Racket `letrec` (or
|
||||||
;; and with optimization for precedure letrecs
|
;; R6RS `letrec*`) is that all right-hand sides are evaluated
|
||||||
(define-for-syntax (immediate-value? stx)
|
;; before any binding is initialized. We can get this effect
|
||||||
(let ([v (syntax-e stx)])
|
;; by using `letrec-values` and a single clause:
|
||||||
(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]))))
|
|
||||||
(define-syntax (r5rs:letrec stx)
|
(define-syntax (r5rs:letrec stx)
|
||||||
(syntax-case stx (r5rs:lambda)
|
(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 ...)
|
((r5rs:letrec ((var1 init1) ...) body ...)
|
||||||
(syntax/loc stx
|
(syntax/loc stx
|
||||||
(r5rs:letrec "generate_temp_names"
|
(letrec-values ([(var1 ...)
|
||||||
(var1 ...)
|
(values init1 ...)])
|
||||||
()
|
(r5rs:body
|
||||||
((var1 init1) ...)
|
body ...))))))
|
||||||
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 ...)))))
|
|
||||||
|
|
||||||
(define-syntax (r5rs:lambda stx)
|
(define-syntax (r5rs:lambda stx)
|
||||||
;; Convert rest-arg list to mlist, and use r5rs:body:
|
;; 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
|
@racket[string-upcase], and @racket[string-titlecase] are not
|
||||||
determined as specified by Unicode Standard Annex #29.}
|
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,
|
@item{A custom textual port must represent positions using integers,
|
||||||
and the positions must correspond to bytes in a UTF-8 encoding
|
and the positions must correspond to bytes in a UTF-8 encoding
|
||||||
of the port's data. For custom ports (byte or character) that
|
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
|
@racketidfont{#%top}, and @racketidfont{#%top-interaction} are
|
||||||
imported into every library and program, and at every phase
|
imported into every library and program, and at every phase
|
||||||
level for which the library or program has imports.}
|
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