Arc Forumnew | comments | leaders | submitlogin
4 points by CatDancer 5630 days ago | link | parent

Here's a patch that allows us to use 'declare to bootstrap into our own implementation of quasiquote written in Arc: http://hacks.catdancer.ws/disable-ac-qq0.patch

For example, from his paper, here's Bawden's inefficient but simple and correct implementation, ported to Arc: http://hacks.catdancer.ws/bawden-qq0.arc

(We could also look around to see if there's other working implementations that we could use... plt scheme's R6RS implementation of quasiquote or Common Lisp's implementation might be worth checking out).

To run your example, I'll load my port of Bawden's implementation:

  $ mzscheme -m -f as.scm
  Use (quit) to quit, (tl) to return here after an interrupt.
  arc> (load "bawden-qq0.arc")
  nil
note how I'm bootstrapping here: I'm using Arc's default implementation of quasiquote based on MzScheme to load Arc and Bawden's code, and then I can switch over to using Bawden's code to implement quasiquote.

Next I can use the patch to disable Arc's expansion of quasiquote:

  arc> (declare 'quasiquotation nil)
  #<void>
...though the existing 'declare assertions use a true value to change Arc's behavior, so maybe this should be named 'disable-quasiquote-expansion or something like that instead.

Now that I'm not being preempted by the Arc compiler, I can implement quasiquote with a macro, such as with Bawden's implementation:

  arc> (mac quasiquote (x)
         (qq-expand x))
  #3(tagged mac #<procedure: quasiquote>)
and your example runs like this:

  arc> (= xs '(x1 x2) ys '(y1 y2) x1 'a x2 'b y1 'c y2 'd)
  d
  arc> (eval ``(list ,,@(map (fn (x y) ``(,,x ,,y)) xs ys)))
  (list (a c) (b d))
Is that the right result?


1 point by CatDancer 5630 days ago | link

Aha, here's a nicer version of the patch that doesn't need the 'declare to be used: http://hacks.catdancer.ws/preempt-qq0.patch

What it does is if the user has defined a 'quasiquote macro, it allows the macro to take precedence over Arc's internal qq implementation; much like any macro in arc.arc can be redefined by the user.

The example now looks like:

  $ mzscheme -m -f as.scm
  Use (quit) to quit, (tl) to return here after an interrupt.
  arc> (load "bawden-qq0.arc")
  nil
  arc> (mac quasiquote (x)
         (qq-expand x))
  #3(tagged mac #<procedure: quasiquote>)
  arc> (= xs '(x1 x2) ys '(y1 y2) x1 'a x2 'b y1 'c y2 'd)
  d
  arc> (eval ``(list ,,@(map (fn (x y) ``(,,x ,,y)) xs ys)))
  (list (a c) (b d))

-----

2 points by fallintothis 5628 days ago | link

here's a nicer version of the patch that doesn't need the 'declare to be used

Cool, thanks.

We could also look around to see if there's other working implementations that we could use... plt scheme's R6RS implementation of quasiquote or Common Lisp's implementation might be worth checking out

Just for reference, I posted my code for a port of a Common Lisp backquote: http://arclanguage.org/item?id=9962

I also tried looking at PLT's r6rs quasiquote (specifically collects/r6rs/private/qq-gen.ss), but I found it a bit daunting because I'm unfamiliar with syntax-case macros. It's probably better for quasiquote to be written in Scheme, though, so perhaps the code could easily be transplanted into ac.scm. I'll just leave it to someone more Scheme-savvy.

-----

1 point by CatDancer 5628 days ago | link

It's probably better for quasiquote to be written in Scheme

Why?

-----

1 point by fallintothis 5628 days ago | link

I was thinking in terms of bootstrapping. The quasiquote library I wrote uses things defined in arc.arc, which in turn are written for quasiquote, but using the one on the Scheme side.

It's entirely possible to rewrite either to fit it all together. For instance, someone could rewrite the quasiquote library in terms of basic operators -- 'assign, 'cons, 'fn (instead of 'let), and the like. Probably more bearable would be rewriting arc.arc to use 'list and 'cons and so forth to build expressions instead of using quasiquote, up until we have enough to define quasiquotation (which doesn't require much); then load qq.arc and continue defining arc.arc with the newfound utility.

Neither of these options sounds pleasant if, as an alternative, we could just have an easily-added Scheme-side quasiquote -- e.g., if mzscheme already implemented it correctly, we'd be done. Granted, there are advantages to having a user-defined quasiquote, not just in the interest of keeping Arc axiomatic but also in giving programmers the option to modify it.

Efficiency was another concern of mine, in that doing quasiquotation in Scheme might be more efficient than cranking 'ac across all of the Arc functions back-and-forth. But this is likely unfounded and more a symptom me worrying rather than actual testing -- the difference could be negligible or even nonexistent. Arc quasiquotes (as I implemented) still compile down to simple Scheme code (to the results of the macroexpansions), so it's probably silly to worry. Just a fleeting concern.

-----

1 point by CatDancer 5628 days ago | link

Well, on efficiency, the quasiquote expansion happens at read / macro expansion / compile time, am I right? So writing the qq expander in Arc vs. Scheme isn't going to affect the speed of the running program, yes?

As for bootstrapping, MzScheme's qq implementation works as long as nested quasiquotation isn't used, and today arc.arc doesn't use nested quasiquotation. So I don't think we need to do anything beyond what we're already doing: load arc.arc, then load a qq implementation that handles nested qq, and then we're free to write macro utilities that use nested qq.

-----

1 point by fallintothis 5628 days ago | link

Arc vs. Scheme isn't going to affect the speed of the running program, yes?

Yes, so far as I can see. I was just being paranoid.

As for bootstrapping, it's still cleaner to have a single implementation, rather than juggling them. Given we're currently only juggling 2 implementations, the problem's not intractable, just "improper".

-----

3 points by CatDancer 5628 days ago | link

I suspect that bootstrapping is almost always doing something improper if you look at it too closely :)

-----