I wonder if modules could be implemented with namespaces?
I guess I use the words "module" and "namespace" interchangeably. I'm not sure what else "module" ("package", "namespace", sometimes "library" (loosely), etc.) would mean.
(use "braces-for-set-builder-notation.arc")
(load "a.arc")
(def set-I-really-want ()
{ (* v v) for v in (vals (table-I-really-want)) })
You wouldn't want a.arc's use of braces for tables to leak into b.arc, which uses braces for set-builder notation (which you further don't want to clobber the braces in the definition of table-I-really-want).
With a fancier module system, you might even have
b.arc
(qualify "braces-for-set-builder-notation.arc" s)
(load "a.arc") ; doesn't qualify its braces for tables
(def set-I-really-want ()
s{ (* v v) for v in (vals (table-I-really-want)) })
(def another-table-I-want ()
{foo 5 bar 10 baz 15})
Though there shouldn't be a reason you couldn't do something like
c.arc
(use "braces-for-table.arc")
(def some-table ()
{x 5 y 10})
(use "braces-for-set-builder-notation.arc")
; braces hereafter are for set-builder notation
(def some-set ()
{ x for x in (vals sig) })
As Arc lacks a proper module system, you can already see the clobber-some effects of definitions being global/unqualified. APIs leak all over the place:
arc> (load "sscontract.arc") ; only really needs to provide sscontract
nil
arc> (priority #\!) ; but the user gets all of the implementation details!
1
Similarly, I don't want to load some library and have implementation-detail reader macros polluting the reader. (If the library's specifically for reader macros, then of course that's okay.)
Even some simple public/private control would be nice. I've played around with this in Arc before. E.g.,
(let localize nil
(assign localize
(fn (expr fs)
(when (caris expr 'def)
(if (~mem (cadr expr) fs)
`(assign ,(cadr expr) (fn ,@(cddr expr)))
expr))))
(mac provide (fs . body)
(let private (trues [and (caris _ 'def)
(~mem (cadr _) fs)
(cadr _)]
body)
`(let ,private nil
,@(map [localize _ fs] body))))
)
arc> (macex1 '(provide (f g)
(def f (x) (h (+ x 1)))
(def g (x) (+ (h x) 1))
(def h (x) (* x x))))
(let (h) nil
(def f (x) (h (+ x 1)))
(def g (x) (+ (h x) 1))
(assign h (fn (x) (* x x))))
arc> (def foo () (prn "outer foo") nil)
#<procedure: foo>
arc> (provide (bar)
(def foo () (prn "inner foo") nil)
(def bar () (prn "bar") (foo)))
#<procedure: bar> ; note: no redef warning, since def changed to assign
arc> (bar)
bar
inner foo
nil
arc> (foo)
outer foo
nil
But this particular approach doesn't interact with macros nicely, doesn't let you qualify namespaces, isn't general, etc. So it's really suboptimal.