Arc Forumnew | comments | leaders | submitlogin
A more powerful 'mz
5 points by rntz 5671 days ago | 4 comments
Short version: Here (http://www.rntz.net/files/escape.patch) is a patch against arc3.tar that adds a special form, '$, that combines the best features of CatDancer's 'mz and anarki's old '$ macro: namely, pass-through-compiler semantics from the former and unquotation of arbitrary arc expressions from the latter.

CatDancer's variously-named special form (which I will henceforth call 'mz) for bypassing the arc compiler has caused quite a bit of discussion. On the surface, it is similar to anarki's '$ macro; however, the latter allows the use of unquoting to substitute arc expressions into the evaluated scheme code. 'mz does not have this feature per se, but thanks to the way the arc compiler works, it is easy to access local arc variables from inside 'mz, since they are compiled down to correspondingly-named mzscheme local variables. Accessing arc global variables, however, requires adding a prefix to their symbols ('__ for anarki, '_ for arc3). Finally, even in 'mz, one still cannot substitute arbitrary arc code into the scheme code.

With a bit of hacking, it turns out there is a way to create a special form which, while still retaining the fundamental aspect of 'mz (that it passes code through the compiler rather than adding an extra layer of indirection with 'eval), allows us to substitute arbitrary arc into scheme. Because it operates more like the corresponding anarki macro, and to avoid confusion with whatever CatDancer eventually decides to name his hack, I've chosen '$ as the name for this special form. For simple cases, it behaves the same as 'mz and '$.

    arc> $.dynamic-wind
    #<procedure:dynamic-wind>
    arc> ($ (symbol->string 'foo))
    "foo"
    
If we take a look behind the scenes, it operates similarly to 'mz in that it substitutes the provided code directly into the compilation, rather than using 'eval, to get at mzscheme. This means you can access arc local variables directly:

    arc> (let x 2 ($ (+ x 3)))
    5
    arc> user break
    ; I'm now at the mzscheme prompt, and am invoking the arc compiler 
    ; directly to see what arc code using '$ compiles down to.
    > (ac '(let x 2 ($ (+ x 3))) ())
    ((lambda (x) (+ x 3)) 2)
However, as with '$, unquotation provides us with a more robust way to substitute arc expressions into scheme code:

    arc> (= y 4)
    4
    arc> (let x "foo" ($ (+ 2 ,(len x) ,y)))
    9
    arc> user break
    ; Let's take a look at what's going on here.
    > (ac '(let x "foo" ($ (+ 2 ,(len x) ,y))) ())
    ((lambda (x) (+ 2 (ar-funcall1 _len x) _y)) "foo")
At this point you know all you need to know to use '$, save how to get at it. I'll probably be pushing some preliminary work on updating anarki to arc3 in the next few days, and this will be among it, but for now, here's a git-diff against arc3: http://www.rntz.net/files/escape.patch. Note that this patch, being against arc3.tar, won't work if applied to eg. anarki's master branch (for one thing, the name of '$ will by design conflict with anarki's '$ macro). It should work against the official branch, though.

How the hack works is a bit complicated. It involves a small refactoring of the quasiquote-handling code in ac.scm. Your best bet is probably just to look at the diff; and if you don't already understand how scheme (and hence arc) deal with nested quasiquoting, that's more or less a prerequisite. But from a user's standpoint, it should "just work".



1 point by shader 5671 days ago | link

Interesting. This will be helpful if I wanted to use a scheme macro (are there any?), but otherwise I would probably just use the mz patch, using the pattern that showed up for the $ macro:

  (mz.function args)
 
instead of

  (mz:function __args)
It almost looks like a package reference, and it gets all of its arguments directly from arc, because it's just returning the procedure and calling it on the arc arguments. It won't work for macros, because those transform code, but it works pretty well for everything else.

-----

1 point by rntz 5669 days ago | link

I've pushed this hack (along with some other initial work on updating anarki) to my fork of anarki's official branch (http://github.com/rntz/arc) under the tag `rntz.$.0'. (Note that merely git clone'ing that repo won't get you this hack; I'm organizing my work along the lines of CatDancer's "Sharing arc hacks", and it's published as a tag only thus far.)

-----

1 point by Adlai 5671 days ago | link

Any reason why you completely redefine ac-qq rather than just putting new code into ac-$?

-----

1 point by rntz 5671 days ago | link

DRY (Don't Repeat Yourself). I'm generalizing an existing function. Doing it this way keeps the code shorter, and in the event that 'ac-qq1 has a bug, then 'ac-qqx probably does too, and if I do it this way then when I (or someone else) tries to merge fixes for 'ac-qq1 they'll get a conflict indicating that they need to modify the fixes for 'ac-qqx rather than having it silently succeed, leaving bugs in 'ac-qqx.

-----