
The truth about Lisp (2006) - 0xmohit
http://www.secretgeek.net/lisp_truth
======
qwertyuiop924
This really is a great piece of affectionate satire. Lisp evangelism is
annoying, even to Lisp programmers.

In any case, Lisp may be the best language, but it's not the most powerful.

What is the most powerful? The language from which god wrought the
universe.([https://xkcd.com/224/](https://xkcd.com/224/))

------
reidrac
I found really interesting the amount of broken links in a blog post that is
10 years old, besides the fact that the blog post still exists after 10 years.

~~~
tempodox
One of those links has a domain of “webhost4life.com”. That must have been a
short life.

------
avindroth
I am fairly deep into learning Haskell. After I am done, should I learn Lisp
(SICP)? Smalltalk? Prolog?

I am learning these languages for mind-expansion.

I am also studying AI, will learning Lisp be relevant? (e.g. Help me reason
about and write AI systems)

~~~
jerf
Haskell and Lisp complement each other in a lot of ways. Lisp is about
empowering the programmer, and building on that empowerment. Haskell is about
restricting the programmer, and then building on those restrictions. For a
clear example, consider STM, how it works in Haskell, and how it doesn't work
particularly well in Lisp because of the inability to restrict transactions in
the necessary way.

Lisp is good to learn, but because it has "won" in a lot of ways I'm not
convinced it's as important as it used to be. Lisp acquired its reputation in
a world where a C programmer would pick up Lisp and _holy shit_ dynamic
typing, first-class functions, garbage collection, REPL, macros, powerful
syntax-aware editors (which C got, but later), atoms, recursion, _violent
foaming at the mouth and falling down in sheer awe_. If it's still your first
language after C, sure. But if you learned, say, Python in school, the list
comes back to "macros, which you really shouldn't make much use of in the more
modern understanding, and a bigger focus on recursion". Less likely to make
you pass out in awe.

(Since I find I sometimes piss people off by claiming Lisp is less than the
bee's knees, remember, it's because Lisp _won_ in a lot of ways. It blazed a
trail that every modern language today has traveled to some extent or other.)

Haskell still has a counter-cultural element because of the fact that Lisp is
quite dominant right now and most languages are about empowering the
programmer to do anything at any time. The restrictions-based languages are
just starting an ascent (currently probably being led in practice by Rust, I
think, if it's not already bigger than Haskell it probably will be in less
than a year), but it's still pretty early.

~~~
nickpsecurity
"Lisp is about empowering the programmer, and building on that empowerment.
Haskell is about restricting the programmer, and then building on those
restrictions."

Best, briefest way I've seen it described. I think that's how I'll start
describing it, too.

~~~
collyw
Its the Perl versus Python argument of functional programing languages.

~~~
nickpsecurity
Creative. Yeah, I can see that.

------
Impl0x
> computers of the future will not be able to implement any of our ideas
> without creating time-travelling algorithms that borrow processing power
> from other computers that are further into the future.

> This sounds difficult, but in lisp it isn't difficult at all.

> in haskell this is a built-in feature

The creepiest part is that it's almost true:
[https://hackage.haskell.org/package/tardis-0.4.1.0/docs/Cont...](https://hackage.haskell.org/package/tardis-0.4.1.0/docs/Control-
Monad-Tardis.html)

------
kossmoboleat
I still do wonder why reddit was reimplemented in Python, but with rewrites in
other languages I think that rewriting in itself made it more readable and not
using the other language. Plus maybe using a web framework instead of doing
most by hand, because I assume lisp had even fewer good web frameworks than
python then.

~~~
coldtea
> _I still do wonder why reddit was reimplemented in Python_

Because they new Python better and/or it has a better and vastly bigger
ecosystem and libs, and it being Lisp only gave the very marginal returns of
being cool to your programming peers.

~~~
mbrock
That seems like an unnecessary jab.

~~~
coldtea
Not if it's true.

Python does have a better and vastly bigger ecosystem and libs.

And doing something in Lisp doesn't offer any huge benefits over Python --
besides the cool factor.

Sure, Lisp has some tricks Python doesn't have -- macros, homoiconicity,
uniform syntax, etc -- but still with those, in real life, people haven't been
able to come with anything like an order of magnitude or at least several
times better programs or faster development than with something like Python.

Just ask Norvig.

~~~
fractallyte
Actually, someone _did_ ask Norvig... ;-)

[https://news.ycombinator.com/item?id=1803627](https://news.ycombinator.com/item?id=1803627)

------
peter303
LISP is powerful because its fundamental syntatic structure and data structure
are the same- a list where the first element is the function-name or keyword.
You can basically write programs that extend themselves by writing out new
functions and data.

Other modern languages like html and json have the nested list as the
fundamental data structure. But they arent self-executing like LISP.

But having one main syntactic and data structure- the list- is what makes LISP
annoying too. You have to translate other syntax and data structures into
lists. Its always possible, but sometimes kludgey and unreadable.

An advantage of LISP in the 1960s was that it was interpreted, i.e. relatively
high speed feedback for short programs, compared to its competitors which
where batch-compiled, and might take hours to see how they would run.

~~~
TheLarch
"But having one main syntactic and data structure- the list- is what makes
LISP annoying too. You have to translate other syntax and data structures into
lists. Its always possible, but sometimes kludgey and unreadable."

I like everything but the quotation above. This is a higher-level version of
the ubiquitous "the parens are ugly" objection.

This objection misses the point because "Lisp is a building material, not
language." In order to use Lisp effectively you design an intermediate
language appropriate for the problem domain. This approach is fundamentally at
odds with a language such as Java, whose premise is that it provides all the
abstractions you need to solve the problem directly. With Lisp you literally
have whatever language you want.

Non-Lisps leak more and more as complexity increases. Two examples that jump
to mind right away are lambdas in Python and generics in Java. In both cases
the designers plugged holes in the abstractions they chose years before. Both
are kludgey in my eyes, clear afterthoughts. Both features are trivial in
Lisp. Lisp is so simple that the limitations never arose in the first place.
Your language has made a compromise to simplify these things, but at the
expense of flexibility. C++'s accretion disk is a marvel at this point.

You can use macros to streamline elaborate data structure creation by the way.

------
grabcocque
Clojure is currently the sexy lisp du jour.

When I first learned Clojure, to me it was the first time programming truly
clicked with me. That first time I ever felt that spark of "oh my god, so
that's what programming can be like!"

~~~
pjmlp
I really enjoy playing with it, and every now and then, do my 4Clojure
challenges.

But the only scenario I could eventually use it for, portable code between
Android and UWP isn't really covered by it.

ClojureCLR is behind Clojure and doesn't run on .NET Core.

Clojure for Android still has lots of performance problems and the project
hasn't been updated since mid-2015.

~~~
JBiserkov
Take a look at ClojureScript (if you haven't already).

It compiles to a subset of JavaScript which is then compiled and optimized
with the Google Closure compiler (the one used for GMail and GMaps) to produce
even better JavaScript.

You can target UWP and Android via React Native + ClojureScript react
wrapper(s). A interesting fact is that the wrappers are up to twice faster
than the normal react due to immutability in the language which enables very
efficient implementations of shouldComponentUpdate.

[https://blogs.windows.com/buildingapps/2016/04/13/react-
nati...](https://blogs.windows.com/buildingapps/2016/04/13/react-native-on-
the-universal-windows-platform/)

~~~
pjmlp
I don't want to use JavaScript based tools.

Right now I am using C++14.

~~~
mcguire
Isn't that roughly akin to saying, "I don't want to use the combination
hammer/screwdriver; I prefer to bang the threaded nails in with flint flakes
that I have knapped myself and that are sharp on every side?"

~~~
pjmlp
No, C++ is a first class language in iOS, Android and WP SDKs with
corresponding tooling, debuggers and IDE support.

JavaScript implies another layer to debug and even more complexity writing FFI
code.

------
type0
> Paul Graham originally wrote reddit, in lisp, on the back of a napkin while
> he was waiting for a coffee. it was so powerful that it had to be rewritten
> in python just so that ordinary computers could understand it.

Because you need a true Lisp machine... Next thing you know, you'll be waking
up in "the matrix".

~~~
criddell
> Because you need a true Lisp machine... Next thing you know, you'll be
> waking up in "the matrix".

Hey now, Symbolics machines may have not been the fastest, but I rarely fell
asleep in front of them.

------
tehmillhouse
And thus the student was enlightened.

------
JohnStrange
I prefer Racket to Lisp. But in a sense it's also Lisp, just not Lisp-2.

~~~
qwertyuiop924
I prefer Scheme to Racket. But that's also lisp.

And scheme and racket are far closer together than Common Lisp.

------
calibraxis
Braced myself before reading this, but what a pleasant surprise!

> infinite number of closing parentheses

Nowadays, you can express it with finite parentheses using -> macros
popularized by Clojure.

~~~
yomly
The thread macro is really a treat and allows for more expressive functional
piping of data. A lot like dot chaining in your python/scala/rubys or
cascading in Javascript - get a lot done with minimal boilerplate

~~~
JBiserkov
Clojure even has a .. macro which makes dot chaining even more readable - the
resulting code has less dots and less parenthesis than the equivalent
java/python/ruby/scala code!

------
jokoon
I sense it would be way more entertaining to learn how to make a language with
clang, learning BNF notation, understanding LL and LR parsing, than learning
lisp or haskel.

That way you quickly overwhelm zealous and eager students so they can calm
down and stick with the languages normal people use, and stop with those usual
functional rabbit holes.

------
timewarrior
When I started using Clojure, the first two weeks were mess. I was trying to
fit everything in procedural way of thinking and boy was it a mess. I felt
really miserable and maybe that is how it felt when I first started to walk.
And then suddenly everything clicked and the world was beautiful.

Clojure has a steep learning curve when you start. After about a year and a
half there is another much steeper curve and if you cross it, I have heard it
feels like you have super powers. I am probably 4/10 on Clojure and 9.5/10 on
Java. However I take around 10% of time to get better results with Clojure vs
Java.

I can try taking a shot at listing why I love Clojure however for me it is as
difficult as explaining why I love someone:

1\. Computers are functional. You give them a massive subroutine and they
execute it. All procedural languages have built semantics to make it
supposedly easy for humans to write code but end up with a lot of hacks. Only
you start writing functional you feel finally connected to the computer.

2\. Immutable structures: With most languages it's difficult to have
assumptions about how your code will work. You pass your data to a function,
can they change the data due to a bug or bad design. Do you create a copy
before sending it to them? All those issues go away. It's better to understand
expectations and stupid errors go out of the way.

3\. Reusable code: because it's functional and without side effects it's much
more easier to create reusable code as a part of standard library. You have
functions like butLast (give me all elements of an array except last), even?,
rest (return all elements of array except first). Imagine how much less boiler
plate would it be. Check out some of the functions here:
[http://clojure.org/api/cheatsheet](http://clojure.org/api/cheatsheet)

4\. Encourages you to write smaller chunks of functions, not 2000 line long
functions. Improves code reusability and testing.

5\. Doesn't allow bad design practices - circular dependency.

6\. Because the language is built on a very few core constructs, you or anyone
else can enhance the language. I have seen situations where someone had a
proposal to extend the language, they just releases it as a library. If people
like it and use it, it would get included as a part of core framework.

7\. The quality of available talent - Because there is a steep learning curve
almost everyone Clojure programmer that you meet is likely to be very smart.

8\. Has inbuilt support for magical stuff like macros, STM. You can Google it
to find out more.

9\. Imagine all the java libraries that were very complicated to use and with
their confusing java docs. Clojure community has built a lot of super easy to
use wrappers on top of it and you could easily write one too.

10\. In other languages if I see a library on github which hasn't been updated
for years, it feels like it has been abandoned and I would not consider using
it. With Clojure, because of functional and no side effects - a code which
works now is likely to keep on working with it's current contract. It is not
uncommon to see libraries which were built by some of the rockstars in the
community within a day and not updated for years but still they work great.

11\. Because of being functional and no side effects, code hot replace
actually works. Many other languages have attempted it, but it always comes
with a bit of caveats. With Clojure it just works. My developer code flow was
that I would use an IDE and which I am writing code, it would hot replace the
code in VM, find the tests which depends on the changed code and run just
them. So I can see the code I am breaking while I am writing code. This is
unbelievable. When we had an issue, I used this to connect to a REPL (a
commandline for VM) - hot swapped a code to add logging, figured out the
issue, fixed the code locally, copied the function to replace the code on
running server, fixed the code and pushed it again (I wouldn't recommend
people do this, but explains the power at your fingertips).

This list could go on and on. In my current job, I am building a big team
where any set of people could come together and build a startup. Like Google's
Area 120, but started more than an year before that. Unfortunately I am not
encouraging people to use Clojure here, because it would set them back by
months. I really love my current job, however I keep getting impulses of
quitting everything and just code Clojure full time.

I hope people can see that I am smitten. Give it a try and I promise you
wouldn't regret.

edited: for readability

~~~
icebraining
_You have functions like butLast (give me all elements of an array except
last), even?, rest (return all elements of array except first). Imagine how
much less boiler plate would it be._

As a Python programmer, those sound like a poor tradeoff for slicing syntax.
And why do (drop) and (nthrest), which seem to do essentially the same but for
lazy/non-lazy, take the arguments in the inverse order?

~~~
madmax96

        > As a Python programmer, those sound like a poor 
        > tradeoff for slicing syntax. 
    

Because Python has a static syntactic system. To Lispers, it makes no
difference whether or not it's slicing syntax or a function call. Clojure also
has a `subvec` function that behaves the way you're getting at.

    
    
        > And why do (drop) and (nthrest), which seem to do 
        > essentially the same but for lazy/non-lazy, take the 
        > arguments in the inverse order?
    

The partial function application for `drop` allows you to create a "dropping"
function like `(partial drop 10)` that you can pass about (such a function has
a particular use-case w/ transducers), and partially applying `nthrest` lets
you create a "to drop" function like `(partial nthrest [1 2 3])` that you can
pass about.

~~~
icebraining
_Because Python has a static syntactic system. To Lispers, it makes no
difference whether or not it 's slicing syntax or a function call._

Conversely, as a programmer, I don't care if the syntactic system is static or
not :) what I care about is ergonomics.

subvec doesn't seem to support negative indices, so while it sounds
superficially similar, it can't replace all those tiny functions (like
butLast), while slicing can.

~~~
madmax96

        > subvec doesn't seem to support negative indices
    

You don't need negative indices to define a function like `butlast` (or any
function for that matter):

    
    
        (defn my-butlast [vec] 
            (if (empty? vec) nil
                (subvec vec 0 (dec (count vec)))))
    

If you really care about negative indices support (although you shouldn't
because _it is wrong_ ) then you can easily add this. IMO, negative indices
hide bugs and obfuscate code. Complaining that a Lisp doesn't support syntax Y
is kind of silly because of the extendable syntax of the language -- if a
language implements Y, then Lisp can implement it as well. Since we have
macros, we don't even need to touch the core language, and this is a huge
advantage when it comes to language durability. As the Clojure community is
very healthy, we have appropriated all sorts of ideas from other languages
(most notably, a very "inspired" implementation of Channels from another
language and a new spec system that bares a striking resemblance to Racket's
contracts...) :) If Python comes out with an earth-shattering language
construct, we'll gladly appropriate it and continue along our merry way.

