
Why Racket? Why Lisp? - Tomte
http://practicaltypography.com/why-racket-why-lisp.html
======
reikonomusha
I dislike this notion that Lisp (or Haskell or OCaml or ...) owe it to
everyone else to explain and enunciate why it can be more productive to use
Lisp.

""" That’s ask­ing too much. If Lisp lan­guages are so great, then it should
be pos­si­ble to sum­ma­rize their ben­e­fits in con­cise, prac­ti­cal terms.
If Lisp ad­vo­cates refuse to do this, then we shouldn’t be sur­prised when
these lan­guages re­main stuck near the bot­tom of the charts. """

What?? Why? The problem is not and has never been communication of Lisp
features. No one made a concise list of why C and Java are so great that
people rushed to use them. Instead, they were pervasively used and taught in
universities, and they are pervasively used in the development of most
applications for e.g. Windows and Linux, and they are relatively simple
languages (in theory) whose semantics most people "get". No wacko high order
crap, no weight curried things, no arrows or morphisms or monads or macros.

Programmers of such languages don't owe the rest of the world anything.
Everyone has a choice about what to use, and it's each individual programmer's
responsibility to choose them wisely. There is plenty of material about Lisp
and Scheme out there. Unfortunately, we are in this TL;DR culture where no one
has the time to spend a few hours every week to learn something new, since
somehow that's too big a risk on their precious time.

Now, for some comments:

1\. Everything is an expression.

He says this is a boon, but it's also confusing for "expressions" which are
side effectful. Too bad he did not talk about that, nor did he talk about how
the expression-oriented way of thinking is really best for purely functional
languages that allow for substitution semantics.

2\. Every ex­pres­sion is ei­ther a sin­gle value or a list.

This is wrong, unless we devolve "single value" into the 1950's idea of an
"atom". What about vectors or other literal composite representations of
things? What about read-time things that aren't really lists or values?

3\. Functional programming.

Functional programming is indeed great, but why don't we talk about how in
Lisps, we don't get efficient functional programming? Lisp has tended to
prefer non-functional ways of doing things because Lisp will allocate so much
memory during functional programming tasks that for many objectives, FP is far
to inefficient. Haskell solves this to some extent with things like efficient
persistent structures and compilation algorithms such as loop fusion. Lisp
doesn't really have any of this, and the data structures that do exist, many
people don't know about or use.

4 and 5 don't really have to do with Lisp but particular implementations.
That's fine I guess.

6\. X-pressions.

What the hell is an X-pression?

7\. Racket documentation tools.

Okay.

8\. Syntax transformations.

He made the same mistake as he so baroquely outlined at the start. What in the
world are these "macros" and "syntax transformations" good for? You're just
telling me they're more powerful C preprocessor macros that can call arbitrary
functions. But I was taught that fancy CPP code is a Bad Idea, so boosting
them is a Worse Idea.

9\. New languages.

Same problem as 8. You say it's useful but you don't say why. Just that it's
"easier".

10\. Opportunities to participate.

Nothing to do with Lisp again.

* * *

Instead of all this glorifying of Lisp and etc, why don't we spend time
increasing that library count from 2727 to 2728? Or do we need to go through
an entire exercise about whether that time spent is worth it or not?

""" Rather, you are—be­cause a Lisp lan­guage of­fers you the chance to
dis­cover your po­ten­tial as a pro­gram­mer and a thinker, and thereby raise
your ex­pec­ta­tions for what you can accomplish. """

You're repeating everyone else. Notice how difficult it is to convey such
things without being hugely abstract and unhelpful? Why don't other
programmers see this huge productivity benefit from these Lisp wizards in
their day-to-day life? Where are the huge, useful applications? They all seem
to be written in C or C++.

""" It’s mind-bend­ingly great, and ac­ces­si­ble to any­one with a mild
cu­rios­ity about soft­ware. """

It is accessible to those who are intently curious about theoretical aspects
of software development, especially abstraction, and who can take exercises
which require mathematical reasoning. A "mild curiosity" in my experience with
others will _not_ suffice.

* * *

This post may sound somewhat cynical and negative, but Lisp enlightenment
articles are almost as bad as Haskell monad tutorials. They're everywhere and
by the end, still no one gets it. And I don't like the attitude that because a
group G doesn't understand it, and group H does, that H owes it to G to
spoonfeed the information. That's not the case.

~~~
yayitswei
It benefits both groups to to enlighten G. Since G is so much larger, that's
how we would increase the library count from 2727 to 27280.

~~~
reikonomusha
The best way to demonstrate it is to write interesting software, not to
flounder on some abstract explanation about the greatness of G's favorite
language.

~~~
mschaef
The original author of the blog post _did_ write some interesting software in
Lisp, used it to write a book, and then he wrote his blog post.

To me this is a good example of something languages have to have to make
progress: users and evangelists/educators, with a large overlap between the
two.

------
aaronbrethorst
From what I've seen out of the Clojure community over the past few years, it
seems like they're far more likely (and able) to offer up concrete examples of
how Clojure makes their businesses and products successful in a way that an
imperative language could not. So, yay Clojure community, and boo on hand-wavy
Lisp people.

e.g.:

[http://www.kreuzwerker.de/en/blog/posts/why-clojure-
rocks-2/](http://www.kreuzwerker.de/en/blog/posts/why-clojure-rocks-2/)

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

~~~
pron
> ... in a way that an imperative language could not

Perhaps a nitpick, but sometimes nomenclature is important. Clojure (like all
Lisps) _is_ an imperative programming language. "Imperative" languages are
contrasted with "declarative" languages[1]. Where does _functional_ fit in and
what is the name for "non-functional"? Well, that's not clear, as "functional"
(in the PL sense) doesn't even have an agreed upon definition. Is Clojure
"functional", then? Well, it's certainly not pure like Haskell is (and it has
explicit loops etc.), but it does encourage more uses of function composition
than, say, Java, it's _more_ declarative, and it also isn't object-oriented,
but that doesn't make it not imperative. Actually, I think even Haskell still
qualifies as imperative.

