
Lisp in 3 words - thomaskrauss
http://www.vagrant-coder.com/articles/english/Lisp-in-3-words.html
======
JeremyReimer
I feel like I understand what the author is trying to say, because I remember
feeling that "click" in my head when I finally understood why LISP syntax was
the way it was, and why it was the best possible syntax. (It was at the same
time that I realized that RPN was the best possible mathematical syntax, if
that makes any sense).

It's hard to explain this to other people, however. It's doubly hard trying to
explain it to people who have spent their careers building up high levels of
skill and knowledge in other languages.

I'm not a professional coder-- I'm a hobbyist. I can program badly in many
different languages. But I find that with LISP, I am much more productive and
happier. I feel like I can "punch above my weight" using LISP, achieving
things that would take a lot more skill and effort to do in other languages.

I sometimes wish I could explain it better to other people, but other times
I'm just happy to work on my own in my "obscure" language with the all the
silly parentheses.

~~~
superobserver
Is Lisp anything like Lambda Calculus? If so, then I should get in on that,
since I taught myself LC in a day. I saw the sheer power and beauty of it when
I had "programed" ternary logic operators on paper with it. The only issue I
had was the excessive use of parentheses. If there is a way to structure LC
like Python (replacing the syntactical function of parentheses with
space/indents), then I'd be sold on that for sure.

~~~
andolanra
There's a lambda-calculus-like core to Lisps, but there's enough on top that
I'm not comfortable saying that Lisp implementations are "just the lambda
calculus." As for indentation-based syntax, there is a Scheme SRFI[^1] that
specifies an indentation-based syntax, although I'm not sure how many Schemes
actually ship with implementations.

