Arc Forumnew | comments | leaders | submitlogin
Lexicons - first class global lexical environments
6 points by lisper 6146 days ago | 9 comments
http://www.flownet.com/ron/lisp/Lexicons.pdf

Code is at http://www.flownet.com/ron/lisp

Common Lisp only at the moment, but could be ported to Arc if symbol macros were added to the language.



2 points by eds 6146 days ago | link

First of all, let me say that I think lexicons look pretty cool.

Second, in Lexicons.pdf, you write the following about hygiene:

"The solution, in a nutshell, is: Within a backquote, precede any function call that you want to be non-shadowable with a comma."

I find this rather ironic considering all the ado on the forum about hygienic macros. (If this works then why did people both writing all those posts about hygiene? Not that I'm saying it doesn't...)

http://arclanguage.org/item?id=3422 http://arclanguage.org/item?id=2962 http://arclanguage.org/item?id=886

So does it really work? (And if it works is it the Right Thing to do?) I suppose there is no possible way to shadow foo in

  (let foo (fn args (apply prs "foo:" args))
    (mac bar args `(,foo ,@args)))
but if I am not mistaken you can't do the same for macros because

  (mac baz args `(prs "baz:" ,@args)) ; would do this in a let if macros were first class
  (mac bad args `(,baz ,@args))
gets you an error. (I've heard this could be solved with first-class macros but I have yet to see any implementation of said first class macros in arc.)

And if this is the Right Way to fix hygiene, should macro writers be expected to do this for every single macro they ever write?

Just wondering what people think.

-----

2 points by raymyers 6146 days ago | link

This came up yesterday. http://arclanguage.org/item?id=3449

Doesn't work in Arc2, but works in Anarki. Also doesn't work with macros, as you say. Macros aren't as big a deal however, because they cannot be shadowed by let or def, only by other macros with the same name.

Personally I think this is a pretty good answer to the hygiene issue. Probably not necessary in every single macro you write, but good if you intend lots of other people's code to use it.

-----

2 points by eds 6146 days ago | link

Yeah, I remember I had to change that to make my pure arc version of infix-eval work :)

-----

1 point by ms 6146 days ago | link

If I understand this correctly, `(,foo ...) embeds the foo function into the s-expr returned by the macro, IOW the car of the s-expr is the function.

While I find this an interesting approach, one problem I see is that this only works as long as Arc is an interpreter. Embedding foo into the s-expr mixes up runtime values (the function foo) and expand-time values (the s-expr).

In a compiler, you would have one runtime in which foo exists, and another runtime (the expand-time, at a higher "meta level") in which the s-expr exists, and the two runtimes can never meet -- they exist on different levels of the reflective tower.

(I am not entirely sure of this, and in any case it does not apply to Lexicons.)

See http://citeseer.ist.psu.edu/flatt02composable.html

-----

1 point by lisper 6146 days ago | link

> So does it really work?

It turns out that the current implementation has a serious bug, so at the moment the answer is no, it doesn't. But the situation appears to be salvageable.

> If this works then why did people both writing all those posts about hygiene?

Well, this is (a form of) hygiene. But it's not complete. As others have observed, it doesn't work for macros (though once the bug is fixed it will) and you still have to put in gensyms (a.k.a. uniqs) manually to avoid downward capture.

-----

1 point by CatDancer 6146 days ago | link

I'm bemused that calling a function fixes in which lexical environment the functions it calls come from. Probably not something I want to use for my (emergency-shutdown) function, hmm? Or do I ensure that the functions that emergency-shutdown calls are fixed to a particular lexicon by, er, writing some other functions that call them and then calling them? But then there's the (turn-power-off) function that (emergency-shutdown) calls...

-----

1 point by nlavine 6146 days ago | link

I'm not sure I quite understand this, but let me see if I can help clear up the confusion anyway.

A function, as distinct from a macro, has the property that when you call it, it will work the same way every time, even if you have provided some crazy bindings that shadow the functions it calls. For instance,

  (def prn args ; from arc.arc
    (do1 (apply pr args)
         (writec #\newline))

  (let pr (die)
    (prn 53)) ; doesn't die.
Hygienic macros work the same way.

Non-hygienic macros do not have this property. That is the basic issue.

(Note: your definition of hygiene may vary. In fact, mine might too; who knows?)

-----

1 point by eds 6146 days ago | link

Don't you mean

  (let pr [die]
    (prn 53)) ; doesn't die.
Otherwise it dies in binding pr to (die) and doesn't even get to (prn 53).

-----

1 point by nlavine 6146 days ago | link

Yeah. I didn't really have a clear definition for die. That's probably better.

I don't seem to be able to edit it now, though, so I'm afraid it will have to stay the bad way.

-----