github

shaunlebron / history-of-lisp-editing

  • четверг, 29 июня 2017 г. в 03:11:47
https://github.com/shaunlebron/history-of-lisp-editing


how people tolerated parens back in the 70s and 80s



NOTE: this is research in progress (references appreciated!)

History of Lisp Editing

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 - Paxedit
  • 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)
  • 1980 - IBM Lisp/VM Lispedit (display editor)
  • 1980 - Zmacs - first structure commands for text editor
  • 1979 - Nokolisp - screen-based editor
  • ...
  • 1967 - BBN (InterLisp) - (teletype structure editor)
  • 1966 - PILOT - first thesis on structure editing

Interlisp

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

Teletype Editor

Try it here!

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.

DEdit

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.

  1. pretty-print window (left) - click to select expressions (current=solid-lined, previous=dash-lined)
  2. command menu (right) - click to perform an operation on selections (current=arg1, previous=arg2)
  3. type-in window (below) - manually type an expression. when done, it becomes selected and clickable

dedit-screen

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

Try it here!

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...

sedit-screen

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

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):

Lispedit

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.

Nokolisp

Try it here!

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 editor 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)))             │
│ )                                            │
│                                              │
└──────────────────────────────────────────────┘

BOOT fib 1 0 is a status line indicating filename - function - level - ?.

Command Description
move cursor to select an expression
6 navigate into list (edit inline if atom)
4 navigate out to parent list (exit if top)
p toggle pretty-print
Paren Command Description Example
a add parens a => (a)
r remove parens (a) => a
w wrap with next a b => (a b)
c conjoin with next (a) b => (a b)

See all the nokolisp commands.

Maclisp

(preferred formatted ASCII files over data structures for programs)

Debating Maclisp vs Interlisp (i.e. storing code as text vs structure)

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

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

Appendix

Non-Lisp discussions on structure editing

Researching methods

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: