Hacker News new | past | comments | ask | show | jobs | submit login

Could someone give an advice on how to grok Lisp, please?

I write Clojure code, read Lisp books, articles etc.

But I don't feel 'magic' yet.

How did you get 'addicted' to Lisps?




If you want to find the 'magic moment' try 'The Little Schemer' by Friedman and Felleisen.

I'm on my third read of it. The first time I tried to implement all the exercises in Ruby and failed around chapter 7 when the language ran out of expressive power. The second time round I implemented it in Javascript and got to chapter 9 before the syntax became too much of an obstruction to seeing what the code was doing (the good parts of Javascript are actually quite similar to Scheme in some ways but the syntax is just horrible).

This third time round I am implementing it in the language it was actually written in, Scheme. And having tried it with two other languages I can suddenly see why LISP is so suited for certain types of problems.

My 'magic moment' came when I finally grokked how the Y combinator works. It was like since I started learning how to code 4 years ago I had been continuously trying and failing to get two mirrors to line up perfectly so the images went off into infinity, and suddenly I got it just right and caught a glimpse of the wonderful self-referential simplicity of the entire of computation.

I use Ruby in my daily work but I want to start using more Clojure. There is a mathematical purity to LISP that other languages don't have.

It's like the whole language itself IS the fixed point function for humans interacting with computers.


That's because the magic is a lie.

I have this book. I've also worked on many Scheme systems and the internals of CMUCL. I was once a Lisp weenie.

The things that made Lisp special are not so special today. Basic things like garbage collection or dynamic typing exist everywhere. The more esoteric things, like CLOS, are esoteric for a reason (they are very difficult to use and impossible to master). The one feature that people still hype has always been a double-edged sword: macros. Scheme entirely ran away from the macros that Common Lisp has, and for good reason. But Scheme still has not developed a hygienic replacement that is equally powerful (and easy to use). They never will. It's been decades now.

The problem with macros and pet DSLs is that the best advice for using them is: don't. They can subtly alter the semantics of your code, and they conflate run-time vs compile-time. Not many people can elegantly weave through all these dimensions at once and not make a disaster. Homoiconicity has been oversold. The practice of CONSing everywhere is just awful, and slow. It's not the '80s anymore. CONS doesn't make sense today.

When you have first-class functions, closures and GC, you have the best things from Scheme/Lisp.


You're using some interesting words for something that is a tool to accomplish a task. You should continue to write code in Clojure and also other languages like C, Python, JavaScript, Ruby, C#, F#, etc. if you want to become a better programmer.

A programming language is a tool like any other and it is not magical or addictive. Your goal should be to solve problems by using the most appropriate tools for the job. Focusing on anything else I think is misguided.


Yet, even carpenters can have favorite tools. I really enjoy hitting stuff with a large sledgehammer; that doesn't mean I use it to do everything... I just really like hitting stuff with a big hammer, makes it extra special when I can actually use it.

Same applies - imo - to programming languages. I use Ruby for most of my work since "it just gets the job done"; but I really love the moments I can work on one of my clojure projects.

Clojure is my favorite hammer at this moment, that might change to F#, Haskell, Go, <new language> anytime.


That's why I said one should program in a plethora of languages to understand the strengths and weakness of each paradigm and feature set. You wouldn't use a sledgehammer to put a nail in the wall for hanging a picture and similarly there are certain situations where Clojure or Ruby is not the right language.


But imagine how much fun it would be to drive that tiny nail into the wall with that huge sledgehammer.

I don't disagree with you - on the contrary - but just wanted to point out that fun might be a great motivator for chosing a language.


In fairness there is some good context for wanting to get the 'magic', Lisps are talked about in such a context, as beautiful life-changing experiences, so it's understandable to be curious. I'd agree, the right tool for the job, and focus on the job, but the context is there to ask. Lisps as I've used them seem like powerful tools.


Yes, lisp dialects are powerful but there is no magic. The road to enlightenment is long and arduous and can not be put in an HN comment box. It's like I said in my original comment, the only way to get there is to just continue to write code and explore different paradigms and languages.


I would not describe the road as long and arduous, so much as long and joyful.

I have never used a language a fraction as fun as Scheme (except for Common Lisp, which is also quite fun).


Yes, I agree, I think pragmatic discussion like this is important, the 'magic, beautiful, life-changing' hyperbole is probably better left alone in analysis I'd say.


I think what you can enlightenment is what others are calling magic.


To feel 'magic', I think you need to read SICP and to do write some typical programms where lisp is really effective: - a lisp interpreter (the second step may be a non deterministic lisp interpreter). - symbolic derivation - a prolog interpreter

If you try any of these exercises in a only procedural language (C, Ada, Pascal, Fortran, ...), you should feel how unnatural it is compared to lisp.


The one feature that really differentiates Lisp from other languages is its macro system. Macros allow you to give arbitrary semantic meaning to an expression. The expression (a b c) could quite literally do anything. It could set the value of b to the value of c (setf), it could call the procedure named by c with the value of b and store that value back into b, or define a class called b which has a local variable called c. Macros allow programmers to build arbitrarily complex DSLs all within Lisp.

A couple examples of some really great macros are those in PAIP[0]. In particular, look at the defrule macro[1][2] for a version of mycin[3]. The macro defrule is a DSL for creating rules about how to diagnose different bacteria. Also look at the rule macro[4][5] for defining DCGs[6], a way to parse natural language.

A great way to learn more about macros is through reading On Lisp[7], in which Paul Graham explores some of the really crazy things that are possible with macros, including implementing continuations[8], creating a DSL for ATNs[9] (another way to parse natural language), and even implementing an object system.

