[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: Req for help on objects and environments
From: |
Andy Wingo |
Subject: |
Re: Req for help on objects and environments |
Date: |
Fri, 03 Sep 2004 19:46:49 +0100 |
Hi Alp,
I know you've got a lot of answers already, but I think the environment
question is still not covered.
On Wed, 2004-09-01 at 11:28 +0300, Alp Öztarhan wrote:
> First, I want to play with the properties on objects.
> I want to be able to serialize an object along with its properties.
> I *can* make and retrieve properties of objects by use of
> (make-object-property). But how do I get a list of the properties of a
> given object?
In case you didn't figure it out, you can't, except from C with
scm_properties_whash.
> Second, I want to manipulate the environment in eval.
> I could not even do what the documentation tells.
> I could not get a handle on (null-environment) etc. (undefined symbol
> :-(
> Besides, I want to manipulate it, giving extra symbols etc.
> Could anybody give me any hint on these?
Sure. Scheme actually has two kinds of environments: toplevel and
lexical. The first is a simple association of names and values. The
concept is very similar to that of "modules", so in guile, toplevel
environments *are* modules[0]:
(module? (null-environment 5)) => #t
By default, guile is not r5rs-compliant when it loads up. I think this
is because (ice-9 syncase) is very slow to load up. Anyway, using
(ice-9 r5rs) will give you everything in the report, including
null-environment.
Modules are what can be passed as the second argument to `eval'. They
should be accessed only with documented functions for maximum
portability between guile versions, and to other schemes. Unfortunately,
modules expose their guts too much because everyone sees boot-9.scm.
So, to opaquely add a:=5 to a module, you can say:
(define env (null-environment 5))
(eval '(define a 5) env)
(eval 'a env) => 5
If you feel more dangerous, you can use module-define, module-defined?,
module-ref, module-variable, etc. See boot-9.scm for more. Dunno what
Marius thinks about this, but I like first-class modules :)
[0] This is complicated by the existence of environment SMOBs, from
environments.c / environment-*. I have no idea whether this code is on
the way in, or the way out. Marius, Dirk?
Lexical environments are a different beast. You cannot access them with
r5rs, I don't think. However, with guile you can, although it's
definitely not documented. I tried to be less hacky with the following
macro, but define-macro's memoizing behaviour caused guile 1.6 to
segfault, so I had to use low-level macros:
(define make-environment
(procedure->syntax
(lambda (exp env)
(local-eval `(let* ,(let lp ((in (cdr exp)) (out '()))
(if (null? in)
(reverse out)
(lp (cddr in) (cons
(list (car in) (cadr in))
out))))
(the-environment))
env))))
;; e.g.
(make-environment a 5 b 6 c a)
=> <a lexical environment with a=5, b=6, c=5
This environment is created with let*, so later bindings can access the
values of previous ones. `the-environment' is a syntax that returns the
current lexical environment. local-eval is a form of eval that takes a
lexical environment instead of a toplevel. Indeed, the `env' argument to
a low-level macro is a lexical environment.
Then,
(define-macro (with-environment env . body)
`(local-eval
,(list 'quote `(begin ,@body))
,env))
(with-environment (make-environment a 5)
a) => 5
(define (bind sym val env)
(if (defined? sym env)
(begin (local-eval `(set! ,sym ',val) env)
env)
(local-eval `(let ((,sym ,val)) (the-environment)) env)))
There's more in (soundscrape environments), in my arch repository. I
wrote this when I just started with guile; the pattern of lexical
environments applied to a problem I had. Now I worry about the low-level
access. A problem for later, I guess...
Hope that helped,
--
Andy Wingo <address@hidden>
http://ambient.2y.net/wingo/