Arc Forumnew | comments | leaders | submitlogin
6 points by suzuki 5013 days ago | 6 comments
Let me introduce yet another implementation of Arc in Java:

   A Revised Implementation of Semi-Arc in Java

The article is written in Japanese, but I hope you read the program code.

The implementation is as exact as it run the verbatim copy of arc.arc in arc3 as a prelude. However, it has some differences. Among others, it is free from _free symbol capture_.

arc> (mac m (n) `(= w ,n)) #<macro:1> arc> ((fn (w) (m 3) (prn w) ((fn (w) (m 4) (prn w)) 100)) 200) 200 100 100 arc> w 4 arc>

I hope you enjoy it.

2 points by akkartik 5011 days ago | link

First time I'm seeing code comments in a non-roman script, and they look really cool.


1 point by jazzdev 4974 days ago | link

Interesting. What problem are you trying to solve with the change to macro variable evaluation?


2 points by rocketnia 4974 days ago | link

This hygiene problem, I believe:

  arc> (obj a 1 b 2)
  #hash((a . 1) (b . 2))
    (let list list:list
      (obj a 1 b 2))
  #hash((((a 1 . nil) . nil) . ((b 2 . nil) . nil)))
Currently, (obj a 1 b 2) expands into (listtab (list (list 'a 1) (list 'b 2))), which means it uses the local meanings of 'listtab and 'list during evaluation.* The Arc community already removes much of the need for hygiene by following the convention of using (uniq) for local variable names generated by macros, but that doesn't help in this case.

Technically, we could fix this as a community too, as long as we adopt a convention like one of these:

- Have (obj a 1 b 2) expand into ('#<procedure: listtab> ('#<procedure: list> ('#<procedure: list> 'a 1) ('#<procedure: list> 'b 2))), for instance.

- Have (obj a 1 b 2) expand into (eval!listtab (eval!list (eval!list 'a 1) (eval!list 'b 2))), for instance, and avoid using "eval" as a local variable name.

- Avoid using existing global variable names as local variable names, and vice versa.

Whenever possible, I like being able to repair a REPL session just by fixing one buggy global binding, so I don't recommend the first option here. The third option is closest to what we have in practice, but I don't like the way the global/local distinction is hazy without introducing some kind of boilerplate naming convention. So the second option is kind of my favorite, but it still smacks of namespace qualification, and it doesn't help Arc code that already exists.

Semi-Arc takes a "none of the above" approach and just implements the hygiene, despite the incompatibilities that risks. I've only found one positive use of "free symbol capture" in practice,* so that probably won't be the top issue when porting code to Semi-Arc.

* IIRC, an example I wrote had one macro that bound a gensym-named local variable and another macro that referred to it using the same gensym. The second macro referred to the variable plainly enough that it was no more useful than an anaphoric variable, and it could just as well be replaced with a dynamic variable or a global variable. Nevertheless, it may turn out to be a useful technique for a variable that needs to be captured by lexical closures but only needs to be used for a specific purpose (incrementing it and broadcasting an update event, maybe).


1 point by jazzdev 4972 days ago | link

Thanks, that's a great explanation. Makes sense.

The Jarc 'match' actually takes advantage of this lack of hygiene to implement this Perl-like idiom:

  (awhile (readLine in)
    (if (match "^\S") (prn it))
Where match is defined to search 'it' if no 2nd arg is provided.

  (mac match args
    `(match-str ,(car args) ,(if (> (len args) 1) (cadr args) 'it)))
I thought about using the same pattern in the Jarc sql package to dynamically turn tracing of the SQL statements on and off. But it seemed inelegant making all the sql functions into macros just to get the dynamic tracing, so I decided to use thread-local variables instead in that case.


2 points by rocketnia 4972 days ago | link

If you don't mind me suggesting...

  (mac match (regex (o subject 'it))
    `(match-str ,regex ,subject))
(Note that this rejects argument lists of lengths other than 1 or 2, whereas yours doesn't.)

And yeah, that is a good use of it. ^_^ An anaphoric parameter.


1 point by jazzdev 4972 days ago | link

Thanks for the improvement. Much shorter and more readable that way. And error checking as you mentioned.