[0] http://norvig.com/paip.html

[1] http://norvig.com/paip/mycin-r.lisp

[2] http://norvig.com/paip/mycin.lisp

[3] http://en.wikipedia.org/wiki/Mycin

[4] http://norvig.com/paip/grammar.lisp

[5] http://norvig.com/paip/unifgram.lisp

[6] http://en.wikipedia.org/wiki/Definite_clause_grammar

[7] http://www.paulgraham.com/onlisp.html

[8] http://en.wikipedia.org/wiki/Continuation

[9] http://en.wikipedia.org/wiki/Augmented_transition_network


Lisp's macro system is so powerful that it actually turned out to be the 'curse' of Lisp:

http://www.winestockwebdesign.com/Essays/Lisp_Curse.html

However I wouldn't call it "curse" but merely the truth that Lisp programmers need a lot of self discipline to write maintainable code.

Lisp was one of the first languages I learned at university (also Pascal and Ada). Afterwards I learned almost every other new programming language. Lisp and the Scheme dialects are still the most powerful languages of all, to this day.

People who are intimidated by such a raw power should take a look at Nim (nim-lang.org). It takes the best of several modern languages and it also has an amazingly convenient and powerful macro system. For instance:

  template repeat * (body: stmt): stmt {.immediate.} =
    block:
      while (true):
        body

  template until * (cond: expr): stmt {.immediate.} =
    block:
      if cond:
        break

  var i=0
  repeat:
    echo i
    i += 1
    until i==7


Also, the language syntax is (basically) designed to be parsed in a trivially obvious way into the internal "list" (really tree, with lists as a common special case) data structure. This lets the friction of writing macros which work with code (or with structured data) be very low: the macro logic that you write is fed that parsed list and works with it directly, skipping the usual glue logic for telling a parser how to cope with syntax for a language extension.

(The "basically" caveat above is because some Lisps honor this code-is-a-list principle more than others. E.g., I have seen remarks about how modern Schemes have moved away from it at least a little bit, with syntax which is importantly not quite a list, though I don't know any of the details. And CL has other kinds of reader magic --- like one-character "reader macros" and like the implicit package which is used as a default for symbols at read time when no explicit package is given --- that can in principle complicate the obvious 1-1 correspondence between source and parsed-as-list representation, although in practice that magic is very seldom used in such a way that you need to think about it.)


> The one feature that really differentiates Lisp from other languages is its macro system.

That's not exactly true. There are many languages, both old and new, which provide macro systems comparable to defmacro and/or syntax-rules. Dylan, Nimrod, Julia and Elixir come to mind.

I personally don't think there's one feature which makes lisps this great. It's really the whole experience, from syntax to repls to tools and so on.


The counterargument has been that while other languages may provide powerful macro systems, they're not as easy to use, nor are they homoiconic.


That's not quite true either. Julia, Prolog, Io are homoiconic, for example. Ease of use is subjective, but most AST based macro systems work in the same way defmacro does, using quote and unquote. Then there's Scheme and syntax-rules, which are (arguably) even easier to get right (not necessarily to use) and which don't even need homoiconicity.


Wow, great answer, many thanks for that!


I only started to feel the magic and getting addicted after having worked with Common Lisp for a good while, enjoying it AND THEN switching back to another, more mainstream language. Languages like C, Java, C#, Perl, Python, Ruby. Then you discover all the artificial barriers that have been put up in those languages, all the needless syntax you need to remember and the hoops they have to jump through to provide basic Lisp functionality like lambdas.

I have never "switched back" to the likes of Scala or Haskell so I can't speak for those. ML and its brethren have been long on my list of languages to check out and only recently I started playing with Haskell.


Most of what made Lisp special has been pulled into other languages. These days IMO Lisp is more of a preference than a magical language.

You really have to think about what it was like in 1990 to understand the appeal of Lisp. No Python, Ruby, Scala, C# or Java. First-class functions were not considered an important part of a language. Garbage collection was widely considered to be something to be avoided in a real language. C++ (this was long before even C++98) was a cutting-edge language.


I strongly disagree.

You will not experience elegance on the level of Scheme from any of the languages you list: not Python, not Ruby, not Scala, C# or Java. I would argue that even Clojure and Common Lisp are not nearly as elegant (though they come closer than the rest).

On the other hand, I think that each language has its strengths, and things that it does more easily or optimally than most others.

Learning to program in different paradigms (procedural, OO, logical, concatenative, etc) can really be a mind-opening expericence, and it's one of the reasons that I most value learning the Lisp way. But other ways are also well worth learning.


I am not an expert Lisper myself, but to understand Lisp's power I'd suggest to write a basic parser of maths expressions (to evaluate things like "2+3*4-7+log(100)") - the language you choose to write it doesn't matter, it can be a Lisp or not.

Doing that will require you to deal with the AST of expressions you are parsing. Then, you can try to tweak a bit the evaluator to optimize it. Doing so will make you manipulate AST, and since LISP is his own AST, you become aware of what you can do with it.


Interesting witness of someone who got 'addicted' to Lisp:

http://www.defmacro.org/ramblings/lisp.html


And his thoughts in retrospect: "I wrote these a long time ago. I was much more naive then about the craft of software engineering, so proceed with caution." http://www.defmacro.org/

For what it is worth, his articles about Lisp are among the things that got me interested in Lisp, and I still like Lisp.


To get an idea of what kinds of things you can do but in a language that might be familiar to you, just look at all the tools built around an AST parsing library like Esprima. Basically you get all that kind of magic, but in a way that is native to the language and natural to work with due to homoiconic syntax (s-expressions).


You sound like someone who really wants to like a band because their friends do.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: