
Plotting an escape from the quagmire of equality in Emacs Lisp (2012) - tosh
http://technomancy.us/159
======
cronjobber
Quite confused. Two examples:

> It turns out there is very little code that would break if Emacs strings
> became immutable

Which means that very little Clojure code would break if they just went ahead
and used Emacs strings.

> Common Lisp fans claim that lisp-2s have first-class functions, but the way
> they are kept separate from other first-class values in their own namespace
> ghetto brings to mind claims of "separate but equal"—at best it is Jim Crow
> functional programming.

 _Jim Crow functional programming??_ The virtue signalling is strong in this
one. He's wrong on the facts, too.

A Lisp-2 doesn't keep the function inside the ghetto, it keeps everyone else
out. Functions can be everywhere, but a non-function can't be the value of a
function binding. Function's aren't second class in this system, they're royal
class.

~~~
db48x
He means that Emacs Lisp code wouldn't break much if strings were made to be
immutable; you don't generally mutate strings. (Buffers, on the other hand,
are mutated all the time.) I would suspect that the converse is also true
though; Clojure code probably doesn't often rely on strings sharing storage,
so making them mutable might not have a huge effect. I've less experience with
Clojure than with Elisp, though, so I might well be wrong.

As for the latter, it does occasionally feel like functions aren't truly
first-class in a lisp-2 because you have to jump through hoops to pass them
along as an argument (funcall, #'foo syntax, etc). In most lisps passing
functions as arguments is just as common as "calling" non-function values is
in Clojure. Anyway, I suspect that the "Jim Crow" dig was hyperbole, not
intentional virtue signalling. :P

~~~
lispm
> does occasionally feel like functions aren't truly first-class in a lisp-2

The definition of 'first class functions' is not a feeling, but three
capabilities:

    
    
        CL-USER 9 > (let ((sin-fn (function sin)))
    
                      (list
    
                        ; 1)  passing functions as arguments to other functions
                        (mapcar sin-fn '(1 2 3 4))
    
                        ; 2) returning them as the values from other functions
                        ((lambda () sin-fn))
    
                        ; 3) and assigning them to variables or storing them in data structures
                        (let ((v #(1 2 3)))
                          (setf (aref v 1) sin-fn)
                          v)))
    
        ((0.84147096 0.9092974 0.14112 -0.7568025)       ; 1)
         #<Function SIN 410007BC14>                      ; 2)
         #(1 #<Function SIN 410007BC14> 3))              ; 3)
    
    

As you can see, functions are first-class values in Common Lisp.

> In most lisps passing functions as arguments is just as common as "calling"
> non-function values is in Clojure

Including Lisp-2s. Passing functions is completely normal and widely used in
Common Lisp. The Common Lisp standard has literally zillions of functions
where you pass one or more functions in.

Common Lisp also can make CLOS objects callable.

~~~
db48x
You've made my point for me. The very fact that you must write (function sin),
or #'sin, or use funcall is a way that it treats functions differently than
normal values. Since it requires some amount of extra though and/or typing,
this often seen as a bad thing. Compare Scheme, Clojure, or other lisp-1s
where if you want to pass the sin function to someone, you just say sin. That
whole outer let vanishes in those languages, and the result is much simpler.

And just as we both agree that in Common Lisp passing functions in as
arguments is very common, so in Clojure is "calling" a vector on a number to
index into it, or "calling" a symbol to use it as an index into a alist or
hash table, etc. Not only do you not have to type anything extra, you can
treat all values as callable.

~~~
lispm
> The very fact that you must write (function sin), or #'sin, or use funcall
> is a way that it treats functions differently than normal values.

Look closer. I have not used FUNCTION in 1), 2) or 3). Common Lisp does not
treat functions different from other values. They are first class values.

These are the three operations which define whether functions are first class
values:

( [https://en.wikipedia.org/wiki/First-
class_function](https://en.wikipedia.org/wiki/First-class_function) ) :

1) passing a function

2) returning a function

3) assigning them to variables or storing them in data structures

None of that requires anything special for functions in Common Lisp.

What you need to do in Common Lisp, is to use FUNCTION to get a function from
a lexical name and you need to call such a function via FUNCALL, but that has
nothing to do with the requirements for a 'first class datatype', which is
defined by the three requirements above (passing, returning, assigning).

