You could hypothetically package the reader changes into their own modules so that you'd need to explicitly say which braces you're using, modules keep their changes local, etc. Anyone know of work done on this front?
Hmm, giving the job of custom readers to modules strikes me as making implementing both modules and custom readers complicated and difficult; and makes unnecessary impositions on the programmer: I might well want to implement one part of my module using one syntax and another part of my module using a different syntax.
On the other hand I think being able to choose your custom reader by source code file would simple to use, simple to understand, easy to implement, would make it easy to customize your editor or IDE to understand your different syntaxes by file, and means that modules can also be easily implemented as they could do their work entirely after the source code has been read in.
I wonder if modules could be implemented with namespaces? You want to call my function foo which calls my function bar, but you don't necessarily want to have to name it "foo" in your own code and you want to be able to have your own "bar" without breaking my function foo. I'll have to think about that one.
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.