4 ms·
Lisp code usually has a complex tree like indentation & layout. Indentation is provided as a standard service by editors and by Lisp itself. See the function PP
by lispm 7y ago
Lisp code usually has a complex tree like indentation & layout. Indentation is provided as a standard service by editors and by Lisp itself. See the function PPRINT as the interface to the pretty printer, which does layout and indentation of source code.
We look for visual tree patterns. For example the LET special form:
LET
BINDINGS
BODY
or more detailed
LET
VAR1 VALUE1
VAR2 VALUE2
...
BODYFORM1
BODYFORM2
...
The list of binding pairs is another common pattern.
There is a small number of tree patterns which are used in the core operators of Lisp. Once you've learned them, reading Lisp is much easier than most people think.
CL-USER 13 > (pprint '(let ((one-number 1) (two-numbers 2) (three-numbers 3)
(four-numbers 4) (five-numbers 5) (six-numbers 6))
(+ one-number two-numbers three-numbers
four-numbers five-numbers six-numbers)))
(LET ((ONE-NUMBER 1)
(TWO-NUMBERS 2)
(THREE-NUMBERS 3)
(FOUR-NUMBERS 4)
(FIVE-NUMBERS 5)
(SIX-NUMBERS 6))
(+ ONE-NUMBER
TWO-NUMBERS
THREE-NUMBERS
FOUR-NUMBERS
FIVE-NUMBERS
SIX-NUMBERS))
- tabtab 7y agoAll indentation does is tell you that there is a hierarchy of some sort. The fact something is one level deeper than another still doesn't tell me generally what it does, because that depends on what the parent(s) does. And it's not a difference maker because "regular" language can also use indents. Further, the coder decides the indentation, and I'm not convinced it's consistent enough. In my example, a curly brace is a curly brace regardless of a coder's preference. It's enforced by the rules the language, not the coder. Another thing I'd like to point out is that languages like JavaScript provide two levels of common abstraction. Using curly braces, parenthesis, and square brackets as an example, you spot them and immediately know the forest-level category something is: code block, function call, or array/structure index. With Lisp, all you are guaranteed have is the function name (first parameter), which you have to do a mental name-to-purpose lookup, which could involve thousands of names. Splitting the lookup into levels improves the mental lookup performance, at least in my head. It also helps one quickly know to ignore something. For example, if I'm looking for a code block, I know I can probably ignore array indexes, and vice versa. It's forest-level exclusion, which is hard to do with single-level lookups because the list is too long: it has to contain the general category of each name. It's extra mental accounting. Hard-wiring in big-picture categories into the syntax allows quickly making forest-level reading decisions, and which individual coders generally can't change. When it comes to team-level read-ability, consistency usually trumps abstraction and many other things. Maybe Lisp can do something similar with "let", bindings, and body, but then it starts to resemble "regular" languages, along with their drawbacks, which is typically less abstraction ability. Consistency "spanks the cowboys", both the good cowboys and the bad cowboys. But at least you know what you have, and can estimate and plan accordingly.
- lispm 7y ago> All indentation does is tell you that there is a hierarchy of some sort. As I said, it's not just indented, but also layouted. As a Lisp developer I see a LET and then know that a binding+body structural pattern is following. binding+body and variations of those is used in a bunch of operators. That's a simple sequence: 1) identify the operator on the left 2) it determines the layout pattern 3) visually apply pattern recognition based on the layout pattern and classify the blocks Lisp is actually quite well to read, but you have to learn the basic structural patterns for a few days. The biggest hurdles are mental blocks and prior exposition to other types of syntax systems. > the coder decides the indentation He doesn't. Lisp does it. There are indentation rules provided by the development environment. If Lisp does the layout, it uses a complex layout system to adjust the code to the available horizontal space, taking into account the constructs to layout. That's why Lisp developers use these indentation and layout tools for decades. Lisp code itself is fully insensitive to formatting. Tools (editor, Lisp, ...) do the indenting and sometimes also the layouting for the user. > Using curly braces, parenthesis, and square brackets as an example, you spot them and immediately know the forest-level category something is: code block, function call, or array/structure index. Lisp uses symbolic names for that. People are extremely good at reading names. Since Lisp names are always at the beginning of a form, there is no guess/backtracking needed to find out the most top-level form. Where as with languages with infix operators I would need to parse the whole thing, finding out the operators and select the one with the highest precedence. > With Lisp, all you are guaranteed have is the function name (first parameter), which you have to do a mental name-to-purpose lookup, which could involve thousands of names. Splitting the lookup into levels improves the mental lookup performance, at least in my head. Lisp has not just functions, but also macros and special operators. Function calls have a fixed syntax and there is not much to understand. Special operators and macros usually signal with their names the kind of structure and thus the layout expected to follow. For example there are a bunch of macros which begin with WITH- . Those signal this pattern WITH- items and property list BODY Where 'items and property list' is something like (name item :option1 value1 :option2 value2 ...) For example a file will be opened like this: (with-open-file (stream file :direction :input) (read stream)) I read WITH-OPEN-FILE and know that it is a WITH- type macro. Then I know the basics of the structure of the code. Lisp has a number of these built-in patterns.