Yeah I'm not sure I understand all the implications. It probably wouldn't be an entirely new evaluation model. Perhaps you just have def store pre-evaluated names.
I went back to your examples, and I think first:rev is already resistant to changes to first or rev (Update: confirmed [1]). What's hard is:
(= first car)
Perhaps we should give def a specialcase so that
(def first car)
creates a synonym without hardcoding the implementation. How about this?
(mac alias(a b) `(= ,a (late ,b)))
[1] Observe:
> (= first car)
> (= last first:rev)
> (last '(a b c d))
d
> (= first cadr)
> (last '(a b c d))
c
I was going to call that '=late. ^_^ There are still other cases where a global function can end up stored somewhere it doesn't stay up-to-date with the variable binding, like storing it as a behavior in a data sructure or using (compare ...). But I don't expect to need anything more brief than 'late, actually.
It's funny, I hadn't settled on the name 'late until I posted it here, and before that point I was thinking of it as 'alias. ^_^ I wanted to avoid confusion with Racket's aliases, so I changed it at the last second.
macros?
Macros generally aren't hackable anyway, right? I don't have any ideas to change that.... Well, except these I guess. :-p
a) Change the whole language over to fexprs. This is probably the most elegant way to make things hackable, but it'll probably be inefficient without a convoluted partial evaluation infrastructure (ensuring things are free of side effects, and headaches like that ^_^ ).
b) Record which macros are expanded every time a command is evaluated, and re-run commands whenever their macros change. Running commands out of order and multiple times would be pretty confusing. (I bet there'd be ways to manage it, but I for one would forget to use them at the REPL.) It would also be easy to fall into an infinite loop by trying to redefine a macro using a command that actually uses that macro.
first:rev is already resistant to changes in first or rev
Oh, good to know. ^_^ For Penknife, I tried to make [= foo a:b] produce a custom syntax if a or b was a custom syntax, but I got stuck. I ended up with [foo ...] using the local values of a and b, I think. In the process I got a bit confused about how a:b was supposed to work in the edge cases, from a design point of view.
This experiment was reflected in two commits in the Git repo: One introducing it, and one removing it 'cause of the poorly thought-out complexity it introduced. :)
Here it is. https://github.com/rocketnia/penknife/commit/3ca7a6c216cc022... Penknife's significantly more complicated than what I've been able to talk about so far, with its own ad hoc vocabulary throughout, so good luck. ^^; Then again, that's a pretty old commit, so it's actually a simpler codebase in ways. XD