
Ask HN: How do you “get” Lisp? - khaledh
Over the years I&#x27;ve read countless articles and comments praising Lisp. Yet, there&#x27;s something that keeps pushing me away from it every time I try to give it a chance. Maybe it&#x27;s the nested prefix syntax, all those parentheses, something else?<p>I read most of SICP, and believe me I like the concepts the book puts forward. But I still don&#x27;t get Lisp. I understand some of the merits: code as data, functional, minimal uniform syntax (s-expressions), macros (meta-programming), etc. But I fail to _appreciate_ those features in the same way I appreciate features in other languages. For example, I can instantly appreciate Elixir&#x27;s pattern matching capability because it makes control flow fades into the background (in addition to simultaneously destructuring variables), removing a lot of noise; I can appreciate its pipe operator because it makes data flow fades into the background as well, letting me focus on logic composition.<p>What&#x27;s the best way to develop an appreciation of Lisp, given that I learn best through examples that clearly demonstrate somethings&#x27;s value, not by reading a laundry list of features?
======
gus_massa
Lisp/Scheme have almost the same number of parenthesis+curly brackets than C.
The difference is than in C the closing curly bracket has it's own line, but
in Lisp/Scheme they are put all together. (If you hate parenthesis, try
Python.)

The main advantage of Lisp/Scheme are the macros. The s-expressions are good
because they make writing macros much easier. You don't have to mentally
translate from the real language to the internal representation while writing
macros.

I made a quick search and Elixir has macros. Do you write macros in Elixir?

The short answer is that Lisp/Scheme had real macros before it was cool.

~~~
khaledh
> The main advantage of Lisp/Scheme are the macros.

Where can I find a practical example/tutorial/guide that demonstrates this in
the context of building an actual application? I'm sincerely curious.

> I made a quick search and Elixir has macros. Do you write macros in Elixir?

Not much. It's something not encouraged by the language designer and community
(since it can result in a lot of "magic" that is hard to understand), and I
rarely found myself needing them.

~~~
gus_massa
The idea is that some repeated patterns can be encoded in a functions, but
other repeated patters need more abstraction. Try to find some repeated
pattern.

Some real example from a internal site for 500 users in the university:

The idea is that I have a parameter with the data of the current user, a
parameter is like a global variable but each tread has it's own copy so it's
"thread safe". Sometimes I want to iterate over all the users inside one of
the administrations form. So I have to write in racket something like:

    
    
      (for ([u (in-list all-users)])
        (parameterize ([current-user u])
          (do-something-interesting-here)
        )
      )
    

