
Lisp-1 Has Won - galfarragem
https://sulami.github.io/posts/lisp-1/index.html
======
kazinator
> _Almost every other somewhat popular language chooses to share a single
> namespace between functions and variables._

Almost every popular language is also not a Lisp at all.

That must also be a well-informed, modern design decision; therefore, just
don't make your language a Lisp.

> _Examples include Clojure, Janet, Python, Java, JavaScript, and even Rust._

The latter three are completely unsurprising given that Algol, Pascal and C
have one namespace for functions and variables.

Oh, and object file formats for assembly languages have one namespace for
functions and variables: there are just symbols which name anything.

However: object file formats are actually smarter than that: they have named
sections, which give the user any number of namespaces. You can have dynamic
symbols, debug symbols, symbols needed during initialization only, ... Within
a given section, though, symbols are in one namespace. You can't have an x
function and x storage location both in the .text section.

Speaking of low-level, not all machines put code and data into the same space.

> _The set of LISP2 languages is quite small these days. Besides Common Lisp
> and Emacs Lisp, both of which are over three decades old at this point,
> there are also Ruby and Perl._

Algol traces back as far as 1958. The hypothesis that the single namespace is
a more modern development doesn't hold water.

When taking a historic look, you have to consider some of the years that were
before you were born.

------
lispm
I didn't know there was a contest.

Not mentioned: R and Elixir are 'lisp-2'.

~~~
kazinator
POSIX shell is a Lisp-2.

 _foo_ is a function (if in the first position of a command), otherwise just a
"word":

    
    
       foo foo bar # look for foo function or command, pass "foo" and "bar" arguments
    

The prefix $ must be used in any position in order to resolve a variable name.

    
    
       $command $foo bar # substitute $command and $foo, then re-parse
    

A function foo and variable foo can co-exist:

    
    
       foo=/usr/bin/foo
       foo()
       {
          print $foo # no conflict
       }
    

GNU Make is a Lisp-1, but needs a $(call F,X Y) operator to pass arguments to
a macro F defined as F := <body> where in <body> the insertion of arguments is
indicated using $(1), $(2), ... All the disadvantages of Lisp-1 with all the
disadvantages of Lisp-2.

------
kazinator
TXR Lisp dates back to 2009 (actually later, because TXR didn' expose a Lisp
initially). It's a Lisp-2.

I'm extremely well-informed on the Lisp-1 versus Lisp-2 topic; about as well
as anyone can be, which makes me incapable of making a wrong choice. Yet, I
made it fundamentally a Lisp-2.

However, I also imbued it with a way of expressing in a Lisp-1 style, because
there is value in being able to work with higher order functions without
clutter.

Lisp-1-like evaluation is implemented as a special operator called _dwim_.
(dwim f x y ...) evaluates the argument expressions in the same way. If any
argument is a symbol, it is evaluated in a combined namespace consisting of
the visible function and variable bindings. Other arguments are evaluated in
the ordinary way. The programmer normally doesn't write (dwim f x y ...) but
rather uses the read syntax [f x y].

There is certain psychology at play in the [f x y] syntax. Objects other than
functions are callable. For instance, a vector and array are callable. [vec 0]
denotes the first element. Lots of languages use [ ] for indexing, and this
plays into that.

There is also a rule that f may not be a macro or special operator. So [let (a
b) ...] is nonsense, unless there is a binding for _let_ so it resolves to a
function. In any case, it doesn't refer to the let special operator. The [f
...] notation assures the reader that f is a callable object, and not an
operator.

The symbolic arguments of dwim may be symbol-macros: (symacrolet ((a f) (b x))
[a b]) is equivalent to [f x].

The existence of separate symbol macros and operator macros is one of the
arguments for Lisp-2. They are different. An operator macro M can only be used
in the (M ...) position. Macros aren't stored in variables or passed around. A
symbol macro and operator macro are processed similarly in that they are both
replaced during expansion, yet differently; they do not have uniform
evaluation.

The user of TXR Lisp knows that there can be no special operator _f_ or
operator macro _f_ which intercepts the meaning of [f x y ...]. It is
absolutely functional; the arguments are subject to the same evaluation
treatment regardless of what is in the environment. In a block of code in
which all parentheses are square, you know that there are no special operators
or macros whatsoever; every name you see is resolved in the function/variable
namespace (or else is a symbol macro) and all evaluation proceeds by
application.

Looking at this backwards: the [f x y ...] application-only, no-operators
syntax could be obtained very easily in a Lisp-1 dialect, and without
complications, as a sugar for some (call f x y ...) form. Done! But since _f_
has moved to the second position, Lisp-1 versus Lisp-2 is no longer entirely
relevant to it. We can have that notation in a Lisp-2 if all we do is turn
_call_ into a somewhat smarter operator which knows how to resolve symbolic
arguments across both namespaces.

