Oh, whoops. I forgot 'pushnew actually does traverse the input list to find out whether the element is new. I was thinking of 'push. XD
I disagree with the notion of membership you're using for dotted lists. If I 'pushnew nil onto (1 2 3 . nil), I want to get (nil 1 2 3 . nil), and it won't work that way if nil is already considered to be a member.
"What do people think of this? Basically I want all list operations to treat atoms as degenerate dotted lists. Does this have any adverse implications for other aggregates (tables)?"
I don't see a problem, but I may not be the right person to ask. If it came down to it, I'd be willing to use 'table-pushnew, 'alist-pushnew, 'maxheap-pushnew, and so on. :-p
What other list operations do you have in mind? While 'pushnew makes sense to use with degenerate dotted lists, it's a very special case: It only clobbers the list at a finite depth, and that depth is actually zero. (Or zero in the unmodified list, anyway.)
What do people think of this? Basically I want all list operations to treat atoms as degenerate dotted lists. Does this have any adverse implications for other aggregates (tables)?
Update: As I expected, taking out the round-trip to table in the first version above saves us some consing. All the changes to get to the second version don't seem to result in any extra consing over the first.
After some thought, I decided to stop half-assing it. What I've been trying to do is make a new implementation of Arc that is backwards compatible with Arc 3.1 but adds new features and fixes bugs.
The problem is that eventually I'll run into features I want to add, or bugs I want to fix, and I won't be able to do that without breaking compat with Arc 3.1.
This is very restricting, and part of Arc is about unbridled freedom. I thought about going the pg route and just saying "screw compat!" but if I did that I'd just end up with Nulan, so what's the point?
So instead, here's what I'm gonna do. There will be two separate languages implemented by the Arc/Nu compiler: Arc/Nu and Arc/3.1.
Arc/3.1 is the Arc you know and love. Unhygienic macros, dynamically scoped globals, and most of the warts and bugs and missing features.
Arc/Nu is a language similar to Arc, but with new features, bug fixes, and general cleanup. It has hyper-static scope and hygienic macros. It doesn't try to maintain backwards compat with Arc 3.1.
Now, you might be wondering, what's the point? I mean, we already have vanilla Arc 3.1 as implemented by pg, so why should Arc/Nu support Arc 3.1 at all?
The twist is that thanks to the magical power of booooxes, I can have Arc/3.1 and Arc/Nu running in the same namespace. This means Arc/3.1 can import Arc/Nu stuff, and Arc/Nu can import Arc/3.1 stuff.
And it all works correctly, so that if you define an unhygienic macro in Arc/3.1 and import it into Arc/Nu, it will behave unhygienically. And vice versa, if you define a hygienic macro in Arc/Nu and import it into Arc/3.1, it will behave hygienically.
And you can do things like import an Arc/3.1 library and mutate its stuff, or do the same to an Arc/Nu library. There's no restrictions between the two, because it all runs in a single namespace.
This means you can write new code with all the shiny features, yet still use old Arc/3.1 libraries. And if you just plain like using Arc/3.1 but there's some Arc/Nu library you want to use? You can.
And if pg ever releases Arc 4, I can just add it as a third language, which will let it interact with both Arc/Nu and Arc/3.1. This is all very very easy to do thanks to boxes.
Now files only export the boxes they create. Which means...
; foo
(def foo ())
; bar
(import foo)
(def bar ())
; qux
(import bar)
(prn bar) ; works
(prn foo) ; error
Basically, "qux" imported "bar" which imported "foo", but "bar" only exported the boxes it defined, thus it didn't export "foo".
This is not only cleaner (and faster), but it opens up the possibility of having two separate Arc versions operating side by side, in the same namespace, able to communicate with each other.
That's important because I really want to have Arc/Nu use hygienic macros and hyper-static scope by default, but that would break Arc 3.1 compatibility. But now I can have Arc/Nu and Arc 3.1 operating at the same time. This was possible before, but was very difficult. Now it's easy.
"Frankly, I think that bracket functions should always have at least one argument permitted."
Groovy does this. The Closure syntax { ... } is shorthand for { it = null -> ... }, which is a one-argument Closure whose argument "it" defaults to null. When I moved from Groovy to Arc, I missed this.
"Well, how did the change not break setforms in arc.arc? Was the original definition for make-br-fn silently overwritten somewhere?"
Yes. The [...] syntax is redefined in make-br-fn.arc after arc.arc is loaded.
I described my opinion of this at https://github.com/nex3/arc/commit/957501d81bafecab070268418.... It did break my code, but I don't mind breaking changes these days (maybe because I'm hardly a user!), and I think a:b syntax is already more useful than either version of [...].
Well, how did the change not break setforms in arc.arc? Was the original definition for make-br-fn silently overwritten somewhere? Last I checked there is still a (let argsyms (map [uniq](cdr expr) ...) inside of the definition of setforms in arc.arc even in the latest versions of Anarki. This will not work with the change to bracket functions that has been made.
Frankly, I think that bracket functions should always have at least one argument permitted.
1. Arc 3.1 uses a kludgy uniq that doesn't actually guarantee unique symbols. I hooked it up with racket's infrastructure at some point, which happens to permit an optional arg.
$ racket
> (gensym)
'g25
> (gensym 'tmp)
'tmp26
2. Also, anarki generalizes arc 3.1 by permitting any number of args to [], including zero:
anarki> ([prn "abc" _1 _2] 34 35)
"abc3435"
This is indeed incompatible with arc 3.1 in one way:
arc3.1> ([prn "abc"] 34) # Must provide one arg, but ok to not use it.
"abc"
anarki> ([prn "abc"] 34) # Must provide exactly as many args as expected.
Error: .. arity mismatch ..
arc> ([(prn "You entered " _)] 34)
You entered 34
Error: "car: expects argument of type <pair>; given ()"
That's good investigation. Note the work described in this thread uses Arc 3.1, not Anarki.
Btw do you mean there's something wrong with defop, or that the example I wrote is incorrect? I had gotten that example from: http://arcfn.com/doc/srv.html
arc> ([(prn "You entered " _)] 34)
You entered 34
Error: "...urces/arc/ac.scm:974:33: arity mismatch;\n the expected number of arguments does not match the given number\n expected: 1\n given: 0"
Do you see something different? I think your defop expression is also incorrect. It just happens to have the right side-effect before it runs into the error. You probably have errors at the server -- that aren't visible on the browser.