(The last three parenthesis should be in the same line, but if you like c-like
formatting, let's put them in their own line.)

I had to repeat this pattern a few times. It is boring and error prone.
Perhaps I have to add a lock for the user profile. Perhaps I need an special
case if the user in the iteration is the administrator. But let's keep the
example simple.

Now I can use a macro to define the pattern:

    
    
      (define-syntax-rule (for/users body ...)
        (for ([u (in-list all-users)])
          (parameterize ([current-user u])
            body ...
          )
        )
      )
    
    

This is the simplest way to define a macro in scheme and racket. It has no
error checks. It has no room for variants. There are more advanced methods to
write good macros. One important point is that there is some magic to ensure
that the variable `u` used inside the macro don't mess with a variable `u`
defined outside the macro.

The nice part is that the macro looks almost like the code I want to repeat. I
only need to use `body ...` in the definition in the first line and then
replace the interesting part with `body ...`. Here is the magic! In the easy
case, the macros look almost like normal code!

Now I can use it as any normal thing in the language, for example

    
    
      (for/users
        (writeln (user->name (current-user))
      )
    
      (define count 0)
      (define sum 0)
      (for/users
        (set! count (+ count 1))
        (set! sum (+ sum (user->age (current-user))))
      )
      (define average (/ sum count))
      (writeln average)
    

I hope the examples are self descriptive.

The idea inside the lispy word is that users should write macros when it is
necessary to write macros. Try to use them sparsely. Try to make them blend
with the language. Try to make them intuitive to use.

A bad example of a macro is:

    
    
      (define-syntax-rule (show x y)
        (writeln (list y x y))
      )
    

It's a bad macro because it looks like a normal function but the expressions
are evaluated out of order and one of them is evaluated twice. So

    
    
      (define n 7)
      (show n (set! n (+ n 1))
      (writeln n)
    

will show

    
    
      (#void 8 #void)
      9
    

but the user probably expect

    
    
      (7 #void)
      8
    

So write macros, but write them sparsely and wisely.

My recommendation is to enjoy Elixir, try to find repeated patters, try to
enclose the patters in functions. When that fails try to write good macros.
When you understand why you want more macros and more macros try racket (or
scheme/lisp/clojure/...).

------
taylodl
Those things you like in Elixir? Make them in Lisp. Think of Lisp as the
language you use to build the language you need to implement your solution.
See Paul Graham's essay _Programming Bottom-Up_
([http://www.paulgraham.com/progbot.html](http://www.paulgraham.com/progbot.html)).

~~~
khaledh
But the thing is, I'm willing to take an opinionated language that gets most
things right over a "god language" that is malleable enough to bend to your
will. I'm pretty sure others will disagree, but I don't feel like writing my
own language using Lisp.

~~~
foo101
But no language, no matter however opinionated, does get most things right,
does it? People complain about C, C++, Java, Go, you name it.

I know many people are averse to the idea of macros that makes Lisp so
malleable (you can add syntactic abstractions like in-fix expressions etc.)
but the same people are not averse to adding new types with classes or new
"operators" with functions. I find it curious that many are comfortable at
stopping the level of abstraction at just that (types and operations). For
some reason, the idea of abstracting away syntax itself or dynamic function
definitions (macros) is unpalatable. Why should the comfort for abstraction
stop just there? Just like one can make a mess with types and functions, one
can make a mess with macros. Just like one can write beautiful and elegant
types and functions, one can write beautiful and elegant macros. Does the
aversion to macros come due to the traumatic experience people relate to when
they think of C/C++ macros?

------
kazinator
> _For example, I can instantly appreciate Elixir 's pattern matching
> capability because it makes control flow fades into the background (in
> addition to simultaneously destructuring variables), removing a lot of noise
> ..._

But where does that stuff come from? Structural pattern matching appeared in
Lisp.

See papers like:

 _Format-directed List Processing in LISP_ [1966]

[https://apps.dtic.mil/dtic/tr/fulltext/u2/633242.pdf](https://apps.dtic.mil/dtic/tr/fulltext/u2/633242.pdf)

 _METEOR: A LISP Interpreter for String Transformations_ [1963]

[https://dspace.mit.edu/handle/1721.1/6106](https://dspace.mit.edu/handle/1721.1/6106)

I'm pretty sure that the word "destructuring" comes from the Lisp culture.
Fifteen, twenty years ago, if someone used "destructuring", it had to be a
Lisp programmer.

------
brudgers
To me, SICP is not really a book about Lisp. Scheme makes the underlying
concepts easier to explain. Pedagogical power was one of the motivations for
developing Scheme.

The Lisp that's more like Erlang(Elixir). The one that was developed for
commercial applications programming is Common Lisp. For me, the book that
shows the power of Lisp for applications programming is Norvig's _Paradigms of
Artificial Intelligence: Case Studies in Common Lisp_
[https://github.com/norvig/paip-lisp](https://github.com/norvig/paip-lisp)

Common Lisp is the result of consensus among industry stakeholders. There is
meaningful consistency but no commitment to purity or theory or dogma. More
about what people are (were) doing than what "people should do".

YMMV.

~~~
khaledh
Thanks for the tip about that book. I'm collecting a number of resources from
the answers here and I'll try to go through them. Right now Paul Graham's "On
Lisp" seems promising.

~~~
brudgers
It's been a few years since I read _On Lisp_. I kind of walked away with the
impression that the main characters are macros and the star is anaphoric
macros. There are nuggets in the buildup to their introduction and anaphoric
macros are interesting. But my brain doesn't wrap very far around macros and
my sense of understanding dissipated pretty quickly each time I stopped
reading. For me, Graham's _On Lisp_ was fun to read but less applicable than
his _ANSI Common Lisp_. _On Lisp_ was a rabbit hole for me. A fun rabbit hole.
But still a rabbit hole.

\---

Changing gears back to your original question, Racket has pattern matching.
[1] [2]

[1]: Racket Guide: [https://docs.racket-
lang.org/guide/match.html](https://docs.racket-lang.org/guide/match.html)

[2]: Racket Reference: [https://docs.racket-
lang.org/reference/match.html](https://docs.racket-
lang.org/reference/match.html)

------
hackermailman
The ability to abstract everything in the language, is what I got from
learning Lisp. You can just keep abstracting and abstracting until you're
working on an entirely different kind of plane where you're now measuring
programs themselves in their entirety and assigning a type to their
'behavior'. Anyway, that's what I got from it.

As for pattern matching, try something like this
[https://cs.uwaterloo.ca/~plragde/flaneries/FDS/index.html](https://cs.uwaterloo.ca/~plragde/flaneries/FDS/index.html)
you'll see how patterns you find by yourself can just be specified and
matched, making it much easier to take apart things like suffix trees.

------
CyberFonic
Initially I avoided macros and simply learnt to write "flow-oriented" small
programs in Scheme. It took a while to get used to not using many intermediate
variables and simply feeding the output of one function into the next. Once I
started seeing patterns I found myself writing small general purpose functions
from which I could assemble larger more complex functions.

BTW it is important realise that Common Lisp and Scheme have significant
differences. Personally I prefer gnuScheme. I hear that many business
applications prefer to use SBCL.

------
TurboHaskal
The greatest feature of Lisp is that everything is an expression. Almost
everything else is secondary as it’s already present in other modern
languages.

If you ever encountered a syntactic limitation in any language, you could go
to Lisp and work your way around it either with macros or even simple control
flow.

I would recommend to skim through Peter Norvig’s PAIP to get a taste of it.
Then, as another user suggested, writing your own pattern matching library
would be a great exercise.

------
db48x
I would recommend implementing a pattern-matching capability in Lisp. With
Lisp you don't need to wait for a language designer to invent a new language
with better pattern matching; you can add pattern matching to the language any
time you want it.

------
mimixco
One of the most striking things about Lisp for me is how concise it is. The
excellent Lisp Tutor Jr [0] will give you several interactive examples that
make you think in terms of shorter and simpler functions, which are the heart
of Lisp programming. As PG has said, if you find that your function is more
than a handful of lines long, you're probably not doing it right. The tutor
app is a good training ground for thinking in Lisp this way and it might be
the breakthrough you need...

[0]
[https://alarm.cti.depaul.edu/lisptutor/login](https://alarm.cti.depaul.edu/lisptutor/login)

------
gms
What worked for me was writing business logic for a customer-facing app. The
amount of unavoidable boilerplate made me understand what Paul Graham had been
on about.

------
frou_dh
The answer for how to find out whether Lisp has practical benefits for you
rather than only theoretical benefits is to... force yourself to write some
practical projects (non-toy)!

[...and additionally maybe expend the effort to absorb a sizeable practical
codebase that others have written]

Maybe the answer to the question will ultimately be "It's not for me", but an
experiential approach is the only way to reach an answer that is satisfying.

~~~
khaledh
This is generally a good way to learn things, as I learn best by doing. But,
when approaching a new language or framework, I need some practical guidance
on building applications using that language/framework.

Ideally I'm looking for the equivalent of Michael Hartl's Ruby on Rails
Tutorial. I'm not a ruby/rails developer, but I did follow his tutorial and it
was one of the best guides I've followed (pedagogically speaking).

------
sloaken
The first step to learning LISP the right way is to understand what LISP
stands for: Lets Insert Some Parentheses :-)

I would be curios if there are a set of guided lessons in Lisp with guided
projects. I would like to revisit this language as it is truly an elegant
language.

~~~
khaledh
> I would be curios if there are a set of guided lessons in Lisp with guided
> projects.

That is exactly what I'm looking for. Practical guidance for building real
world applications. If the answer is "Lisp is not for business applications",
then fine, at least I have my answer.

