load in environment
Hi, I was wondering if there is a built-in way to eval the contents of a file inside of an environment other than (current-module)? We have eval and primitive-eval, and it seems that load is currently (conceptually) a read, primitive-eval loop until eof is reached. Why not allow an environment arg to load, making it (conceptually) a read, eval loop until eof is reached? There are two ways that I've thought of to implement this if it is not implemented in guile already (which it doesn't seem to be). One is to simply read the file repeatedly, and eval the results in the given environment: (define load-env-1 filename env) (let* ((file (open-input-file filename)) (datum (read file))) (while (not (eof-object? datum)) (eval datum env) (set! datum (read file The second way is to make the desired environment temporarily be the current module: (define load-env-2 filename env) (let ((real-current-module (current-module))) (set-current-module! env) (load filename) (set-current-module! real-current-module))) The second way has the advantage of not reinventing the wheel when it comes to the read-eval loop, but looks rather strange. If anyone knows of a better way to do this, or especially if someone knows of a procedure already in guile to do exactly this, I'd love to hear about it. If anyone has thoughts on ways that one or both of these might be improved, I'd also love to hear about that. Regards, Jon ___ Guile-user mailing list Guile-user@gnu.org http://lists.gnu.org/mailman/listinfo/guile-user
Re: load in environment
Jon Wilson wrote: The second way is to make the desired environment temporarily be the current module: (define load-env-2 filename env) (let ((real-current-module (current-module))) (set-current-module! env) (load filename) (set-current-module! real-current-module))) The second way has the advantage of not reinventing the wheel when it comes to the read-eval loop, but looks rather strange. It is a sensible enough pattern, easily made exit/reentry-safe with dynamic-wind in Scheme: (define (load filename . env-lst) (if (null? env-lst) ((@ (guile) load) filename) (load-env-2 filename (car env-lst (define (load-env-2 filename env) (let ((old-cm #f)) (dynamic-wind (lambda () (set! old-cm (current-module)) (set-current-module! (environment-module env))) (lambda () (load filename)) (lambda () (set-current-module! old-cm) What other Guile state might you want to modify in the dynamic context of a load, though? -- ;;; Stephen Compall ** http://scompall.nocandysw.com/blog ** But you know how reluctant paranormal phenomena are to reveal themselves when skeptics are present. --Robert Sheaffer, SkI 9/2003 ___ Guile-user mailing list Guile-user@gnu.org http://lists.gnu.org/mailman/listinfo/guile-user
Re: load in environment
Stephen Compall wrote: What other Guile state might you want to modify in the dynamic context of a load, though? Dynamic-wind looks like a quite good idea here. I'll probably use that. Thanks. Well, I'm writing a function to load up some data from a file and stick it in a hash table. The data file looks something like this: -- begin data file -- (item "foo" "bar is a metasyntactic variable" 1) (item "baz" "barn is a unit of cross section" 2) (item "frob" "nitz is more or less meaningless" 86) -- end data file -- Then I call a function to load this data. (define (load-data filename) (let* ((my-table (make-hash-table)) (item (lambda (name text number) (hash-set! my-table name (make-item text number (m (make-module)) (real-current-module (current-module))) (module-define! m 'item item) (set-current-module m) (load filename) (set-current-module real-current-module) my-table))) [note: make-item is a record constructor.] I certainly could just write code that reads in an expression from the file, and sticks the data from it into the hash table. Probably safer than using load (nothing is evaluated), and perhaps better for other reasons as well. But this way is very pretty (I think). Additionally, if I add (module-use! m (null-environment 5)) or some such, then the user can generate the data programmatically, which sounds attractive (there isn't currently a good use-case for this, but I can picture some down the road perhaps). I'm not sure if my-table is what you meant by "other guile state" that I might want to modify, but it is definitely something visible to the rest of the program which I want to modify by loading filename. I'm a little bit mystified that I can modify my-table from inside (load filename) at all, since my-table is certainly not visible to the code inside filename. I guess that I can because my-table is wrapped up in the closure of item. I'm not really clear on the interaction between modules (especially set-current-module) and closures. A closure inside of one module can apparently reference and modify things in quite another module altogether. Maybe if it were not 1am, this would be more obvious. Regards, Jon ___ Guile-user mailing list Guile-user@gnu.org http://lists.gnu.org/mailman/listinfo/guile-user
Re: load in environment
Jon Wilson wrote: I'm not sure if my-table is what you meant by "other guile state" that I might want to modify, but it is definitely something visible to the rest of the program which I want to modify by loading filename. I'm saying that there are many possible system properties one might want to temporarily change when loading, so it is impractical and asymmetric to exalt one or another as an argument to `load'. I'm a little bit mystified that I can modify my-table from inside (load filename) at all, since my-table is certainly not visible to the code inside filename. I guess that I can because my-table is wrapped up in the closure of item. I'm not really clear on the interaction between modules (especially set-current-module) and closures. A closure inside of one module can apparently reference and modify things in quite another module altogether. Your `item' closure carries around an environment, which has as its environment-module the module that contains your `load-data' function. When you call it, even from another environment with a different environment-module, you evaluate its expressions in the environment it captured when it was created. The closure isn't "inside" any module; you merely gave it a binding in your temporary module. temp-module m has # has # which is eq? to item captured the environment containing my-table so can refer to my-table when called -- ;;; Stephen Compall ** http://scompall.nocandysw.com/blog ** But you know how reluctant paranormal phenomena are to reveal themselves when skeptics are present. --Robert Sheaffer, SkI 9/2003 ___ Guile-user mailing list Guile-user@gnu.org http://lists.gnu.org/mailman/listinfo/guile-user
Re: load in environment
Stephen Compall wrote: The closure isn't "inside" any module; you merely gave it a binding in your temporary module. A. You seem to have effectively defuzzied my thinking. Again, thanks! Jon ___ Guile-user mailing list Guile-user@gnu.org http://lists.gnu.org/mailman/listinfo/guile-user