~~~
db48x
> What you need to do in Common Lisp, is to use FUNCTION to get a function
> from a > lexical name and you need to call such a function via FUNCALL, but
> that has nothing > to do with the requirements for a 'first class datatype',
> which is defined by the > three requirements above (passing, returning,
> assigning).

And I'm saying that in practice, regardless of any technical definitions
you'll find in a textbook, this need to treat functions specially is exactly
what makes people who learn Common Lisp wonder why people say that functions
are first class values. You don't have to look up the value of a variable by
writing (variable foo), but you do have to use (function foo).

Clojure goes one step further and lets you treat non-functions as if they were
functions, by using them in the function positions of expressions.

~~~
lispm
> regardless of any technical definitions you'll find in a textbook

It's the definition of first-class values. You may have your own, but then you
need to tell us what you mean first. Communication by redefining established
terms is getting painful...

> why people say that functions are first class values

Because you can pass functions, return functions and store functions. That's
what "first-class datatype" means.

> You don't have to look up the value of a variable by writing (variable foo),
> but you do have to use (function foo)

Only if you want to get the function from the function namespace. If the
function is already referenced in the value namespace, then you don't have to
do it.

> Clojure goes one step further and lets you treat non-functions as if they
> were functions, by using them in the function positions of expressions.

Which existed long before Clojure in Lisp. For example Lisp Machine Lisp had
callable arrays 4 decades ago.

Features like these make it a good write-only language.

~~~
db48x
> Communication by redefining established terms is getting painful...

And here I thought I was telling you that not everybody uses "first-class" (or
even "first-class values") in precisely the same way. I agree that the
strictest definition only deals with how you use the various types of values
you might have in your program, and not with the types of names you can give
them. I hope you can also agree that not everyone limits themselves to just
the values; they see the differences in how functions get stored in the
environment, and recalled from it, and see this as treating the functions
differently than the variables.

This does mean that many people are operating with a broader definition of
what "first-class" means. It would be perfectly clear to call it "first-class
naming", for example, but polysemy is not unique to software engineering; we
must allow for it in all fields of endeavour.

My only point all along was merely that when someone hyperbolically calls
Common Lisp a "Jim Crow" language, they are not wrong merely because they are
talking about names instead of values.

As an aside, I didn't mean to imply that Clojure invented callable arrays,
merely that Clojure programs use them frequently; probably just as frequently
as they use higher-order functions.

I take no position on whether any language is "write-only" or not; that would
be nearly as productive as talking about "virtue signalling". ;)

~~~
lispm
> And here I thought I was telling you that not everybody uses "first-class"
> (or even "first-class values") in precisely the same way.

I know of no other definition of 'first-class value', which is an established
concept since at least Scheme was invented in the mid 70s, which made
functions true first class values. The idea that procedures in some
programming languages were not first-class seem to come from C. Stratchey from
the mid 60s, where functions in Algol can't be the result of compound
expressions, can't be stored in variables and data structures.

> It would be perfectly clear to call it "first-class naming"

If someone would define it and give it some useful semantics, it might be
clear.

> I didn't mean to imply that Clojure invented callable arrays, merely that
> Clojure programs use them frequently; probably just as frequently as they
> use higher-order functions.

This podcast speaks exactly how an error introduced by callable data
influenced the developer leave Clojure for Haskell:
[https://building.fireside.fm/37](https://building.fireside.fm/37)

------
peatmoss
The timestamp shows that this was written some years ago (2012). I know Guile
Emacs has made some progress in the meantime, but is still not done. I wonder
if there have been any other changes that would allow for this to happen.

------
hellofunk
Phil is one of the most interesting people in the Clojure community, and in
the software industry in general. Always good to see what he's thinking.

~~~
sunng
So sad to see he is leaving Clojure community. That's a sign of the death of
Clojure. A few great developers have moved their focus away from Clojure.

~~~
j_m_b
The reports of Clojure's death have been greatly exaggerated.

~~~
hacker_9
Mainly from people who just want the language to fail for some reason.

------
kruhft
"At the heart of Clojure and ClojureScript’s implementation is #equiv that is
in turn based off of Henry Baker’s egal operator introduced in this paper.
Briefly, equality in Clojure is defined by equality of value, which is
facilitated by pervasive immutability. Equality in the presence of mutability
has no meaning."

[http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.23.9...](http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.23.9999)

------
ungzd
> Of course, with a compiler that targets Emacs Lisp, you can work around this
> by implementing your own immutable types

Clojurescript uses this approach and probably it's ok.