[^1]: Various extensions to Scheme are proposed as numbered SRFIs; the
extension in question is SRFI 49, as defined by
[http://srfi.schemers.org/srfi-49/srfi-49.html](http://srfi.schemers.org/srfi-49/srfi-49.html)

~~~
moron4hire
I might be mistaken, but I believe a Python-like syntax for Racket was the
strategy undertaken for Pyret: [http://www.pyret.org/](http://www.pyret.org/)

I can't find any direct connection to Racket, though, and it's not part of the
Racket package repository.

~~~
sparkie
The connection to Racket is the people behind it. Pyret was developed by
students of Racket's developer, S. Krishnamurthi (with his support).

~~~
greghendershott
I think Shriram would point out he is one of many people responsible for the
development of Racket.

------
Lambdanaut
I don't like to be so negative without an objective reason, but that was
really very rambling. I don't feel like I learned anything there.

I don't doubt Lisp is beautiful, but I don't think the author explained it
well.

~~~
rthomas6
They didn't. But I think I understood it anyway and can explain it to you.

As a result of Lisp being in prefix notation, which is just a fancy way of
saying you always put the action first (for instance you add numbers like (+ x
y z)), that design choice results in EVERY part of the language having the
same syntax. That is, _everything_ is an action that eventually returns a
value, and it all is used the same way. There are no special syntaxes --
loops, conditionals, function definitions, everything. Since it's all the
same, everything all the way up to the top level is one action composed of
other actions chained together.

Parentheses in Lisp languages are used differently than other languages:
parentheses are used for grouping and ordering in other languages, but in
Lisps they're used to denote scope. The first word after an open paren is
always an action, and every word thereafter is always an argument. Then
arguments can be a lower level of scope which performs another action, and so
on.

So really, Lisp has almost no syntax at all, and a Lisp program is nothing but
a big tree of actions that start at the top level and work down (sort of).

~~~
pkaye
"Reverse polish notation" is postfix notation where the action is last. For
example Postscript or Forth. Lisp is prefix notation where the action is
first.

~~~
rthomas6
Oops, corrected. Thanks!

------
sago
I'm a big fan of Lisps. I like the simple syntax. Scheme is my go-to tool for
some jobs, particularly metaprogramming. And I use the syntax a lot for DSLs
because it is so trivial to parse.

But there is something to be said for using syntax as a way of representing
meaning.

Conditions, loops, function definitions, types, and so on, can be expressions
(depending on the language, they may be fundamentally so), but having them
look different, that reduces the interpretive burden, I think.

Perhaps the bigger lesson of the OP is how few programmers understand how
their language works. A case for people to write their own languages as part
of a CS course, maybe?

I can't remember who said that learning Lisp makes you a better programmer,
even if you don't use it day to day. I strongly agree. It did that for me.

~~~
Bognar
> Conditions, loops, function definitions, types, and so on, can be
> expressions (depending on the language, they may be fundamentally so), but
> having them look different, that reduces the interpretive burden, I think.

I think this is a very important point. Since everything is the same in Lisp,
it's nearly impossible to have an idea of what the program is doing "at a
glance". In (sane) syntax heavy languages, you can glean a significant amount
of information in a short period of time just by scanning the syntax without
reading the code.

This is less of an issue when writing a program, and more of an issue when
maintaining one.

~~~
thomaskrauss
I sure have a bit more problems maintaining Lisp code than writing it. But
here I'm more comparing these two endeavors with one another while dealing
with Lisp rather than comparing each one to the same endeavor in another
language. Writing Lisp code is such a breeze that it is in fact unfair to
compare other tasks to it. It's also a bit unfair to compare writing Lisp code
to the task of writing code in many other languages.

It is very true that in syntax heavy languages, scanning is made very
efficient from the syntax of the code. And sure enough, with big chunks of
Lisp code, scanning is a chore. But it is important to understand that
scanning is an enabler or, in a more mathematical expression, it is a
sufficient condition to make scanning a palatable option. But it is absolutely
not a necessary condition.

How?

Lisp code is generally terse and split into several tiny functions. There are
some exceptions of course and, based on my experience, there is no exception
for such exceptions: they are all tedious to read.

How tiny are the functions you may asked? Here's some stats about my project:

It has 8368 lines of Lisp code for a total of 676 definitions (variables,
functions, macros and some other things). The average ratio of lines of code
required per definitions is thus 12.37! That is completely, absolutely way way
less than code in C, Java or Javascript. You may say that I just have a lot of
very tiny utilities in the range of, say, 3 to 5 lines of codes. While it's
true in a way, the overall average holds well to about 12 lines of code even
if you look at the level of code systems (rather than the whole project) or
even at the level of files (rather than whole libraries).

The point that I am trying to get across is that, while I agree there is a
connection between having an idea of what the program is doing "at a glance"
and gleaning information by scanning thanks to the syntax, this connection is
certainly _not_ forwarding any qualitative information about what a program is
doing. I mean, from gleaning information from syntax to understand what a code
does, nothing is passing that is remotely like 'this does that'. Syntax only
guides your eyes. Scanning only allows to locate pieces of interest. But to
know what a code does, you have to read it and there is no other way around.

And that's the very purpose of my essay. I am like you. I think I know better
what a program is doing when I have some syntax but it's only an illusion.
Syntax has absolutely no meaning in itself about what is being done. I have to
read the name of the actions and what is passed to them. And if I want to
really know what is being done, I have to read it all.

True, it's easier to read code with syntax guiding your eyes but when your
code is only 12 lines, you can just read the whole very quickly and you know
_everything_ about it, not just the pieces you have gleaned. Syntax heavy
languages make it easy to have a lot of information in a short amount of time
but they make it more difficult to get the whole picture because they just
spread code on so many lines with things less connected than in Lisp (two
problems about that: statements do not return results and ask the programmer
to do variable plumbing).

At the present time, I think it's all a matter of taste because getting to
know what is happening still requires quite some work regardless of the
language involved and the more complex what a program should perform, the more
code there will be to read.

But Lisp has the edge here I think. Note that some of the various code systems
I gave some stats about earlier are not trivial. One has two Lisp code parsers
(one of them just gives the stats I exposed, the other one identifies
dependencies): 1194 lines for 86 definitions thus a ratio of 13.88. Another
one "full view debugs" code: 659 lines for 39 definitions thus a ratio of
16.9.

Despite the goals these code systems tackle, they do not sky-rocket in their
stats; every one of them stays very reasonable. And both projects bring much
insights about the structure of the code and what is being done. Especially
the latter. Full view debugging is about computing all intermediate results
inside a given code and layout them all in the browser. It's like when one
debugs by hand except that it is all done automatically and everything is here
for you to see.

In other words, you can scan and you do not get an idea of what the program is
doing. You get what it is really doing. And because Lisp syntax is simple,
that full view debugger works on _any_ Lisp code (although of some of the most
exotic actions, it does not go into them).

~~~
sago
> Syntax only guides your eyes. Scanning only allows to locate pieces of
> interest. But to know what a code does, you have to read it and there is no
> other way around.

You could say "paragraphs and punctuation only guide your eyes, but to know
what the text says you have to read it, there's no other way around" \-
ancient greek was written without word spaces, it barely introduces any
ambiguity.

> 1194 lines for 86 definitions thus a ratio of 13.88

Just checked my current python codebase. It has 1540 loc, and 95 definitions ,
for 16.25 on your metric.

And bear in mind you can't put things all one one line in Python (i.e. it
would be trivial to write 1 loc per unit in a Lisp, but not good practice).
What would it do to your numbers if your program followed SRFI 49? Newline is
just a form of punctuation, after all.

Ultimately "no, this language is more awesomer" gets nowhere, I think. You're
clearly passionate about Lisp and think it is the best. Good for you. After
writing hundreds of thousands of loc in several languages (incl. Lisps), I'm
not so sure. Maybe I am just plain wrong. Maybe I just need to do more until I
really 'get' it. Who knows!

~~~
thomaskrauss
> You could say "paragraphs and punctuation only guide your eyes, but to know
> what the text says you have to read it, there's no other way around" \-
> ancient greek was written without word spaces, it barely introduces any
> ambiguity.

I'm not sure to understand. But I fully endorsed your paragraph statement up
to but not beyond the remark that a parenthesis is a punctuation. I was not
suggesting we don't need some kind of punctuation or blank lines in code. I
was pointing out Lisp dialects are proof you can basically code with just
three signs of punctuations: newlines, left parenthesis and right parenthesis.

Are we also clear on the fact every programmer knows how to program in Lisp,
even if they didn't even program in it? It's just like function calls, except
for the whole language. Really. There's no need to write Lisp code a lot. It
is enough to take a few steps back, consider the whole picture and see it for
what it is.

Lisp is chainable action perimeters. And that's very easy because _it is just
like function calls in C, Java, Javascript_ or many other, more mainstream
languages. If you know one of them - and I bet that's the case - then
congrats, you can program in Lisp! Whether you choose to do so or not, you're
the judge of course and either way is fine with me. But don't say reading or
understanding Lisp is hard because for that you only have to learn the
vocabulary, as is the case for every programming language.

Anyway, thank you very much for the pointer to SRFI 49! I have searched a bit
about indenting Lisp code but never found something that detailed.

I'm sorry for the absurdly fine-grain of my stats. It's just that I have my
own Lisp code parser for that and it includes inner comments and blank lines.
So it's really that precise but I was silly to recopy these numbers without
thinking about the issue.

My point was to say they are _consistently_ that low. And for some languages,
it's clearly not the case. But from the few codes of Python I have read and
given your own stats, it feels like Python is very consistent. And in my eyes
that's definitely a very good thing.

> "Ultimately "no, this language is more awesomer" gets nowhere, I think.
> You're clearly passionate about Lisp and think it is the best."

I just read again my comment and it can so be read like that... I should have
been more careful. I'm truly sorry to have almost versed into a flame debate.

But to read my comment in the direction that Lisp is more awesome or simply
the best is to amplify too much my claim which was relative to a precise
issue: the needed amount of lines of code against the complexity of the
problem. I really said nothing more than Lisp has an edge there and I think
the examples give an idea of complex problems: parsing code to get a precise
line count or to identify dependencies or to even execute automatically step-
by-step the code, these are surely complex tasks. At least it is for me and I
can't imagine coding it in other languages than Lisp. Because of their very
syntax.

~~~
sago
Thanks for the response.

> I was pointing out Lisp dialects are proof you can basically code with just
> three signs of punctuations: newlines [I think you meant whitespace
> generally], left parenthesis and right parenthesis.

I agree. In fact, with SRFI49, you can do it with just newlines and spaces. My
point is that you can write prose with just spaces, periods and capital
letters too (or less). But the use of parentheses, dashes, colons, semicolons,
question and exclamation marks, quotation marks, and ellipses, is not a bug.
See the metaphor I'm getting at?

> Are we also clear on the fact every programmer knows how to program in Lisp

Yes, if by 'program in Lisp' you mean 'program in a lisp-like syntax'.

I tend to think that syntax is a rather superficial thing, compared to
learning the model of computation and the runtime environment. Then Lisp is
quite different from C, say. A C programmer doesn't already know Lisp. One
problem I had with the OP was that: it seemed to suggest the syntax 'was'
Lisp.

I think Python in Lisp syntax would be more Python than Lisp, personally.

~~~
thomaskrauss
Okay, I understand better your point. (I have also misunderstood SRFI49 so it
didn't help!). The things you described are features, right?

But what is OP? Opening paragraph?

> compared to learning the model of computation and the runtime environment

There is indeed more important things to learn than syntax. The thing is, for
Lisp, chainable action perimeters not only covers the syntax, it also covers
the model of computation itself. The basic one at least, without macros and
any object system. Still, that basic one is quite broad.

On that question you actually anticipate another article I wanted to share:
shortcomings of instructions. It's only logical. If in Lisp dialects the atom
is the chainable action perimeter, what other languages have? The answer is
the instruction and well, I will keep that for next week but you can read it
if you want. The URL is [http://www.vagrant-
coder.com/articles/english/Shortcomings-o...](http://www.vagrant-
coder.com/articles/english/Shortcomings-of-instructions.html)

~~~
sago
> The things you described are features, right?

Right, they provide additional structure that can in turn help someone express
themselves.

But you're right, the complexity can obscure some underlying simplicity.

I suspect that the solution is to disentangle the two: to help programmers
understand the computational model independent of the language.

> it also covers the model of computation itself

eval/apply is what I'd consider the model of Lisps, rather than chainable
action perimeters. The two are linked, of course, former depending on the
latter. I guess you probably mean roughly the same thing by it, so I'm not
disagreeing, just saying what I was thinking of.

I agree, the von Neumann model of computation is not necessarily useful if
programmers believe it is the only model. But I think it is crucial for
programmers to understand.

OP = original post (i.e. the article on your site).

------
moron4hire
I would have said, "Mother flipping macros." I think, historically, it's the
closest reason to why Lisp stuck with S-Expressions, rather than continuing to
develop M-Expressions, as was originally the plan. Homoiconicity makes it
easier to develop more advanced macro facilities than in, for example, C.

Once we got to see just how powerful macro programming could be, the
S-Expression syntax was here to stay.

------
jeffreyrogers
Before I ask my question, I'm going to preface it by saying that it is not
intended as a criticism of anyone's favorite language, but something I'm
genuinely curious about. Here's the question: what substantial pieces of
software are written in a functional style (lisp or otherwise).

I'm curious because I've used functional languages in the past and even
written some fairly substantial projects in one of them (a toy compiler
written in Ocaml), however, I've never left with the impression that they are
superior to other languages. In my experience functional languages give you
some convenience with doing functional things while making lots of other
things slightly more difficult.

~~~
mhb
ITA (used by Orbitz) - Lisp

Jane Street seems to like OCaml -
[https://www.janestreet.com/technology/](https://www.janestreet.com/technology/)

------
javajosh
Good piece. There's an even deeper truth about applications - that they are
defined by a relatively small set of top level function evaluations, called
asynchronously. If you're into pure functions, you can manage all mutable
state in one place.

Much of the incidental complexity of real software comes from misunderstanding
this, just as much of the _real_ complexity comes from the problem of
maintaining a big, distributed, mutable state.

------
cgag
"code is data" is the traditional incantation

~~~
baddox
And you don't even need three words, just "homoiconicity."

~~~
smacktoward
There is definitely something quite Lispy about responding to the question
"What is Lisp?" with the word "homoiconicity" and then waiting for the person
who asked to figure out what that actually means.

------
devsaysstuff
Lisp in 3 words - Too Many Brackets! Tomorrow Discussing Ruby - method
missing, or missing method? Stay tuned for our weekly newsletter - Java and GC
- if it really worked, it would collect and delete the whole JVM!

~~~
thomaskrauss
Indeed, Lisp has too many brackets!

However, how many different roles do they have apart from writing action
perimeters?

The answer is 0!

And 0 times 10, or 100, or 1000 or well, just go for any number, it doesn't
matter, that's still 0.

Also, note that Lisp has only parentheses. While in the end, it is a matter of
taste, I don't think one can disagree on the fact Lisp only has parentheses
and they serve only one purpose.

Other languages have in fact many roles for parentheses while also having
brackets and many roles for them while also having curly braces and many roles
for them.

------
nutate
wait, parameter, perimeter

------
jaywunder
Just a question, does he mean "parameters" instead of "perimeters"?

~~~
thomaskrauss
I really mean perimeters.

An action _perimeter_ returns a value. To perform its work, it needs
parameters. That is: values.

Some of these values can be written by hand, others need to be computed. In
that latter case, you ask for a computation by writing an action perimeter.

And there's no need for a special syntax to use the value that results in
executing that perimeter. You just write it in the appropriate place, as a
parameter.

So in practice, you can chain perimeters with one another. Until you have
expressed all the computations you wanted the computer to do.

~~~
nutate
According to google you just made that up? I only see action perimeter in
reference to expanding the perimeter of action of the coast guard in Canada.
So like... how is an "action perimeter" different than a function? In which
case you get the more succinct two words "chainable functions."

After looking at the French version I see that "action perimeter" is from the
french perimeter d'action (accents removed) which translates better in english
(once again according to the interwebs) as: sphere of operations.
[http://dictionary.reverso.net/french-
english/p%C3%A9rim%C3%A...](http://dictionary.reverso.net/french-
english/p%C3%A9rim%C3%A8tre%20d%27action)

Once again, I'd go so far as saying the concept of functions works just as
well here, but at least it gets over the near homonym of parameter/perimeter.
The chaining of scoped actions is pretty vital to lisp, and I suppose
functional programming in general.

~~~
thomaskrauss
I haven't read the notion of action perimeter phrased anywhere else. I just
came up with it some years ago when I was trying my colleagues to give Lisp a
go.

An action perimeter is different from a function because, for instance, you
can write (if <test> <then-clause> <else-clause>).

For a function, all its arguments are evaluated first and then it is applied.
That's certainly not the case for _if_ since the whole point of a condition is
to refrain from evaluating some code unless a condition is met.

Hence, in Lisp, the simple notation encompasses and is fully operative on
every action, including the ones that do not behave like functions. While in
many language chaining perimeters is only about function calls. And in
addition it is rarely idiomatic to chain function calls in such language.

Thank you for pointing out the similarity between parameter and perimeter
which borders on confusion. Thanks to everyone who brought it up to!

It's clear that's an issue I overlooked. The reason is I use the term
_argument_ in English and in French, never parameter itself. But that's
probably because once I realized the notion of a perimeter is important in
Lisp, I stopped using the word 'parameter'.

Sorry for that! I'll try to find a better term.

------
dschiptsov
Oh, I too have a few words about what a Lisp is.

Remember that DNA structure - an aminoacid in the CAR and the next CONS in
CDR?)

Lets say that it is not a coincidence, given that the DNA structure was a host
topic these days.)

Guess where the Actor Model came from?)

