[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: another take on hackers and painters



On Tue, May 20, 2003 at 06:36:31PM -0500, mcguire@cs.utexas.edu wrote:
> Matt Hellige <matt@immute.net> wrote:
>  >Here's another big one: reflection and dynamic evaluation.
> 
> Aha!  That is a big one.  I suppose the other alternative is to write
> your own "eval-string" including parser, type checker, and so forth. :-)

That wouldn't solve anything, since the embedded interpreter would be
"independent". The real challenge is making eval'ed code interact with
the runtime environment of the host program:

(define x 'foo)
(eval '(set! x 'bar))
x
==> bar 

And this is non-trivial to do safely in a statically typed language.

> Are there any staticly typed languages that expose an interface like
> Scheme's eval or Python's exec/eval (which actually take strings)?[1]  If
> so, what does the interface look like?[2]

I asked the same question some time ago, and didn't get many answers:
<http://www.ai.mit.edu/~gregs/ll1-discuss-archive-html/msg01198.html>.

I still am not aware of any system that supports anything that I'd call
"real" statically typed eval. OCaml's dynamic linking allows some
interaction with the runtime environment (you can compile source into a
bytecode module on the run, then dynamically link it to the program),
but type checking requires that interface files for all run-time modules
are available (and consistent with the actual interfaces that the
running program was compiled with). The Toplevel library of Efuns seems
to do something similar, although more conveniently.

Staged systems such as MetaML do seem to support some form of eval
(since you can construct expressions at runtime and then execute them),
but I'm not quite sure how expressive it really is. In particular, it
seems like you cannot construct a variable from a run-time value (eg. an
input string).

I think that proper support for eval and reflection requires that all
types can be reified to run-time values, and that the type system can
track the dependencies between them. In this case, the type of eval
could be eg.

eval : forall t . String -> Env -> t

or perhaps more accurately

eval : \Pi t . String -> Env -> t

You would then call it like this:

eval Int "2 + x" env

The eval function then gets a runtime representation of the Int type,
the string, and an environment (which acts both as an environment and a
typing context, ie. it maps identifiers both to values and to types).
Eval then parses the expression and tries to typecheck that its type
really is Int (in the typing context of env), and if everything
succeeds, the expression gets evaluated in env, and the result is
returned. The static type of the whole call to eval is also Int.

The real magic comes when you can get an enviroment that is also the
environment of the _host_ program:

x = ref "foo"
eval String "x := ref \"Bar\"" %magic_lexical_environment
!x
==> "bar"

Of course such a system requires some delicate interaction between
values and types, but type systems with intensional polymorphism already
mostly support these things. I just haven't seen any real languages
where these things would have been implemented.

I'm writing my master's thesis on this very subject, so I'd be very
grateful for additional references.


Lauri Alanko
la@iki.fi