~~~
icebraining
_You don 't need negative indices to define a function like `butlast`_

No, my point is that if you have negative indices, you don't _need_ butlast
and a bunch of other functions; those just add more cognitive burden, in my
opinion.

 _Complaining that a Lisp doesn 't support syntax Y is kind of silly because
of the extendable syntax of the language_

I wasn't complaining, and this discussion isn't just about the syntax. The top
poster was citing those functions as qualities of Clojure _and its stdlib_ ,
so I was comparing the two. Obviously I can write a subvec with negative
indices support, but then I can also easily write a butLast in Python. But
those wouldn't be in the stdlib.

I'm not even trying to put down Clojure, I don't even know enough about the
language, my reply was specifically about those functions and the praise
thereof.

~~~
madmax96

        > those just add more cognitive burden, in my opinion.
    

Of course that is a valid viewpoint, but remember that using a function
(instead of splicing syntax) has the added advantage of being _composable_ and
_applicable_. These two features are crucial when you're dealing with
efficient persistent data structures and separating purity/impurity, so in a
very real sense you do _need_ these things as they make life easier in other
areas. Python isn't a functional language and doesn't have to concern itself
with dealing with persistent data structures efficiently and so they don't
mind that to achieve a composable and applicable splicing solution they'd have
to wrap the splice in an abstraction. That's fine, because if you're writing
Python like that, then you're probably writing Python wrong (in the sense that
it wouldn't perform or read as well as it would if you would have just used a
functional language.) But if you're writing functionally, you obviously
consider that abstraction's standard existence a good thing.

