[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
lexically scoped Load
`Load' as defined in Revised^3.99 Report on the Algorithmic Language
Scheme [Draft August 31, 1989] has several problems owing to its
dynamic nature:
1) `load' opens a back door to eval:
(define global-eval-return #f)
(define (eval frob)
(call-with-output-file "tmp1"
(lambda (file)
(write (list 'set! 'global-eval-return frob) file)))
(load "tmp1")
global-eval-return)
2) `load' does not specifiy the lexical environment in which the forms
are evaluated.
3) A scheme program that includes a `load' in it will cause the run
time system to need to include either an interpreter or
compiler.
Making `load' a derived expression rather than a procedure solves all
these problems. I will call it `include' in order to avoid name
confusion. The Report entry would be something like:
------------------------------------------------------------------------
(include filename) essential syntax
Filename should be a string naming an existing file containing Scheme
source code <expression1> <expression2> .... The <expression>s are
evaluated as though contained in a surrounding begin form
(begin <expression1> <expression2> ...) in the lexical environment.
Some implementations may require that if the file specified by
filename contains definitions and the include loading it is inside a
<body> then the the definitions must be at the beginning of the file
and the include must be before any expressions in the <body> which are
not includes or definitions.
If the contents of the file specified by <filename> change during
execution of the program then the actions of include are not specified.
Include does not affect the values returned by current-input-port and
current-output-port. Include returns the value of the last <expression>
in the file.
------------------------------------------------------------------------
In the Derived Expression Types section would be the rewrite rule:
(include <filename>)
= (begin <file-expression1> <file-expression2> ...)
A macro for include would be:
(define-macro include
(lambda (filename)
(cons 'begin
(call-with-input-file filename
(lambda (file)
(let next ((r (read file)))
(if (eof-object? r) '()
(cons r (next (read file))))))))))
The above problems are solved:
1) Expressions cannot be evaluated (included) which are not known at
compile time.
2) The lexical environment of the expressions in the file is the
lexical environment of the (include <filename>) form.
3) In a compiled only system all the files included are required to be
present at compile time. A runtime eval is not needed.
This definition of include will satisfy most existing use of load. In
addition, it allows definitions to be loaded into a lexical
environment without affecting the global environment:
(define (add-with-modular-arithmetic . args)
(include "modular-arithmetic-functions.scm")
(apply + args))
Incompatability issues:
1) Include specifies a return value. Load does not.
2) Include does not make sense on non-source files. Load allows
implementation dependent behavior on non-source files.
For an interpreted system, an interesting extension is to have
(include #f) call the read-eval-print loop in the current lexical
environment. If the interpreter does not care about mixing defines
and expressions this would implement separate name spaces.