Skip to content

Latest commit

 

History

History
361 lines (308 loc) · 9.26 KB

readable-s-expressions-arne.org

File metadata and controls

361 lines (308 loc) · 9.26 KB

Readable s-expressions

Problem

The Problem

(let 
    ((a 1)
     (b 2))
    (message
        (number-to-string
            (* (- a b) (+ a b)))))

“I’ve used Lisp my whole programming life and I still don’t find prefix math expressions natural.”

  • Paul Graham

s-expressions: Simple, clear, ugly.

“Lisp has all the visual appeal of oatmeal with fingernail clippings mixed in.”

  • Larry Wall

“After 13 years of doing Lisp and 3 or 4 years of Python, I agree: I prefer writing Lisp, but Python is easier to read.”

  • John Wiseman

“LISP: … ‘Lots of Irritating Superfluous Parentheses’”

  • Jargon File

Challenges

Be General

useful regardless of underlying semantic

Be Homoiconic

underlying data structure is clear from the syntax

Abbreviations

Prior work

Lisp has, for over 50 years, had abbreviations

'x means (quote x) 
(a b c) 
means 
(a . (b . (c . ()))) 

Adding New Ones

Takes time to learn & implement

makes code readable

For arbitrary Lisps (Scheme, Common Lisp, Emacs Lisp, Arc, Clojure, …)

Readability counts

“When you program, you spend more time reading code than writing it… a language that makes source code ugly is maddening to an exacting programmer, as clay full of lumps would be to a sculptor.”

  • Paul Graham

Readable solution

Readable solution

new abbreviations

Normally-formatted s-expressions keep working

You can update your reader to support these

Three new expression tiers

(0) starting lisp

(let 
    ((a 1)
     (b 2))
    (message
        (number-to-string
            (* (- a b) (+ a b)))))

(1) Curly infix

(let 
    ((a 1)
     (b 2))
    (message
        (number-to-string
            {{a - b} * {a + b}})))

(2) Neoteric

let((a(1)
     b(2))
    message(
        number-to-string(
            {{a - b} * {a + b}})))

(3) Sweet

let
    \\
        a 1
        b 2
    message
        number-to-string
            {{a - b} * {a + b}}

Curly-infix-expressions

(c-expressions)

  • S-expressions, + curly braces \{…\} contain an “infix list”
  • A “simple infix list” represents one operation; it has:
    • An odd number of parameters
    • At least 3 parameters, and
    • All even parameters are the same symbol … maps to “(even-param odd-params)” so \{2 + 3\} maps to (+ 2 3)
  • Otherwise maps to “(nfx parameters)”.
  • No built-in precedence, use another \{…\} for embedded list

Curly Infix Examples:

Basics

Basics

{n <= 2} 
   ↓
(<= n 2) 

Multiple operators

{2 * 3 * 4} 
     ↓
(* 2 3 4) 

No Precedence

No Precedence

{2 + {3 * 4}} 
      ↓
(+ 2 (* 3 4)) 

Mixed operators

{2 + 3 * 4} 
     ↓
(nfx 2 + 3 * 4) 

Neoteric-expressions (n-expressions)

Definition

  • e(…) → (e …)
  • e\{…\} → e(\{…\})
  • e[…] → (bracketaccess e …)
  • unprefixed “( . e)” → e

Examples:

f(1 2) maps to (f 1 2) 
f{n - 1} maps to f({n - 1}) 
which maps to (f (- n 1)) 

Basic Sweet-expressions (t-expressions)

  • Includes neoteric-expressions, and deduces parentheses from indentation
    • An indented line is a parameter of its parent
    • Later terms on a line are parameters of the first term
    • A line with exactly one term, and no child lines, is that term; multiple terms are wrapped into a list
    • An empty line ends the expression
    • Empty lines before expressions are ignored
    • No indentation processing inside ( ), [ ], and { }
  • Stop “Lots of Irritating Superfluous Parentheses”

Examples

Sweet-expression Example #1

Sweet

define factorial(n)
    if {n <= 1}
        1
        {n * factorial{n - 1}}

↓ ↓ ↓ ↓ ↓

(define (factorial n)
  (if (<= n 1)
    1
    (* n (factorial (- n 1)))))

Sweet-expression Example #2

define long-and-boring?(x)
    cond
        not(pair?(x))       #f
        not(list?(x))       #f
        {length(x) < boring-length} #f
        #t           boring?(x)

Sweet-expression Example #3

define unit-list(x)
  cond
    null?(x)    '()
    pair?(x)
    if null?(cdr(x))
      unit car(x)
      append unit(car(x)) LISTSPACE unit-list(cdr(x))
    #t  append(LISTSP.SP unit(x))

Sweet-expression Refinements (1)

  • ;-comment-only-lines completely ignored
    • Even indentation irrelevant
    • Useful to “separate” lines without ending whole expression
  • Indents: one-or-more space, tab, and/or !
    • A line with only indentation is an empty line
    • If an expression starts indented, then indentation disabled
    • “!” is surprising, but solves past problems with indentation-sensitive syntaxes & enables highlighting

Sweet-expression Refinements (2)

  • A \text{\textbackslash\textbackslash} between datums (aka SPLIT) starts a new line at current indentation
  • A \text{\textbackslash\textbackslash} after indent (aka GROUP) represents no symbol
    • Useful for lists of lists
  • A $ in the middle of list (aka SUBLIST) restarts list processing (Haskell-like)
    • Right-hand-side (including sub-blocks) is the last parameter of left-hand side
  • Leading quote (etc.), followed by space or tab, quotes rest

Example with let*

Sweet

define factorial(n)
    if {n <= 1}
        1
        {n * factorial{n - 1}}

↓ unsweeten ↓

(define (factorial n)
  (if (<= n 1)
    1
    (* n (factorial (- n 1)))))

Tools available

Tools available

unsweeten: Translate sweet-expressions to s-expressions

Can be used in makefiles

sweeten: Translate s-expression to sweet-expressions

Simplifies transition

sweet-run: Translate and run sweet-expression script

Can use guile, scsh, clisp, …

neoteric-guile: Run guile using neoteric-expressions

sweet-guile: Run guile using sweet-expressions

Conclusions

Conclusions

“Readable”

  • is much more readable
  • is easier to understand
  • uses three tiers
    • Curly-infix-expressions: \{a + b\}
    • Neoteric-expressions: f(a b)
    • Sweet-expressions: f a b

More info & implementation: readable.sourceforge.net

Released under CC-BY

  • This presentation is released under the Creative Commons Attribution 3.0 Unported license (CC BY 3.0)
  • You may share, remix, and make commercial use of the work, as long as you give attribution to “David A. Wheeler”.
  • creativecommons.org/licenses/by/3.0/