Arc Forumnew | comments | leaders | submitlogin
1 point by almkglor 5981 days ago | link | parent

Yes, and it appears to be the best solution if we want to have compile-time macro support, because the alternative would be a very slow AST-traversal interpreter.

Speed is of course never an issue, except when it is. ^^



1 point by rntz 5981 days ago | link

That's not the only alternative.

A lightweight but hackish alternative would be to special-case modules in the translation process. This could be done by checking, whenever you have an sexpr of the form "((<name1> <name2>) ...)", whether <name1> is globally bound to a module and <name2> to a macro within the module.

A more general way to do this would be, when you have an sexpr of the form "((...) ...)", before doing anything else, to macroexpand the sexpr in functional position. Then you could write modules as macros, expanding to the evaluation of their arguments in that module (the macro equivalent of what mine do via 'defcall now).

I think, but am not sure (so feel free to prove me wrong), that the real dichotomy is not between CL packages and AST interpretation, but between supporting first-class macros or the equivalent, and making the module system part of the language itself (hacking ac.scm) rather than creating it within the language.

A CL-like package system, for example, breaks the symbol-string isomorphism: what symbol a string becomes now depends upon what module you're in, which means you can't just mimic namespaces by 'uniq'ing all the symbols in a module that aren't imported from some other module: 'read, 'sym, etc. need to be changed so that they know from what module they're being invoked. Again, I'm not sure of this, but I think the abstraction will inevitably leak unless you change the translator itself to support your module system.

-----

1 point by almkglor 5981 days ago | link

> A more general way to do this would be, when you have an sexpr of the form "((...) ...)", before doing anything else, to macroexpand the sexpr in functional position. Then you could write modules as macros, expanding to the evaluation of their arguments in that module (the macro equivalent of what mine do via 'defcall now).

Hmm. Care to try implementing this?

-----

3 points by rntz 5981 days ago | link

http://pastebin.osuosl.org/9215

Done. The above links to the result of "git diff" after the changes. While I think it works (it loads arc.arc fine), I don't want to actually push it to anarki in case I've made a mistake and there's some existing code it breaks. With it, and my module system, you can do the following:

In "test.arc":

    (prn "test.arc evaluated")
    (mac mquote (x) `',x)
At the arc repl:

    Use (quit) to quit, (tl) to return here after an interrupt.
    arc> (load "lib/module/python.arc")
    nil
    arc> (use test)
    test.arc evaluated
    #3(tagged module #<namespace>)
    arc> (mac test* (x) (test x))
    #3(tagged mac #<procedure>)
    arc> (test*.mquote foo)
    foo
If this gets pushed to anarki, it would be trivial to rewrite lib/module/python.arc so the "(mac test* ...)" line is unnecessary.

-----

1 point by almkglor 5981 days ago | link

Hmm. Looks good, although I'm dubious about the second diff block (problem is that I don't have access to an Arc right now, so I can't quite see where that modification is)

As an aside - could we possibly do this without depending on mzscheme namespaces? It should be possible to have the macro instead be something of the form:

  (mac module-name (x)
    (case x
      member  gs42 ; where gs42 is a (uniq)-ed symbol
      member2 gs43
              (err:string "module does not contain member - " x)))

-----

1 point by rntz 5978 days ago | link

The second diff block is just a continuation of the change to 'ac-macro?. The modified function looks like this:

    (define (ac-macro? fn)
      (let ((fn (if (pair? fn) (ac-macex fn) fn)))
        (cond
         ((symbol? fn)
          (let ((v (namespace-variable-value (ac-global-name fn) 
                                             #t 
                                             (lambda () #f))))
            (if (and v
                     (ar-tagged? v)
                     (eq? (ar-type v) 'mac))
                (ar-rep v)
                #f)))
         ((and fn
               (ar-tagged? fn)
               (eq? (ar-type fn) 'mac))
          (ar-rep fn))
         (#t #f))))
As for doing it without mzscheme namespaces, yes, that could be done. That would be the CL way, more or less.

-----