Arc Forumnew | comments | leaders | submitlogin
8 points by raymyers 6154 days ago | link | parent

Perhaps modules should be valid containers. Thus instead of introducing a new syntax foo@a, we can use (foo 'a) and foo!a using sugar already in place. (I realize I am not the first person to say that.) I also would not like having to use mdef and m= within a module. Ideally, I should just use def, mac, and = as normal and export the symbols I want visible from outside.

    (module foo (export a bar)
      (= a 'in-top)
      (def foo (x) (+ x 1))
      (def bar (x) (+ x 1))
      (pr a))
    (prn foo!a)
    (foo!bar 0)
    (= bar foo!bar) ; an import.
    (= a2 foo!a)    ; a qualified import.
This could all be implemented as an optional library, except for those pesky macros. And of course, we do need a module system with adequate macro support.


1 point by sacado 6154 days ago | link

What about something like what you are proposing, but where you have to explicitly state when you use the module namespace, since we obviously can't overwrite = without sad effects ?

For example, let's take the $ symbol (another ugly one :) to mean "the current module". The above could be written :

  (module foo (export a bar)
      (= $!a 'in-top)
      (def $!foo (x) (+ x 1))
      (def $!bar (x) (+ x 1))
      (pr a))
    (prn foo!a)
    (foo!bar 0)
    (= bar foo!bar) ; an import.
    (= a2 foo!a)    ; a qualified import.
Advantages : - very simple - written in pure Arc (thus candidate to the core language)

Here's a macro implementing part of that behavior : (= $ nil) (= $path* '()) ; Current module hierarchy

  (mac module (name . body)
        (w/uniq old-$
                `(with (,old-$ $)
                        (= $ (table))
                        (push $ $path*)
                        ,@body
                        (pop $path*)
                        (if $path*
                                (= (,old-$ ',name) $) ; Put it in the parent
                                (= ,name $))          ; Put it in global namespace
                        (= $ ,old-$))))
It supports imbricated modules. To import a module, or do a qualified import, the classical table manipulation functions work.

  (module foo
    (module bar
      (= $!baz 'arc)))

  arc> foo
  #hash((bar . #hash((baz . arc))))
  arc> (= bar foo!bar)
  #hash((baz . arc))
  arc> bar!baz
  arc

-----

2 points by raymyers 6153 days ago | link

It sounds like several of us are working on different module ideas. How about we start throwing our prototypes in a `lib/module' directory on the git?

-----

1 point by almkglor 6152 days ago | link

Done, hacking off yours since it was already there ^^

-----

2 points by almkglor 6154 days ago | link

This requires us to have decent code-traversal.

Question (dunno the answer, not on my hacking computer): how will a macro receive the expression (foo:bar foo)? As (foo (bar foo))? as ((compose foo bar) foo)? As (|foo:bar| foo)? (|| is used to enclose a literal in symbols)

-----

1 point by sacado 6154 days ago | link

  arc> (macex 'foo:bar)
  foo:bar
Too bad :(

-----

3 points by cooldude127 6154 days ago | link

i like the looks of this. i fully support taking advantage of the simplicity arc already has.

-----

1 point by sacado 6154 days ago | link

There's a problem with using = and def. I tried it, but many parts of the core and libraries assume a unique namespace. As commands can have many side-effects, everything breaks easily.

But the idea of using tables is excellent.

-----

1 point by sacado 6154 days ago | link

Anyway, we must be able to access the global namespace too. If you overwrite = and def, you can't. Or you have to define g= and gdef :)

-----

4 points by almkglor 6153 days ago | link

Here's a different idea. Suppose that instead we build a basic modulesystem which transforms:

  (modules-base
     ;name of module.
     foo
     ;set of functions in this module
     (bar)
     ;set of module variables
     (nitz)
     ;set of functions from other modules
     ((module2 hmm niawniaw))
     (def bar (x) (hmm) (niawniaw) (do1 nitz (= nitz x))))
to:

  (= foo
     (with
        (bar nil nitz nil hmm module2!hmm niawniaw module2!niawniaw)
       (= bar (fn (x) (hmm) (niawniaw) (do1 nitz (= nitz x))))
       (fill-table (table) 'bar bar)))
Then we create another macro which simply scans through the code for (def ...) forms and transforms the following code:

   (module foo
     (use module2)
     (module-vars nitz)
     (def bar (x) (do1 nitz (= nitz x))))
to:

  (modules-base
     foo
     (bar)
     (nitz)
     ;gotten by taking (keys module2)
     ((module2 hmm niawniaw))
     (def bar (x) (do1 nitz (= nitz x))))
Weaknesses: (1) we can't make module-variables accessible outside. If we had access to environments, though, we could.

(2) macros are impossible as yet, whether shared or not. Possibly, we need macrolet, and adding some mechanism to store macros separately from the module table - possibly in a table-of-tables module-macros.

Implementation: simple scanning would be nice. However, modules-basic would be better implemented by a 'macrolet form.

Conclusion: We need macrolet.

-----