Collapsing towers of interpreters [pdf]
cs.purdue.edu
Collapsing towers of interpreters [pdf]
1–10 of 25 posts
Re: Collapsing towers of interpreters [pdf]
#2Re: Collapsing towers of interpreters [pdf]
#3How is stage polymorphism different then a language supporting embedded languages (e.g. javascript with regex)?
Stage polymorphism I guess means abstracting over how many stages there are till you get to plain old non-code data; hopefully someone will chime in who's more up to date or free to read the paper tonight.
Re: Collapsing towers of interpreters [pdf]
#4Re: Collapsing towers of interpreters [pdf]
#5How is stage polymorphism different then a language supporting embedded languages (e.g. javascript with regex)?
From reading section 3, it seems that "stage polymorphism" allows the same piece of code to be used in different "stages". For example, we might have a function call like `square(4)`: if we evaluate it now, like an interpreter, we get the value `16`; if instead we "stage" it, like a compiler, we get code which (when executed) will call `square(4)`.
The polymorphism comes from parameterising the 'elimination forms' (branching, function calls, etc.). We can think of `square(4)` as being `call(square, 4)`, and we're overloading the choice of `call`: for an interpreter, we use a `call` which does the function call now; for a compiler, we use a `call` which constructs code for doing the call.
As for regular expressions in Javascript, this is more powerful for several reasons. Firstly, regular expressions are so limited that they can't reference other values; hence there's not much difference between interpreting or compiling them.
What about a more powerful embedded language, like `eval` running Javascript from within Javascript? That has the problem that we can't send values between different "levels" of Javascript. Say we have a value `x = 42` and we want to create an 'embedded' program `x + x`. We can pass around a string `"x + x"`, but when it eventually gets sent to `eval` it won't necessarily use the same `x` as we intended (it basically suffers from dynamic scope).
If we had a way to "stage" Javascript from within Javascript, we could ensure the correct value is used, but we'd probably have to write some funky expression like `` (depending on the language; take a look at MetaML for an example!). If we want to stage some Javascript which stages some Javascript (and so on), we'd accumulate horrible nesting/escaping boilerplate.
This "stage polymorphism" lets us write `x + x` for all stages, including things which are evaluated immediately. Their technique is also one pass, meaning that we don't have to run evaluators in compilers in evaluators... It also works with reflection, and with interpreters which implement the language semantics differently (they include examples like maintaining a count of how many times a variable is accessed, and for converting to continuation passing style).
Re: Collapsing towers of interpreters [pdf]
#6Re: Collapsing towers of interpreters [pdf]
#7This is a very intereresting video featuring one of the authors (Nada Amin). Strangely enough, I watched it a few hours ago. It brings some ideas.
Re: Collapsing towers of interpreters [pdf]
#8How is stage polymorphism different then a language supporting embedded languages (e.g. javascript with regex)?
I haven't read this paper yet (I've been meaning to), but: a staged programming language is something like quasiquoting in Lisp, but typically with a typing discipline: a value can have the type "expression of type T". A two-stage program might have a type like "expression of type (expression of type U)". This helps to efficiently implement embedded languages just as Lisp macros can expand to faster code than runtime…
Re: Collapsing towers of interpreters [pdf]
#9Earlier quoted context omitted.
I haven't read this paper yet (I've been meaning to), but: a staged programming language is something like quasiquoting in Lisp, but typically with a typing discipline: a value can have the type "expression of type T". A two-stage program might have a type like "expression of type (expression of type U)". This helps to efficiently implement embedded languages just as Lisp macros can expand to faster code than runtime…
> (Expression of type U) Isn't this how many statically toed functional languages model their type systems? 'list a' is an expression, is it not?
eval: "expression of type U" -> U
quote: U -> "expression of type U"
chriswarbo's reply higher up should be taken to supersede my reply -- he's obviously more current on this stuff.Re: Collapsing towers of interpreters [pdf]
#10Earlier quoted context omitted.
I haven't read this paper yet (I've been meaning to), but: a staged programming language is something like quasiquoting in Lisp, but typically with a typing discipline: a value can have the type "expression of type T". A two-stage program might have a type like "expression of type (expression of type U)". This helps to efficiently implement embedded languages just as Lisp macros can expand to faster code than runtime…
> (Expression of type U) Isn't this how many statically toed functional languages model their type systems? 'list a' is an expression, is it not?
No, it's a type. 'list' is a type constructor. Staging is a different beast from types altogether. Read up on MetaOCaml for how staging works in a typed language.
You're probably confused by the fact that typed languages assign types to expressions, but a value of type "expression" is something different. You're reifying the AST of an expression as a value at runtime, and then you can build further expressions, and then compile them all.