Can you explain how it is a consequence?
Can you explain how it is a consequence?
Note that I did say "Some of the more modern languages have that facility, but it's rarely as elegant as it is in Lisps."
Example: JavaScript is sometimes claimed to have first-class functions. It kinda does, but you can't redefine (e.g.) the "+" function as you can in Lisps. So it's basically half-assed. C has function pointers, which again is (sort of) like first-class functions, but also don't let you redefine "+" (they're also incredibly ugly to use). C++ has operator overloading, so you can (again, sort of) redefine "+", but unless things have changed since the last time I used it (which has admittedly been a long time, though not long enough), I believe that's only available at compile time, not run time.
And of course even in (e.g.) JavaScript when you redefine a function it doesn't automatically get compiled, as it does in many Lisps (maybe the JIT will eventually get around to it, maybe it won't).
And so on.
(I'm using "function" here as a shorthand for "function or procedure" because I don't want to type that a half-dozen times).
Lisp doesn’t even have "operators" — everything is a function. Gosh, the more you learn about Lisp, the more it feels like we went backwards. We tried to simplify programming, only to find ourselves buried under layers of complications. Just think about how many times we've reinvented state management for React alone: Redux, MobX, Recoil, Zustand, Jotai, Effector, XState, Overmind, Hookstate, Easy Peasy, Rematch. And that's not even a comprehensive list. What's funny is that some of these are "improved" versions of previous "improvements". Each time we try "improving" the previous "improvement", it seems we continually need to reinvent another layer of "improvements". Dafuk are we doing?
Don't learn wrong things. Lisp has operators and no, not everything is a function. LET for example is not a function. It is a built-in special operator in Common Lisp. Similar in other Lisp dialects. Scheme R7RS documents "let" as syntax: https://standards.scheme.org/corrected-r7rs/r7rs-Z-H-6.html#... with a "named let" as a variant: https://standards.scheme.org/corrected-r7rs/r7rs-Z-H-6.html#...
In Emacs Lisp: https://www.gnu.org/software/emacs/manual/html_node/eintr/le...
"The let expression is a special form in Lisp..."
Also: limiting the redefinition of standard operators is not backwards, it's useful, to prevent to crash a Lisp, since in Lisp function names are often late bound. -> changing a core function will have immediate effect on all code using that.
Macros are also not "function". Macros are operators which expand source code to new source code.
Lisp typically has these operator types:
* functions, which are operators which get called with evaluated arguments
* macros, which are operators, which get called with source code and which return new source code
* special operators (QUOTE, LET, DEFUN, SETQ, IF, ...), which are typically hard-wired in the implementation with both syntax and semantics. Scheme has a set of those, too.
Additionally one my see fexprs, which are operators, which are called with source code. Then in some Lisps some functions lazy evaluate their arguments.The glossary of Common Lisp explains "operator": https://www.lispworks.com/documentation/HyperSpec/Body/26_gl...
operator n.
1. a function, macro, or special operator.
2. a symbol that names such a function, macro, or special operator.
3. (in a function special form) the cadr of the function special form, which might be either an operator[2] or a lambda expression.
4. (of a compound form) the car of the compound form, which might be either an operator[2] or a lambda expression, and which is never (setf symbol).
> You can't redefine itIn standard Common Lisp it is UNDEFINED what happens when one redefines a standard operator of Common Lisp. Typical implementations will signal an error (which often provides a restart). Typical implementations will also extend this to other protected packages, such that the user can't accidentally replace an operator and the Lisp system may crash.
When a is a class type (and more recently this is now supported for enumerations also) then the surface syntax a + b means the same thing as a.operator+(b): invoking the operator + member function of a with argument b.
Unless I'm mistaken (which I may well be), you can't do that at runtime, only at compile time.
Indeed, in C++, our a + b expression is statically analyzed to be working with specific types; the declared types of a and b. When that code is compiled, it will work with no other types.
However, if we anticipate that kind of extension, we can have a be a reference to some numeric_base class where operator + is a virtual function.
With some help from a bit of platform specific coding, we can have dynamically loaded modules which can provide new classes derived from numeric_base that ca be passed to existing code in the program which uses + on numeric_base.