But Clojure can certainly be contrasted with OO and procedural languages (even
though at least one of its core abstractions -- protocols -- is borrowed from
OO).

[1]:
[http://en.wikipedia.org/wiki/Imperative_programming](http://en.wikipedia.org/wiki/Imperative_programming)

~~~
LesZedCB
>Clojure (like all Lisps) is an imperative programming language. "Imperative"
languages are contrasted with "declarative" languages.

Wikipedia, and probably everybody, defines truly functional programming
languages (which includes Clojure and the other Lisps) to be declarative, not
imperative. [1]

[1]
[http://en.wikipedia.org/wiki/Declarative_programming](http://en.wikipedia.org/wiki/Declarative_programming)

~~~
mrottenkolber
> truly functional programming languages (which includes Clojure and the other
> Lisps)

This is wrong. I don't know how to say this... Lisps do usually support
functional programming paradigms, but most Lisps are indeed anything but
functional (in the ML sense).

~~~
dragonwriter
Lisp was considered a functional programming language before ML existed. Lisps
generally don't have as strong and exclusive support for the functional
paradigm as some newer languages (and pretty much anything else still in use
is newer than lisp), but then C++ is known as an OOPL despite having less
strong and exclusive support for the OO paradigm than many _older_ languages,
so there's that.

~~~
bitwize
_Lisp was considered a functional programming language before ML existed._

That was then and this is now. Today, functional programming means side-
effect-free with a strong type system, and efficient use of higher-order
abstractions over functions, including things like typeclasses to define
entire morphisms given a few functions which establish relationships between
objects. Lisp doesn't really support this effectively. Arguably, with concepts
C++14 is more functional than Lisp.

~~~
dragonwriter
> Today, functional programming means side-effect-free with a strong type
> system

Functional programming has always meant the _style_ or _paradigm_ of
programming that prefers side-effect-free declarative code that can be
modelled in the substitution model; type systems have always been (and remain)
orthogonal concerns. A functional language is one that supports the functional
paradigm, but it has never been most commonly used for languages that
_exclusively_ support that paradigm. Pure functional code is the term that has
been used for code that is exclusively in that style, and pure functional
language is the term that is generally used for a language that has exclusive
support for that style.

------
na85
I sure hope the giant, hideous, obtrusive diamonds inserted into the text to
denote a hyperlink doesn't catch on as a trend. It's a great way to break the
flow of the text and irritate your readers.

As for the idea of Lisps, well, it sure seems neat. But I've literally never
run across a situation where I needed my code to edit itself. I've never run
across a situation where the lack of an everything-is-an-expression-is-a-list
feature prevented me from doing what I wanted to do.

So I just don't really feel the need to get repetitive strain injuries in my
pinky from reaching for the parentheses all the time.

~~~
cespare
As someone who writes Lisp (well, Clojure) every day and does not particularly
enjoy it, I find the common complaint about parentheses to be a non-issue.

In fact, I'm not sure I've heard of anyone who wrote any significant amount of
lisp code and came away talking about parentheses. This seems to be mostly a
reaction from people who've read a bit of Lisp without using it.

Then again, I just noticed that I type ( and ) with my third and fourth
fingers, so maybe it would be worse if I typed properly :)

~~~
jsmeaton
I would assume it'd be the same as people complaining about significant
whitespace in python. No one who actually programs in python complains about
the whitespace.

~~~
jahnu
I find it a pain and error prone when having to change indentation in python
code. E.g. when adding an 'if' in front of a block of code. So easy to miss a
line or mess up the indentation in the block itself and then you might not
spot an error until run time.

~~~
djur
I was under the impression that Python emits an error about inconsistent
indentation at compile time (the initial parsing and interpretation of a
script file), not runtime (+x time units later, after the program has
started). Is that incorrect?

~~~
jahnu
I'm talking about something like this..

    
    
        def foo():
            do_this()
            and_this()
        

later I change it..

    
    
        def foo():
            if something():
                do_this()
            and_this()
    
    

oops... and_this() should have been in the if block and I won't find out till
I run it.

(imagine a much bigger more complex example of the above function)

In large pieces of code this can be easy do. If you are forced to use
parenthesis it's much more difficult to make this error. One could argue that
experience prevents you from doing this but I have sadly found this not to be
the case in practice.

~~~
lutusp
> If you are forced to use parenthesis it's much more difficult to make this
> error.

By "parentheses" you mean delimiters, which create visible boundaries to
defined areas in code. Parentheses are an example of delimiters, but not all
delimiters are parentheses.

Bash has if ... then ... else ... fi

Ruby has if ... else ... end

C/C++/Java have (logical test) { controlled area }, nested to any practical
depth.

And so forth. Python doesn't.

> One could argue that experience prevents you from doing this but I have
> sadly found this not to be the case in practice.

This is an argument against complex functions that do a lot, as opposed to
breaking program logic up into smaller blocks that are easier to understand
and control. The old argument against this practice was that a large function
that did everything was faster than the same logic broken into smaller blocks.
A modern compiler will generally prevent this from happening.

~~~
jahnu
Well I used the word parenthesis since the topic was Lisp.

> This is an argument against complex functions that do a lot

Functions large and complex enough to make this problem significant seem to be
the reality I have to deal with when programming in the large. It's only my
opinion but a language feature that improves my real world experience at no
cost is a bonus.

------
jimbokun
If you took a Common Lisp programmer from the early to mid 90s in a time
machine to today, very little about current programming languages would seem
novel or an advance over what he or she was using then.

I think this is a reason for much of the smugness of Lisp programmers.
Whatever features you think are new or cool or advanced about your programming
language, Lisp probably got there first.

~~~
lmm
Nonsense. We've figured out how to do type systems. We can even fully infer
types if you're willing to accept some quite reasonable restrictions on how
polymorphic your code is. We have a bunch of reasonable approaches to effect
tracking, which Lisp folk used to have to do by hand (that story about the T
garbage collector sounds like the most unmaintainable piece of code I've ever
heard of). We know how to solve the expression problem.

Modern "pragmatic"-oriented languages have little that wasn't in Lisp - or in
Algol. Which is fine! The innovation is about the wider ecosystem (a lisp
programmer from the '90s would be amazed by CPAN, never mind maven), or about
making common tasks easy (a lisp programmer might eventually put together a
collection of idiosyncratic macros with much of the functionality of Rails,
but that wouldn't be a project you could hire someone else to maintain). OTOH
modern "researchey" languages, like Coq or even Haskell, are far far ahead of
Lisp.

~~~
progman
> OTOH modern "researchey" languages, like Coq or even Haskell, are far far
> ahead of Lisp.

I know Common Lisp well, and I honestly tried to learn and to use Haskell. I
realized that Haskell has the advantage of a strong type system but it seems
only to be useful for language research (compiler writing) and mathematical
applications. Haskell is (in my case) almost useless for every day real world
applications. It is a very good choice if I know the algorithm and data
structures exactly in advance. But real world applications often require
changes which are not predictable. It is a pain to align a whole Haskell
project according to new requirements to make the whole system work again. It
takes far too much time, and I wonder where the benefits are if other weaker
typed languages can do the same job as well, or even better.

In the Lisp world I can develop prototypes very quickly. And if I need a
strong type system as in Haskell then I can use Shen (shenlanguage.org) which
has a strong rule based type system on top of Lisp. That means that I can use
both worlds -- the default dynamic system of Lisp, and the strong type system
of Shen.

Lisp is still very powerful and yet small in comparison to the huge LLVM
system of Haskell. It can be used on embedded systems (ECL for instance) which
Haskell is not able to do (AFAIK).

I don't know what you exactly mean with "tracking". If that means tracing then
Lisp even offers backtracking (debugging back in time), and I think almost
every Lisp programmer knows Slime.

So the claim that Haskell is "far far ahead" of Lisp is not true at all. The
only real weak point of Lisp is a good GUI library. I wish there were strong
support of Qt and HTML5.

Another favorite language of me is Nimrod because it joins the best of several
languages (Python, Perl, Lisp and C) together.

~~~
rrradical
> It is a pain to align a whole Haskell project according to new requirements
> to make the whole system work again.

I'll quote a recent tweet by Chris Done: "I feel like 80% of Haskell advocacy
should involve screencasts of people refactoring large codebases."

In my experience, refactoring is easier with a strongly typed compiler, not
harder. It may take more time and work to get your program to "run" again, but
the end result will be more likely correct, and more likely to be a better
design.

~~~
klibertp
There are other ways of making refactoring easy. I'm not trying to dismiss a
powerful type system - which is a great help indeed - but pervasive unit tests
and contracts work as well. Linters are a nice addition, and even gradual
typing like in Erlang with Dialyzer is much better than nothing. The point
being: problems solved by type systems are being solved with other tools, too.
I don't want to argue about _how well_ these tools work, because all of them
(including static type systems) have relative strengths and weaknesses; it's
just unfair to present refactorings or correctness guarantees as benefits
reserved for type systems alone.

~~~
codygman
I'd argue that you can rely more on powerful types because they lend more to
the totality of your program. This is just a hunch/intuition though. If I'm
wrong, I'd be glad to know why and how so I can correct that ;)

------
mrottenkolber
Can not resist...

This article is fairly misguided. I find it painful that everybody who writes
about a Lisp offshoot (Scheme, Clojure, ...) ends up misrepresenting Common
Lisp.

To sum up "Why Lisp?" from a CL perspective: CL has pretty much every feature
of every programming language around, only that its better designed,
implemented and generally more powerful. It's just a poweruser language. Its
not just macros, sexps and lambdas. Its also number types, arrays, OOP,
symbols, strings, structs, dynamic/lexical variables, lambda lists, multiple
return values, on-line disassemble, exceptions, restarts, MOP, metacircular
definition, great implementations, great libraries...... the list goes on and
on... I surely forgot a ton of great stuff. TL;DR: CL got everything. And this
"everything" is designed so well that its extensible and no CL programmer ever
needs to doubt that any new feature can be implemented easily in CL.

To correct a few of the wrong statements of OP:

> “Wait—I love state and data mu­ta­tion. Why would you take them away?”
> Be­cause they’re false friends.

CL is NOT particularily functional. Just because we know how to write good
side-effect free code, doesn't mean its a functional language. (We jave SETF
after all, failed to mention that aove).

> a syn­tax trans­for­ma­tion in Racket can be far more so­phis­ti­cated than
> the usual Com­mon Lisp macro.

Outright wrong. The only reason Scheme has weird macro systems is because its
a Lisp 1. CL is designed well (thus being a Lisp 2), and thats why its simple
but ultimately more powerful macro system can work.

> A macro in Com­mon Lisp is a func­tion that runs at com­pile-time,
> ac­cept­ing sym­bols as in­put and in­ject­ing them into a tem­plate to
> pro­duce new code.

This is so wrong I had to write this comment. A macro in Common Lisp is a
COMPILER, it accepts arguments and returns an SEXP. It is infinitely powerful,
it can do EVERYTHING.

~~~
hvs
I would take issue with the OOP in CL being better implemented than other
languages. Don't get me wrong, the Metaobject Protocol is a feat of modern
engineering, but the actual result is an OOP that feels tacked on after the
fact. CLOS is very powerful, but when it comes to OOP, other languages are
syntactically cleaner in their implementations.

Also, it's a bigger debate, but the lack of hygenic macros in CL is often seen
as a negative. Again, this is a larger debate, but certainly a case can be
made that CL doesn't have everything designed so well.

I love CL, but it's helpful to remember its limitations.

~~~
mrottenkolber
> syntactically cleaner in their implementations.

Listen to yourself please.

> lack of hygenic macros in CL

Which lack? CL macros are usually very hygienic, being a Lisp-2 and all,
having GENSYM.

> I love CL, but it's helpful to remember its limitations.

What limitations? Not having syntactical things you seem to like and
supporting non-hygienic macros are not limitations. Quite on the opposite, I
believe these are features.

------
cturner
The top reason here could been written - lisp is more expressive. You can find
ways to express an idea that make sense now, and which are readable. Macros is
a different part of the same idea.

\--

Maybe I'm doing it wrong, but a problem I've had with racket is as you begin
to build larger projects, when something breaks it can be quite difficult to
find out exactly where the break happened. When you compile Java or run
Python, it's almost always immediately obvious what broke.

The way I got around this was to use a methodical TDD approach. Would be a
shame if that turns out to be as good as it gets for lisp.

Something I haven't done yet but am interested to get to is attaching a repl
console to a running process.

~~~
calibraxis
Yes, that is very important. When I watch experienced programmers learn Lisp,
they write a couple functions, then go through the pain of debugging that.

They should unlearn that. And put tiny fragments in the REPL. (Or whatever
interactive tool you have.) Playing with it.

~~~
cturner
Since lisp is homoiconic (refreshed on this, see downvotes below) it would be
nice if you could type things into a repl and then run a function like this:
(persist function-i-just-wrote). And then it would save to a text file. Then
you wouldn't need to stuff around with the mouse copying from one buffer to
another and the like.

(I expect something similar is possible in emacs, but emacs is not my thing.)

Hmm. I suppose I could just write the persist function myself. Watch this
space.

~~~
dedward
What you just described is pretty much universally handled by editor
integration.... I can't imagine anyone actually develops lisp without this.

The editor is hooked directly up to a running image.. a keypress (or two)
causes an expression to be executed in the running image... you can flip to
the REPL and goof around directly and/or at the same time work from one or
more editor buffers and selectively execute code as you desire. You can bust
into the debugger whenever you feel like it, etc etc.

Someone else described it better above I think - but this image-based
interaction is one of the most attractive things for many - it goes well
beyond just having a REPL where you can evaluate code... lisp was basically
designed around the idea of interactive development.

If you think this through to a large, complex project - you can have a giant
running application, working in production, and still attach to it with an
editor/environment and debug it live... that's hard to do with anything else.

------
_delirium
The manual to this publishing system, discussing how its markup/programming
language is implemented as a custom Racket language, is pretty interesting:
[http://mbutterick.github.io/pollen/doc/](http://mbutterick.github.io/pollen/doc/)

------
bad_login
It seems most people here have never used (and not tried) racket.

I decided to use racket for my little sides projects, as replacement for scala
and clojure.

I choose it because it was clear for me i can't stand limitations other
language impose to me in way of style and boilerplate, the racket macro (aka
syntax transformer) system is the most advanced i know to reduce the
boilerplate to a minimum and so just write what i want to express. In facts i
rarely write macro because writing a good macro demand you take care of errors
syntax, i am lazy in the bad meaning of the term.

I choose it because it's dynamic typed and i get more convinced that type go
on your way most of the time (expect complex algorithms)(i write little
projects, so refactoring argument is out). It enable me to write code and eval
it on the fly with geiser (using enter! on the back), after eval the new
function i test it in the repl, hack until the function meet the requirement
copy paste from repl and boom i get a unit test. Because it as eval and it
will become handy one time in your programmer life for sure.

I choose it because of it's sexpr syntax, as a heavy user of emacs i know that
other syntax is a pity.

Also because it has (and i use):

1\. llar parser (implemented through a macro).

2\. A pattern matching nothing to envy scala or clojure deconstructs.

3\. An optional type system.

4\. A contract system.

What i find hard as a new comer (to racket, not as a programmer already now
scala, clojure, half of c++ :), php) is

1\. The broadness of the features the language offer, which feature to use
e.g.: class or generics.

2\. The documentation is rich but lack of examples for the common cases, so
you need to read the doc of the function (sometime it's huge).

3\. Understanding how racket module works is quite hard and you have the
documentation, if you don't plan to play with the macro expander (the stuff
that run your macro) and some dynamic features you don't really need to.

4\. You need to 'register' the errortrace library if you want a stacktrace,
quite a surprising behaviours for me.

My opinionated conclusion:

Racket is the best language design i ever see, it's hard to learn but make you
feel learning an other language will just become to learn a new sub-optimal
syntax. Sadly the ecosystem is lacking libraries and peoples and i am not
helping in this way.

~~~
MrBuddyCasino
Ah, someone with Clojure experience. I wanted Clojure to be my next language
to learn, so now I'm curious why you ditched it in favor of Racket?

Especially:

\- Whats the concurrency story for Racket?

\- If I wanted to code my REST endpoints in Racket, are there competitive
libraries available?

~~~
logicchains
Regarding the Racket concurrency story, it has places; [http://docs.racket-
lang.org/reference/places.html](http://docs.racket-
lang.org/reference/places.html).

"A place is a parallel task that is effectively a separate instance of the
Racket virtual machine. Places communicate through place channels, which are
endpoints for a two-way buffered communication."

So places are somewhat like Erlang processes.

Distributed Places are also interesting: [http://docs.racket-
lang.org/distributed-places/index.html](http://docs.racket-
lang.org/distributed-places/index.html)

~~~
seabee
Places are about parallelism. For concurrency specifically, the most
interesting features are threads, channels, and futures and can all be found
here: [http://docs.racket-
lang.org/reference/concurrency.html](http://docs.racket-
lang.org/reference/concurrency.html)

Distributed places is pretty cool, however!

~~~
MrBuddyCasino
Thanks. So basically we get most of what Java has to offer plus thread
mailboxes, which is nice. Not sure what to make of Places though - zeroMQ
exists and has Racket bindings, is there something Places is better at?

------
wes-exp
Author is wrong about hygienic macros – they are not more powerful. They are
less powerful, and more complicated, in order to enforce safety. Whether this
is preferable or not is a matter of debate.

~~~
samth
No, the article is correct. Hygienic macros give you strictly more information
to work with, enabling them to be more expressive. It's possible to implement
unhygienic macros, either at an individual macro level or a whole new macro
syso, using Racket's macro system.

~~~
wes-exp
I'm thinking you're right in the theoretical sense, but I'm right in the
practical sense. Every time I've looked at hygienic macro systems, it just
seems like now I'm jumping through extra hoops to overcome a more restrictive
way of doing things. Is that extra information you cite typically useful for
anything besides safety? Can you give an example?

~~~
samth
Yes, the information is useful for lots of things. For example, tracking the
binding information in the data is how DrRacket manages renaming, how Scribble
(the Racket docs tool) hyperlinks every identifier in every example to the
correct documentation for the identifier, how Typed Racket tracks type
metadata for identifiers, ...

------
agentultra
Some practical features I enjoy in CL:

1\. _Conditions and restarts_ : As far as error handling in programs go this
is the most rock-solid system I've encountered. You can tell the system which
bits of code, called restarts, are able to handle a given error condition in
your code. The nice thing about that is you can choose the appropriate restart
based on what you know at a higher-level in the program _and continue_ that
computation without losing state and restarting from the beginning. This plays
well with well structured programs because the rest of your system can
continue running. Watching for conditions and signalling errors to invoke
restarts... it's really much better than just returning an integer.

As a CL programmer using SLIME or any suitable IDE, this error system can
throw up a list of _appropriate_ restarts to handle an error it encounters. I
can just choose one... or I can zoom through the backtrace, inspect objects,
change values in instance slots, recompile code to fix the bug, and choose the
"continue" restart... voila the computation continues, my system never stopped
doing all of the other tasks it was in the middle of doing, and my original
error was fixed and I didn't lose anything. That is really one of my favorite
features.

2\. CLOS -- it's CL's OO system. Completely optional. But it's very, very
powerful. The notion of "class" is very different than the C++ sense of
struct-with-vtable-to-function-pointers-with-implicit-reference-to-this.
Specifically I enjoy parametric dispatch to generic functions. C++ has this
but only to the implicit first argument, _this_. Whereas CLOS allows me to
dispatch based on the types of all of the arguments. As a benign example:

    
    
        (defclass animal () ())
        (defclass dog (animal) ())
    
        (defgeneric make-sound (animal))
        (defmethod make-sound ((animal animal))
          (format t "..."))
        (defmethod make-sound ((dog dog))
          (format t "Bark!"))
    
        (make-sound (make-instance 'animal))
        (make-sound (make-instance 'dog))
    

Will print "..." and "Bark!" But the trivial example doesn't show that I can
dispatch based on all of the arguments to a method:

    
    
        (defclass entity () ()) ;; some high-level data about entities in a video game
        (defclass ship (entity) ()) ;; some ship-specific stuff... you get the idea.
        (defclass bullet (entity) ())
    
        ;; ... more code
    
        (defmethod collide ((player ship) (bullet bullet))) ;; some collision-handling code for those types of entities...
        (defmethod collide ((player ship) (enemy ship))) ;;; and so on...
    

Conversely...

    
    
        Ship::collide(const Bullet& bullet) {}
        Ship::collide(const Ship& ship) {}
    

Where collide is a virtual function of the Entity class requiring all sub-
classes to implement it. In the CLOS system a method is free from the
association to a class and is only implemented for anyone who cares about
colliding with other things.

The super-powerful thing about this though is that... I can redefine the class
while the program is running. I can compile a new definition and _all_ of the
live instances in my running program will be updated. I don't have to stop my
game. If I encounter an error in my collision code I can inspect the objects
in the stack trace, recompile the new method, and continue without stopping.

3\. Macros are awesome. They're like little mini-compilers and their
usefulness is difficult to appreciate but beautiful to behold. For a good
example look at [0] where baggers has implemented a Lisp-like language that
actually compiles to an OpenGL shader program. Or read Let Over Lambda.

One of the most common complaint I hear about macros (and programmable
programming languages in general) is that it opens the gate for every
developer to build their own personal fiefdom and isolate themselves from
other developers: ie -- create their own language that nobody else
understands.

Examples like baggers' shader language demonstrate that it's not about
creating a cambrian explosion of incompatible DSLs... it's about taming
complexity; taking complex ideas and turning them into smaller, embedded
programs. A CL programmer isn't satisfied writing their game in one language
and then writing their shaders in another language. And then having to learn a
third language for hooking them all up and running them. They embody those
things using CL itself and leverage the powerful compiler under the
floorboards that's right at their finger tips.

Need to read an alternate syntax from a language that died out decades ago but
left no open source compilers about? Write a reader-macro that transforms it
into lisp. Write a runtime in lisp to execute it. I've done it for little toy
assemblers. It's lots of fun.

... this has turned into a long post. Sorry. I just miss some of the awesome
features CL has when I work in other languages which is most of the time.

[0]
[https://www.youtube.com/watch?v=2Z4GfOUWEuA&list=PL2VAYZE_4w...](https://www.youtube.com/watch?v=2Z4GfOUWEuA&list=PL2VAYZE_4wRKKr5pJzfYD1w4tKCXARs5y)

~~~
dllthomas
_" CLOS allows me to dispatch based on the types of all of the arguments."_

But can it dispatch based on the return value?

~~~
juliangamble
This is an example of dispatching on return type in Clojure - which is similar
to Common Lisp.

[http://stackoverflow.com/questions/22740178/clojure-
dispatch...](http://stackoverflow.com/questions/22740178/clojure-dispatch-on-
return-type-as-expressive-as-haskell-typeclasses)

(The Haskell purists point out that the dispatch isn't determined at compile
time - form your own opinion about whether they have a point).

~~~
kenko
I'm not a Haskell purist, but this isn't really dispatch on return type, this
is manual inspection of manually provided metadata that just happens, in this
case, to be (intended to be) a return type.

The return type isn't enforced, incidentally:

    
    
        user> (defn ^String my-function [^Integer foo] (apply concat (repeat foo "x")))
        #'user/my-function
        user> (my-function 3)
        (\x \x \x)
    

Whoops, I meant (apply str ...).

You also can't use the metadata on a function introduced by (defn ^ReturnType
...) in more or less any useful way, if you don't have a reference to the var
itself. If you pass it to a function, you basically can't recover it:

    
    
        user> (defn do-something-interesting-with-return-type [f] (println "here's my metadata:" (meta f)))
        #'user/do-something-interesting-with-return-type
        user> (do-something-interesting-with-return-type my-function)
        here's my metadata: nil
        nil
    

Gone!

You can tell that something fishy is going on in the SO answer because the
author has to pass in the function by name, #'return-string.

------
ColinDabritz
A good list of some interesting 'day to day' benefits of Lisp. Maybe that is
something that would appeal to beginners especially.

From my perspective Lisp is a powerful language because of its genesis in
research. The question wasn't "How do we make a tool to make this hardware do
what want?" but rather for a research goal.

If you want to read the actual original Lisp paper look up: Recursive
Functions of Symbolic Expressions and Their Computation by Machine, Part I
John McCarthy April 1960

Paul Graham covers it nicely in this essay, especially the "What made Lisp
different" list about 1/3 in
[http://www.paulgraham.com/icad.html](http://www.paulgraham.com/icad.html)

Lisp has had expressiveness we're only recently seeing in popular mainstream
languages now. It has to do with the design, the simplicity, and how Lisp
expresses problems. I've often heard it described as "the language gets out of
your way." That's why Lisp.

~~~
smeyer
Thanks for the link (it's one of PG's I hadn't read yet.) That being said, I
really didn't like the part where he implied that if 1 line of Lisp can
replace 20 lines of C that it also means that a feature can be developed 20
times faster in Lisp than C. Are you a Lisp programmer? I've only used it a
bit, but I didn't get the impression things would scale that way for feature
development.

~~~
ColinDabritz
Interesting point. Particularly I believe that the 'coding' part isn't the
real job, I'm not just an overpaid typist. So why is concise expression good?

For the record, I am NOT a day-to-day Lisp programmer, but I've played with it
a little and read about it some.

I think it's because its about expressing your problem clearly. It's not "20
times less lines" so much as it is "20 times clearer expression". Not that
it's exactly 20x, but it seems better. When you express things more clearly,
and structure your code more like your problem, and less like your programming
language, you shed a lot of accidental complexity ( See Out of the Tarpit -
[http://shaffner.us/cs/papers/tarpit.pdf](http://shaffner.us/cs/papers/tarpit.pdf)
), so managing the complexity of your project is easier, which means fixing
bugs and adding new features is also easier. I think this is the route being
implied when they say you can develop features faster. I'm not so certain
you'd see the benefit in a particular feature, but over time.

Note that a lot of the modern languages are picking up many of these
expressive features, closing the gap there as well, which is wonderful.

------
DCKing
Why Lisp? That is understood.

Why Racket? From an ignorant outsider's perspective, all Lisps seem to be more
or less interchangeable when it comes to the language. They only differ in the
details, and each seems to be about as difficult to learn as the other.
Although this article does make somewhat of a case for specifically Racket, it
seems to be a rather weak one - tools are nice and some language details are
nice. But the same general arguments can be made for other Lisps, most notably
Clojure. It seems to me that Clojure is a lot more practical: it has many good
libraries in both Clojure and Java, it has some great tools, there's a lot of
momentum, and it can be deployed everywhere (including the browser).

So, being an ignorant outsider, is there any reason the Lisp I should learn
_isn 't_ Clojure?

~~~
klibertp
> all Lisps seem to be more or less interchangeable when it comes to the
> language

Definitely not true.

It may be true to an extent for implementations of one particular lisp, like
Common Lisp or Scheme, but even then there are very real, and significant
differences. Simple and regular syntax makes it actually much easier to build
many different semantics, and that's what lisps are about.

Racket has less libraries than Clojure and no access to JVM ecosystem. On the
other hand it's FFI capabilities to C are very nice and easy to use. Racket
macro system - syntax-parse (with syntax-rules and syntax-case and... defmacro
for simpler cases) - is the most powerful there is right now. Combined with
access to the reader and ability to make reader macros this makes Racket much
easier to extend and transform than Clojure (by design). Which takes us to the
biggest advantage of Racket, which is it's actually a family of languages,
both s-exp based and with traditional syntax, built for specific purposes,
which you can mix and match easily. Typed Racket and lazy variant, and FrTime,
and Datalog - and more - are examples of this. Then you have module system
which is a game changer for unit-testing, object system which is more powerful
than most (besides CLOS, but there's always Swindle), the most advanced
contracts system among all PLs, and of course quite fast JIT compiler and many
more.

Clojure is simpler than Racket, but provides a set of highly opinionated
defaults which people are comfortable with. I think Clojure and Racket are
like Sublime Text and Emacs - Emacs _is_ strictly more powerful, but it
requires much more work to use this power well, while Sublime works well from
the get go. But in the end both are infinitely better than Notepad and sooner
or later you will come to know both, which is what I suggest you should do.

~~~
DCKing
Thanks for the clarification. Is it worth considering others besides Racket
and Clojure as a first Lisp? Are there Lisp equivalents of Vim and Atom as
well?

~~~
eudox
Yes, Common Lisp. Gradually-typed, fast, compiled, standarized, stable, and
with multiple mature implementations.

------
michaelsbradley
RacketCon is being held in Saint Louis, Missouri, USA the day following the
Strange Loop 2014 conference (also in Saint Louis):

[http://con.racket-lang.org/](http://con.racket-lang.org/)

I hope to see some of you there!

------
kazinator
Check it out. For five years I have been developing a tool called TXR. It's a
"Unixy" data munging language that is ideally suited for programmers who know
something about Lisp and would like to move away from reaching for the
traditional stand-bys like awk, sed, perl, ...

You do not have to know any Lisp to do basic things in TXR, like extracting
data (in fairly complicated ways) and reformatting it, but the power is there
to tap into.

In TXR's embedded Lisp dialect, ("TXR Lisp"), you can express yourself in ways
that can resemble Common Lisp, Racket or Clojure.

You can see a glimpse of this in this Rosetta Code task, which is solved in
three ways that are almost expression-for-expression translations of the CL,
Racket and Clojure solutions:

[http://rosettacode.org/wiki/Self-
referential_sequence#TXR](http://rosettacode.org/wiki/Self-
referential_sequence#TXR)

Or here, with syntax coloring:

[http://www.nongnu.org/txr/rosetta-solutions-
main.html#Self-r...](http://www.nongnu.org/txr/rosetta-solutions-
main.html#Self-referential%20sequence)

If you closely compare the original solutions, you will see that certain
things are done more glibly in TXR Lisp.

------
mapcar
> If Lisp lan­guages are so great, then it should be pos­si­ble to sum­ma­rize
> their ben­e­fits in con­cise, prac­ti­cal terms.

His list is concise but man did he take a while to get to it!

Seriously though. The introduction was super relevant as I have wondered the
exact same question about Lisp myself. What features make it so praise-worthy?
Maybe X-expressions isn't a core feature for everyone to appreciate, but the
fact that everything is an S-expression is an understated value. People
complain about its syntax, but alternate versions (so many reincarnations of
parentheses-less Lisps) have never caught on.

The thing is, Lisp is no longer unique in its feature set, and languages with
more standard forms of syntax have incorporated some of its features. But it
is uncommon to find all of these listed features in one language. In the
domain of data analysis where I do most of my work, it still makes me sad that
XLISP-STAT has been supplanted by other languages which leave the user
wanting.

~~~
agumonkey
By feature set you mean sequences, map/filter/reduce and such ?

I felt there was more to Lisp than that. It was the root of the ML/function-
based family, which deepened the recursive typed logic McCarthy talked about
in his early papers.

The first-class function and functions as modeling unit, giving composability,
and domain embedding as first class.

------
happywolf
Agree with some of the earlier comments: the diamond-shaped thingies inserted
are really a nuisance and breaks the reading flow.

~~~
jey
Maybe only because it's unfamiliar. After all, other punctuation doesn't break
your flow. And trying to figure out whether something is a link or not also
breaks flow.

~~~
happywolf
The real question is why someone would change something most people already
getting used to. I don't see any compelling reason to change the link in this
way, do you?

------
colig
Does anyone else find it difficult to highlight things on this page?
Specifically, 'kvetchery' which is found in the third paragraph.

I believe the author is the one responsible for the facelift of Racket's
documentation. He may belittle his own lack of formal programming education
but I am thankful for his design chops.

------
einhverfr
I am learning Perl's FP features and really liking it, and teaching myself
common lisp. I enjoyed the article quite a lot actually.

I find it is very hard to define functional programming for many people but
this is what I have come to explain to people:

 _Functional programming means thinking in terms of mathematical functions in
the f(x) sense. Once you get that basic promise, that for any given input you
have a single correct output, then it transforms the whole way you think about
and designing your software._

The better I get with lisp, the more everything else changes. I may have to
try Racket.

~~~
raiph
What about spending a few minutes exploring P6 and providing feedback about it
to Larry Wall et al on #perl6?

One easy way follows (for you or anyone else reading this who is curious about
P6). Preferably between about noon and midnight GMT (so you're more likely to
catch Larry Wall, nick TimToady) visit the freenode IRC channel #perl6 (eg go
to
[https://kiwiirc.com/client/irc.freenode.net/perl6](https://kiwiirc.com/client/irc.freenode.net/perl6)
and enter a nick) and enter 'hi'. There are on channel evalbots and folk who
will be happy to show you a well designed and continuously improving Perly
blend of FP, OO, etc.

Yesterday's log is at
[http://irclog.perlgeek.de/perl6/yesterday](http://irclog.perlgeek.de/perl6/yesterday).
Hope to see you in the log. :)

------
amirouche
I tried somewhat Pollen and it's kind of fantastic, the only thing is getting
to work with a new project in a language that I don't know very well is
difficult for me. That's why I started a similar project in Python, watch
[https://warehouse.python.org/project](https://warehouse.python.org/project)
if you interested /azoufzouf/

~~~
amirouche
I just pushed the code. You can have a look at it @
[http://amirouche.github.io/azoufzouf/](http://amirouche.github.io/azoufzouf/)
there is all you need to know and ⵣcode{pip install azoufzouf}.

With that markup, it's easy to plug any function you want. That's right. It's
not nested and is inspired from unix philosophy, I dare to say. I tried
several time Sphinx, docutils alone and other markups they don't deliver as
much as this one (sofar).

------
theRhino
Not sure how closely you have read Siebel - your 1st few points are covered
pretty comprehensively at the start of his book

------
59nadir
I think it's kind of sad that most of the comments in this thread are about
other languages than Racket and only barely touch on the articles points
(mostly the stuff you don't need to actually try the language (or any lisp) to
comment on). I think it says a lot about what the crowd on HN is really all
about.

------
sanatgersappa
My personal experience with Clojure has been that it 'bends' the brain - in a
good way, and it forever changes the way you program. It is extremely
difficult to go back to the style of coding I did before my exposure to
Clojure. I guess other Lisps would provide a similar experience.

------
rodrigosetti
Nice write-up. I really like Racket, but never had a chance to use it in a
professional project so far.

By the way, Scribble (item 7) is an implementation of Literate Programming - a
feature is some other languages too. In Haskell, for example, you can write
programs in Latex with embedded code.

------
hyp0
Re 1. everything is an expression benefit, condition example:

C-like languages often have the ternary operator, _cond?exp1:exp2_ , that is
exactly this. I feel clever using it, but I consider it a hack, because it's
(usually) less clear. A microcosm of lisp, clever but unclear.

~~~
wtetzner
I think it mostly seems unclear in C because of the syntax.

If you could write this in C, would it still seem unclear?

    
    
        int x = if (y == 0) then 7 else 10;
    

As opposed to one of these:

    
    
        int x;
        if (y == 0)
          x = 7;
        else
          x = 10;
    

or

    
    
        int x = 10;
        if (y == 0) x = 7;
    

It makes everything local, and in my opinion reduces cognitive load.

~~~
hyp0
(speaking for myself only): I find the _?:_ syntax clearer... probably because
I've known it for so many years. It's the doing several things at once that,
for me, makes it unclear.

Of your examples, I find the very last one the clearest. Arguably, it's a
hack, because it assigns values twice to _x_ \- but it feels like the syntax
embodies the semantic truth of _y==0_ being an exception. A pattern matching
solution (with a specific and then a general rule) would also embody this, but
to me, having the general rule first, with a following exception, seems more
intuitive.

Disclaimer: "intuitive" is all very subjective, and it's certainly possible
that with experience, my intuition could change. But for better or worse, the
above is my opinion today!

PS: I do think your first example is cool, neat and clever. I understand and
feel that aspect of the appeal.

------
alvatar
Many of the last items in the list should be in the category "Scheme". Racket
is a dialect from Scheme, but it still is a Scheme. The syntax-case macro
transformations are available in most Scheme systems.

~~~
dragonwriter
> Many of the last items in the list should be in the category "Scheme".
> Racket is a dialect from Scheme, but it still is a Scheme.

The name was changed to Racket from a name with "Scheme" in it because its not
a Scheme in the strict sense; Racket does not conform to any of the Scheme
reports (though its bundled with language definitions that do, as well as lots
of others, but the Racket language, while near Scheme, is not.)

~~~
pflanze
> because its not a Scheme in the strict sense; Racket does not conform to any
> of the Scheme reports

The same could be said for many, if not most "Scheme" implementations.

Scheme didn't standardize stronger language abstraction features, otherwise
what Racket offers aside its core implementation (unless they would deviate
just for the purpose of lock-in) would just be Scheme libraries, and it would
be fair to call it "the Racket implementation of the Scheme language, which
comes bundled with more involved language libraries than most".

From a marketing standpoint, their move is good for them and bad for the
Scheme community because they imply that "Scheme" as a brand or community
isn't able to support the languages that they are implementing. They may have
the finances and manpower to make it work for them, but it leaves out the
community from which they have grown. I'm not deep enough inside the community
to know all the factors that lead to this but as a fringe participant it seems
(more than?) somewhat untruthful and disappointing.

------
picardo
Is it just me or is this page entirely blank? I poked through the source for
quite a long time, but couldn't undo it. The text is there. There is something
in the CSS that obscures it in Chrome. So annoying.

------
TheMagicHorsey
Why does Racket perform so slowly on benchmarks compared to Clojure and SBCL?

~~~
LeonidasXIV
> Why does Racket perform so slowly on benchmarks compared to Clojure and
> SBCL?

Clojure benefits from the optimization of the JVM and SBCL has a couple of
pretty bad-ass hackers working on the compiler. Racket on the other hand uses
a pretty of the shelf JIT compiler which might not be as specialized as the
other two.

Language-wise, there is hardly anything that would make Racket inherently
slower than Clojure. Maybe continuations.

------
guilloche
When visited with w3m I got spaces breaking words frequently. Is there any
justification to use complex html to control intra-word spacing for a web
page?

~~~
sjy
Those are soft hyphens, which supplement the crappy hyphenation support built
in to most browsers. w3m should probably just ignore them, but it looks like
your version is broken[1].

[1] [https://bugs.debian.org/cgi-
bin/bugreport.cgi?bug=441934](https://bugs.debian.org/cgi-
bin/bugreport.cgi?bug=441934)

------
CMCDragonkai
Many of the reasons you wrote are the same that got me attracted to Elixir.
That and of course erlang interop and OTP.

------
GFK_of_xmaspast
It's kind of interesting that the author's examples of 'woah! look at all
these cool packages' include plotting, unit testing, and a gui. Those
standards feel a little low to me.

------
dschiptsov
"Clarity is an evidence" as the saying goes. This post only proves its
correctness.)

The distinct feature of Lisps and good lispers is clarity of thought and
conscience of writing.

------
qewrffewqwfqew
That's some pretty ugly text for a site called 'practical typography'.

~~~
arm
Oh? What makes you say that? On my OS X computer at least, it honestly looks
gorgeous:

[http://f.cl.ly/items/3o2r3E2T2y3v3M3T291i/Screen%20Shot%2020...](http://f.cl.ly/items/3o2r3E2T2y3v3M3T291i/Screen%20Shot%202014-08-21%20at%203.10.46%20AM.png)

~~~
fake-name
Yeah, except the obnoxious diamond symbols used to denote each link, rather
then underlining them, like has been standard for 20 years now.

~~~
chipotle_coyote
Underlining isn't very attractive, either, even if it's standard. I don't
_mind_ the diamond, but I'm not very enthused by it, either.

------
jstoja
Please.... text-align: justify; ...

~~~
Tomte
Please... see [http://practicaltypography.com/justified-
text.html](http://practicaltypography.com/justified-text.html) for the
author's opinion.

Personally I believe that Matthew is wrong there. There's no justification for
justification. :-)

~~~
swah
Also on that page: "Jus­ti­fi­ca­tion is a mat­ter of per­son­al pref­er­ence.
It is not a sig­ni­fi­er of pro­fes­sion­al ty­pog­ra­phy. "

