1. 28
  1.  

  2. 4

    Curiously, this article doesn’t really talk about lisp syntax or parens at all, but instead uses that as the hook to talk a out the power of macro languages and pure asts.

    1. 6

      I think that may be its strength – it helps you develop an intuition for the abstract syntax by showing how building up to it enables greater and greater expressiveness. The concrete syntax is less relevant.

      1. 4

        I guess I was hoping for something more like how lispers reportedly “don’t see the parens” or other strategies for making more lisp code more readable to a newcomer. Especially the practise of piling close parens all together in a massive stack instead of using indentatiin to help visually signal where things end often makes lispy code very hard to decipher for me without reformatting it or using paren-highlighting crutches.

        1. 2

          In emacs’ lisp-mode, indenting an entire sexp shows the logic very cleanly and the indentation will be wrong if you have the wrong number of parens in a batch. But sometimes I just go to a pile of close parens, delete them all, and the watch what happens when I start typing them back in. See https://www.gnu.org/software/emacs/manual/html_node/emacs/Multi_002dline-Indent.html https://www.gnu.org/software/emacs/manual/html_node/emacs/Matching.html#Matching

          1. 2

            I’ve found using indentation to separate each part of the AST to be useful (so the code looks like a tree), just stack close parens at the end and have the editor highlight the matching parens to make sure the right amount of them is there.

            1. 2

              just stack close parens at the end and have the editor highlight the matching parens to make sure the right amount of them is there.

              Yeah, this is a great description of my biggest problem with reading LISP. Stacking them at the end makes it impossible to see where things end/close

              Imagine C code written like this:

              void thing() {
                  while(other) {
                      if(you) {
                          stuff;}}
                  if(nice) {
                      stuff;}}
              

              This is what most lisp looks like to me :P

              1. 1

                I guess I’ve just gotten used to it because that looks readable to me - I get the information of what block is where in the indentation, having the braces match separated out doesn’t add any additional understanding of where things logically are. But my main language used to be Python so maybe that prepped me to focus on indentation and whitespace.

                1. 1

                  I mainly work in python so I am pretty comfortable with white space, but I’m in the same boat as singpolyma. Their example is pretty tame compared to some lisp code where you have 8+ rparens backed up at the end. Without editor support, I have to be very careful about reading the whole function and maintaining a paren count so I can edit it.

                  Below is a pretty simple function pulled at random from The Seasoned Schemer. If you wanted to refactor and put a cond inside the abort and around the cons, I experience a bit of cognitive overhead from counting out parens.

                  (define the-empty-table
                    (lambda (name)
                      (abort
                        (cons (quote no-answer)
                          (cons name (quote ()))))))
                  

                  Whereas this is a lot easier to modify:

                  (define the-empty-table
                    (lambda (name)
                      (abort
                        (cons (quote no-answer)
                          (cons name (quote ()))
                        )
                      )
                    )
                  )
                  

                  (IDEs with colored parens or scope highlighting help, of course.)

                  That said, I also have trouble navigating in vim using [number][movement] patterns. I have never learned to look at a piece of text and say, “Ah, yes, ‘5w’” or “13j”. I think it is a similar skill.

                  1. 1

                    I wouldn’t do any explicit counting of parens at the end, I would just add the cond and then stack or delete parens at the end until the editor highlights that the last paren matches the one before define. Or maybe I am misunderstanding your example. What would your code look like with the cond added?

                    1. 1

                      I think you understand me and I’ll try that technique out. Part of my point is that the syntax is tougher to work with without some IDE help. Having paren matching, colored parens and scope highlights alleviate the issue.

                      1. 2

                        Yeah you definitely want paren matching (highlight the half of paren pair) and automatic indentation at the very least. Not sure how helpful color vs. just highlighting the selected one.

                2. 1

                  Clojure user here; Indentation plays a big part, and pattern matching on the forms/functions is the other thing. For your example:

                  (defn thing []
                    (while @other
                      (when you
                        (stuff)))
                    (when nice
                      (other-stuff)))
                  
                  ;; ...code continues here...
                  

                  The first thing I read: “a function named thing of no arguments. I don’t care where its closing paren is because of the whitespace below signifies it ended.

                  The next: a while block, followed by a when (while is not very common in Clojure but it’s there). I see that using indentation. An important thing: when is a special case of if that only has one branch (the “truthy” branch). So the indentation it “creates” is its own conceptual block.

                  Diving deeper -> the while block has as a condition @other -> the @ at the front is an indication of a mutable thing, and it has to be otherwise the while would never exit.

                  And so on. It’s definitely harder when you first approach because defn, when, do etc are not present in C-style languages, so it’s all a jumble of words and parenthesis. Rainbow parentheses plugins help quite a lot, and parentheses matching is a must.