The linguistic philosophies of Clojure and Python are radically different that
these functions are a quality for Clojure, while if you're writing Clojure
like you'd write Python you would consider them unnecessary.

~~~
icebraining
Yeah, functions have those advantages. That's why Python also has slice(),
which you can then apply to any list, in a composable way. But when you don't
need those features, the splicing syntax adds less crud than a bunch of
function with non-obvious names.

Eg. use of slice():

    
    
      >>> butLast = slice(-1)
      >>> getitem([7, 8, 9], butLast)
      [7, 8]

~~~
madmax96

        >  But when you don't need those features

Ah, in a purely functional language you always need those features :)

------
spdionis
Today we could add node.js to the replacements list.

------
adamnemecek
You should add 2006 to the title. The topic is very mid 2000s.

~~~
blunte
With anything (especially technical) I read online, the first thing I look for
is the post/publish date. Some tech content is timeless, but much of it is
useless if older than two years.

~~~
mcguire
Absolutely. All of the jokes in this article have been reimplemented in Ruby
and then in Javascript since it was published.

------
grabcocque
Extant lisps rated by their likelihood of changing your life:

Scheme: 7/10 Common Lisp: 3/10 Racket; 8/10 Emacs Lisp: 0/10 Clojure: 9/10
LFE: 9/10

These rankings are scientific fact.

~~~
qwertyuiop924
They'll all change your life, but Scheme will change your life more, and
better.

------
catnaroek
That blog post is tagged “functional”, but Lisp isn't a functional language -
not even an impure one.

Functional programming is expressing computations as the evaluation of
mathematical functions whenever it's possible. Sure, some operations are
intrinsically not mathematical functions (like sending data over a network,
returning the system date, you name it), but, in general, data structures and
algorithms should be implemented as values and mathematical functions on them.

Mathematical functions are mappings from _values_ of a domain to _values_ of a
codomain. Naturally, if we want mathematical functions to be a basic building
block for programs, we need a rich set of values on which said functions may
operate.

Now, here's the thing: _Lisp doesn 't have compound values_. The only values
Lisp has are numbers, characters and references to objects. All of them are
primitive and indivisible.

“But, catnaroek, what the hell are you smoking? Aren't lists, structs and
vectors compound values?”

No, in Lisp, they're not. They're mutable objects whose state at any given
point in time may be interpreted as a value in your favorite metalanguage of
choice. Maybe if the metalanguage isn't Lisp itself, you can interpret the
object's state as a _useful_ value!

In case the above wasn't too clear, let's review the difference between values
and objects:

(0) A _value_ is something you can bind to a variable. (At least in a call-by-
value language, which Lisp most definitely is.) It doesn't matter, or even
make sense, to ask whether “this 2” is different from “that 2”. There is
always _one_ number 2, regardless of how many times the number 2 is stored in
physical memory. Nor does it make sense to ask whether 2 will suddenly become
3 tomorrow. 2 and 3 are always distinct values.

(1) An _object_ is an abstract memory region. Every object has an identity and
a current state. The identity is always a primitive, indecomposable value. The
state may be compound, but it isn't always a value. (This depends on the
language.) Even if the current state is a value, the state at a later point in
time might be a _different_ value. Objects with immutable state are largely
impractical - why bother distinguishing the physical identities of entities
that never change?

Now it becomes perfectly clear that, while Lisp has compound objects, it
doesn't have compound values. Sadly, without compound values, you can't have
functions taking compound values as arguments, or returning compound values as
result. Since compound entities are unavoidable in practical programming, this
means you pretty much have to use objects.

“But, catnaroek, what if we encode compound values as Gödel numbers?”

Hah! Have fun with that!

\---

As an exercise for the reader, for each of the following languages, determine
whether it's functional or not: Scheme, Racket, Clojure, Scala, F#, Erlang,
JavaScript. Justify your answers.

~~~
qwertyuiop924
>you can't have functions taking compound values as arguments, or returning
compound values as result.

 _sigh._ Okay then, wiseguy, what's map doing then? Because that's sure as
hell a function, and it's definitely returning and being called with a list.

~~~
catnaroek
Returning a compound object, obviously. And Common Lisp's `mapcar` isn't a
mathematical function.

~~~
qwertyuiop924
>Common Lisp's `mapcar` isn't a mathematical function.

Yes it is. It takes a function and a list as input, and outputs a list of the
results of that function applied to each element of the list. It has no side
effects, it maps a domain to a range, and it's referentially transparent, so
long as the function you passed to it is.

~~~
catnaroek
> It has no side effects

It has the side effect of creating new object identities, at least when its
“list” argument isn't `nil`. That identity is a completely new value that
didn't exist before `mapcar` was called.

> it maps a domain to a range

In mathematics, the domain and codomain of a function are sets. Sets don't
exist “in time”, let alone get new elements in time.

~~~
qwertyuiop924
Oh for god's sake...

Yes, the value did conceptually exist before the function ran. Or is Haskell's
map equally not functional?

And the set for map doesn't grow over time.

~~~
catnaroek
> Or is Haskell's map equally not functional?

Haskell's `map` _is_ a function at the time it is called. If it is called a
second time, and new objects were allocated in between, then `map` is a
different function, but still a function.

> And the set for map doesn't grow over time.

`mapcar` creates new object identities that didn't exist before. It's as
effectful as it gets.

~~~
qwertyuiop924
Whether or not the object is new in RAM is purely semantic. It's the same
values. And whether they are eq is entirely irrelevant to this discussion.

~~~
catnaroek
> Whether or not the object is new in RAM is purely semantic.

Well, we're arguing programming language semantics! And what matters isn't
whether it's a new memory block in RAM, which is an implementation detail, but
rather whether the language will treat the new value or object as equal to
anything that previously existed.

> It's the same values.

Can you bind the “value” to a variable?

~~~
qwertyuiop924
I can bind the concrete representation of it returned by map to a variable,
which is then equal to all other concrete representations of that value. Same
as rust, or any other programming language.

~~~
catnaroek
> I can bind the concrete representation of it returned by map to a variable,
> which is then equal to all other concrete representations of that value.

What you're actually binding to a variable is just the identity of the first
cons cell in the “list”. That's by no means an actual list value. The
difference will be exposed as clearly as daylight if you mutate the cons cell.

~~~
qwertyuiop924
Yes, because that's how lists work. Just like in Haskell.

~~~
catnaroek
Nope. Haskell doesn't expose the physical identity of anything that isn't a
reference cell (STRef, IORef, etc.). It's not even a type error - there's
_syntactically_ no way to query it. You just operate on values directly. The
same is true in SML. Even objects are manipulated via their identities, which
are values.

Because values are a useful abstraction.

~~~
qwertyuiop924
That isn't what I meant. What I meant was that lists are kept as a reference
to the head cons cell, in every language that implements lists as singly-
linked lists. That's just how it works.

~~~
catnaroek
> What I meant was that lists are kept as a reference to the head cons cell,
> in every language that implements lists as singly-linked lists.

That's an implementation detail. Language abstractions are to be judged by
their own semantics, not their possible implementations. And, FWIW, when I
evaluate ML programs by hand on a piece of paper, lists aren't implemented as
references to anything - a list is just a sequence of elements. On the other
hand, if I had to evaluate Lisp programs on paper (thank goodness I don't have
to!), object identities would still appear all over the place.

~~~
qwertyuiop924
>when I evaluate ML programs by hand on a piece of paper, lists aren't
implemented as references to anything - a list is just a sequence of elements.

Well, yeah. Jusr like when I evaluate Lisp. But the _idea_ of a cons cell is
inherent to ML's list struture: They call it the cons operator for a reason.

~~~
catnaroek
> Well, yeah. Jusr like when I evaluate Lisp.

Then you're not really evaluating Lisp programs according to Lisp's well-
defined semantics. Changing the semantics of a language makes the result a
different language.

> But the idea of a cons cell is inherent to ML's list struture: They call it
> the cons operator for a reason.

Yep, but “cons cell” means completely different things in Lisp and ML. In
Lisp, a cons cell is an object. In ML, a cons cell is a value.

~~~
qwertyuiop924
>Then you're not really evaluating Lisp programs according to Lisp's well-
defined semantics. Changing the semantics of a language makes the result a
different language.

So long as the actual semantics (how the language behaves) stays the same, you
can interpret it in your head any way you want. You don't think of lists as a
string of pointers when evaluating ML, and it's the same thing.

>In Lisp, a cons cell is an object. In ML, a cons cell is a value.

That's not the earthshaking difference you seem to think it is. In fact,
values and objects are two aspects of the same thing. At the end of the day,
lists are still chains of pointers, mutable or no, "object" or "value" (and I
have to put it in quotes because your definition isn't in _any_ way the common
one).

I give up. Your mental model seems to be horrifyingly warped and broken, but
it seems to accurately model computation, so it really doesn't matter.

~~~
catnaroek
> You don't think of lists as a string of pointers when evaluating ML,

No, it's not. The Definition of Standard ML says _absolutely nothing_ about
lists or strings being implemented as pointers. Lists and strings are values.

> and it's the same thing.

It's not.

> That's not the earthshaking difference you seem to think it is.

It is. Values have a nontrivial equational theory that enables two
syntactically different programs to be deemed equal using local reasoning
exclusively. That is, without observing the effect of a computation on its
much larger context. This in turn enables much more aggressive optimizations,
both by hand and automatic, than are possible if all you have is object
identities.

> In fact, values and objects are two aspects of the same thing.

Nope. Values are the more fundamental notion, mathematically. Object
identities are but a particular kind of value, and so are object states in any
mathematically civilized language.

> At the end of the day, lists are still chains of pointers, mutable or no,
> "object" or "value" (and I have to put it in quotes because your definition
> isn't in any way the common one).

Lists aren't chains of pointers when I evaluate them on paper. _A list is just
a sequence of elements._ But even when working on a computer, using actual
lists has concrete benefits, for example, the compiler is free to apply
optimizations like “gluing” consecutive nodes to improve locality of reference
(in the generated program) and ease the job on the garbage collector (assuming
the list is used in a single-threaded fashion). In the limit, it's as if I had
used a C++-style `std::vector`! When all you have is object identities, this
optimization is obviously unsound.

------
jackfoxy
I would like to see a light-syntax dialect of Lisp that recognized semantic
white space to get you out of the parentheses maze. (But you could still
optionally use parens when you wanted.)

Disclaimer: I've been coding almost exclusively F# and SQL for nearly 3 years,
and any kind of ceremony and noise characters in code just throw me off.
Typescript is being hard on me right now.

~~~
zeveb
> I would like to see a light-syntax dialect of Lisp that recognized semantic
> white space to get you out of the parentheses maze.

Take a look at sweet-expressions:
[http://readable.sourceforge.net/](http://readable.sourceforge.net/)

~~~
qwertyuiop924
I'd reccomend wisp over readable: it's more readable than readable.

~~~
zeveb
The wisp I found is JavaScript-written-in-S-expressions, not Lisp-written-in-
something-other-than-S-expressions. Naturally, I tend prefer S-expressions,
but I was responding to someone who wanted a homoiconic alternative.

