I'd like to find out how people tolerated parens back in the golden days of Lisp. I have a feeling we might've forgotten some things that would be useful today, or might influence some new ideas.
I started by working backwards from today (still filling in blanks):
- 2015 - Parinfer
- 2014 - Lispy
- 2012 - Smartparens
- 2005 - Paredit by Taylor Campbell
- 2001 - DrScheme, now DrRacket
- ...
- 1987 - Interlisp SEdit (structure editor. full interactive display)
- 198? - Interlisp DEdit (display editor. clickable display + command window)
- 1983 - BBC LISP FEDIT (structure editor, based closely on PSL fedit)
- 1980 - IBM Lisp/VM Lispedit (display editor)
- 1980 - Zmacs - first structure commands for text editor
- 1980 - Portable Standard Lisp fedit/sedit (structure editor)
- 1979 - Nokolisp - screen-based editor
- ...
- 1967 - BBN (InterLisp) - (teletype structure editor)
- 196? - Standard Lisp fedit (structure editor)*
- 1966 - PILOT - first thesis on structure editing
In Interlisp, the programmer worked with source code presented by a structure editor, which operated on source code in the form of memory-resident Lisp data structures.
—Evolution of Lisp
Portable Standard Lisp, as used at Cambridge University in England and later commercialised by Acornsoft, had a structure editor, entered as sedit for editing arbitrary s-expressions or as fedit for editing functions. Whether this feature existed in Portable Standard Lisp as used at Utah and other sites is not known, but is probable, since it is understood that the Cambridge version was a straight port. Similarly, it is not known whether this feature existed in Standard Lisp prior to the 1980 release of Portable Standard Lisp, but again it is probable, since the new feature in Portable Standard Lisp was the Lisp-to-C compiler.
A command-line interface for editing s-expressions. Rather than displaying the whole file, only one expression is displayed at a time—by printing after each command.
- use
N
to go Nth child of current expression - use
0
to go up to parent - nested sub-expressions collapsed by default to
&
- expand with
?
- pretty-print with
pp
Six paren commands can be performed on the current expression's children:
Command | Name | Mnemonic | Extra Inference |
---|---|---|---|
BI |
Both In | ()+ |
|
BO |
Both Out | ()- |
|
LI |
Left In | (+ |
adds ) at end |
LO |
Left Out | (- |
removes ) and EVERYTHING AFTER IT |
RI |
Right In | )< |
|
RO |
Right Out | )> |
(A B C D E F G H)
>(BI 3)
(A B (C) D E F G H)
^ ^ wrap parens around index 3
(A B C D E F G H)
>(BI 3 5)
(A B (C D E) F G H)
^ ^ wrap parens from index 3 to index 5
>(BO 3)
(A B _C D E_ F G H)
^ ^ unwrap parens around index 3
(A B C D E F G H)
>(LI 3)
(A B (C D E F G H))
^ ^ insert left-paren before index 3, and right-paren at end
(A B (C D E) F G H)
>(LO 3)
(A B _C D E_ _ _ _)
^ ^ ^ ^ ^ remove parens around index 3, and EVERYTHING AFTER IT
(A B (C D E F G H))
>(RI 3 2)
(A B (C D) E F G H_)
^ <----- ^ move right-paren of index 3 to inner index 2
>(RO 3)
(A B (C D_ E F G H))
^ -----> ^ move right-paren of index 3 to end
See the 1967 BBN Lisp System section on "structure changing commands" page 49.
The display editor was a visual alternative to the teletype editor—click one or two expressions in the pretty-print, then click a command to execute on those expressions.
- pretty-print window (left) - click to select expressions (current=solid-lined, previous=dash-lined)
- command menu (right) - click to perform an operation on selections (current=arg1, previous=arg2)
- type-in window (below) - manually type an expression. when done, it becomes selected and clickable
Clicking an expression while holding Shift unreads it into the type-in window (pastes as text).
- left click - select object
- middle click - select containing list
- right click - select lowest common ancestor with previous selection
DEdit Paren Command | Initially Hidden? | Teletype Command |
---|---|---|
() |
same as BI |
|
( in |
middle-click () to show |
same as LI |
) in |
middle-click () to show |
same as RI |
() out |
same as BO |
|
( out |
middle-click () out to show |
same as LO |
) out |
middle-click () out to show |
same as RO |
See the 1985 Interlisp-D Reference Manual Volume II: Environment, Chapter 16 page 407.
SEdit later replaced DEdit as the default visual structure editor for Interlisp. It allowed the user to type directly into the pretty-printed view, and did away with the separate type-in window from DEdit. It may look closer to a normal text editor we're used to, but...
Though it appears to be a normal modern text editor, it still has the constraints of an auto-formatted structure editor. To give the user the most freedom within these constraints, a very interesting language was crafted around the mouse, allowing it to interact with the structure in a way I can only describe as vim-like. See my take on documenting its unique caret states and selection types.
After seeing this novel mouse behavior, I can see why most paren commands from DEdit and teletype editor were removed in SEdit. The mouse primitives work well with just the simplest paren commands (wrap/unwrap), exposed as hotkeys:
Hotkey | Name | Description |
---|---|---|
Meta-( |
Parenthesize | wraps selection in a list. places ▲ after ( |
Meta-) |
Parenthesize | wraps selection in a list. places ▲ after ) |
Meta-/ |
Extract | unwraps selected list, string, or quote |
Normal insertions, deletions, and clicking of parens have the following behavior:
Paren Operation | Description |
---|---|
Type ( |
inserts () with ▲ inside |
Type ) |
nothing inserted. places ▲ after next ) . selects whole list |
Backspace at ( |
removes list if empty, else no-op |
Backspace at ) |
nothing deleted. places ▲ before ) |
Middle-click ( |
selects list. places ▲ on clicked side of ( |
Middle-click ) |
selects list. places ▲ on clicked side of ) |
See the 1987 Lyric Release Notes or Medley Release Notes in Appendix B, and mailing lists musings 1, 2
ZMacs in 1980 is reported to be the first text editor with balanced parentheses commands. The 1987 ZMacs Editor Reference shows them on page 209 (3-137):
I must say that I wish I could use LISP/VM again, and Martin's editor. I've always felt it gave me the best interface, with the highest productivity, of any editor I've ever used for LISP. —Cyril N. Alberga
An important feature of Lispedit is a program display that shows the structure of a Lisp expression from the point of view of a selected sub-expression. The sub-expression, called the focus, is shown high-lighted and its relationship to the surrounding context is shown by automatically generated indentation. Selected components of the focus and its context are elided (shown as '...') in order to condense large expressions to the confines of a finite screen. —Interactive program execution in Lispedit
There are no surviving images of what Lispedit looked like. But reconstructing from descriptions:
┌────────────────────────────────────────────────────────────────┐ │TOP DISPLAY AREA: pretty-printed and condensed code ▲│ │ ("focus" expression highlighted) ││ │ ││ │ 1 (LAMBDA ││ │ 2 (INPUT) ││ │ 3 (PROG (WORDLIST) ││ │ 4 (DO ((I 0 (+ (FINDENDWORD INPUT I) 1))) ...) ││ │ 5 (SETQ WORDLIST (REVERSE WORDLIST)) ││ │ 6 (NMAPCAR ││ │ 7 (LAMBDA ││ │ 8 (WORD) ││ │ 9 (COND ││ │ 10 (((ONE-OF a e i o u) (ELT WORD 0)) &) ││ │ 11 ('ELSE ││ │ 12 (CONCAT ││ │ 13 (SUBSTRING WORD 1 (- (SIZE WORD) 1)) ││ │ 14 (SUBSTRING WORD 0 1) ││ │ 15 "ay ")))) ││ │ 16 WORDLIST) ...) ││ │ ▼│ ├────────────────────────────────────────────────────────────────┤ │FENCE LINE: (recursion-level / input-state / current-object) │ ├────────────────────────────────────────────────────────────────┤ │MESSAGE AREA: (recent command messages, multiline if needed) ▲│ │ ▼│ ├────────────────────────────────────────────────────────────────┤ │Program Function Keys: (currently defined keys) │ ├────────────────────────────────────────────────────────────────┤ │Command Area: _ │ └────────────────────────────────────────────────────────────────┘
See the 1984 LISP/VM User's Guide and Experience with an Uncommon Lisp.
In 1979, Nokolisp's editor was added as the author's reaction to the first Interlisp teletype editor, to see what it might look like as a screen-based editor.
Rather than conventional pretty-printing seen in later screen-based editors, Nokolisp's editor displayed a subexpression on each line, allowing you to move a cursor line-by-line to select one to operate on. For example:
0> fib
(lambda
(x)
(if
(< x 2)
x
(+ (fib (1- x)) (fib (- x 2)))))
1> (edit fib)
This would bring up the following view:
( BOOT fib 0 0
_ lambda
(x)
(if (< x 2) x &)
)
(Notice &
elides the long expression for fitting.)
The _
cursor is initially on the first line. If we move _
down to the third
line, we can select and focus it to see our next view:
( BOOT fib 1 0
_ if
(< x 2)
x
(+ (fib (1- x)) (fib (- x 2)))
)
I believe the BOOt fib 1 0
is a status line indicating your position in the
root expression.
Paren commands are letters (need to verify):
Paren Command | Description |
---|---|
a |
wrap in parens |
r |
remove parens |
w |
extend paren to next expression |
c |
push last element out of paren |
(preferred formatted ASCII files over data structures for programs)
A discussion/debate from 1978 that reveals a lot about how people thought about text vs structure when storing and displaying their code:
Programming in an Interactive Environment: the Lisp Experience
- response by Richard Stallman arguing for text: https://www.deepdyve.com/lp/association-for-computing-machinery/surveyor-s-forum-structured-editing-with-a-lisp-PzoXAz9GCu?impressionId=594bfe8baf9dc&i_medium=mydeepdyve&i_campaign=recommendations&i_source=recommendations
- author's reply: https://www.deepdyve.com/lp/association-for-computing-machinery/surveyor-s-forum-structured-editing-with-a-lisp-mQNqMU2je0?impressionId=594c0f05171ea&i_medium=docview&i_campaign=recommendations&i_source=recommendations
- a much later followup discussing how structured editing died: https://groups.google.com/forum/#!msg/comp.lang.lisp/D2Q5t8IEOkg/AqbNfOxZgUIJ
- Maclisp killed it because they wanted custom layout of code and comments
This is so far my favorite summary of this topic from 1997. (too many great points to list). https://groups.google.com/d/msg/comp.lang.lisp/dldLx8Yj7q8/u4y2zq19XIYJ
- Prune: https://www.facebook.com/notes/kent-beck/prune-a-code-editor-that-is-not-a-text-editor/1012061842160013/
- Frame-based editing: https://news.ycombinator.com/item?id=14609215
- Intentional Programming: https://www.youtube.com/watch?v=tSnnfUj1XCQ
- similar to Interlisp (i.e. structure-based)
started from Paredit credits, (could not locate sedit.el
):
The original inspirations for paredit were Interlisp-D's structure editor 'SEdit' -- a real structure editor, not a cheesy imitation like paredit -- and Guillaume Germain's sedit.el for GNU Emacs.
- finding mailing list discussions
- looking for official reference manuals of lisp machines
- using deepdyve to find articles
- asking around
General:
- Evolution of Lisp seems to provide a good map.
- http://www.softwarepreservation.org/projects/LISP/