Skip to content

Instantly share code, notes, and snippets.

@creationix
Last active July 10, 2017 20:53
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save creationix/ab9e99102d2a40c0f82c to your computer and use it in GitHub Desktop.

Lisp syntax, but using whitespace to remove most parentheses.

  • Every line is wrapped as a list. Use do to get just the value.
  • Empty lines are ignored.
  • Indented lines are concatenated to their parent lists.
  • A pipe (|) acts like indentation without wasting whitespace.
  • Use square brackets for inline lists.
  • Use round parentheses for infix notation (first two items are swapped)

For example, take the following lisp style program:

(print "Hello World")

(for (x 10)
  (for (y 10)
    (printf "%d + %d = %d" x y (+ x y))
  )
)

In my modified syntax, this would look like:

print "Hello World"

for [x 10] | for [y 10]
  printf "%d + %d = %d" x y (x + y)

A recursive Fib function could look like:

let fib | λ [n]
  if (n ≤ 2)
    do 1
    do ([fib (n - 1)] + [fib (n - 2)])
; Standard lisp style syntax, but each line is assumed to be wrapped in parens
print "Hello World"
; Loop 10 times with i changing from 0 to 9
; Indent means to continue parent list, but each line is own sub-list
for [i 10]
print i
; Loop over a list of names
for [name names]
print name
; Nested loops using | syntax
; | means to assume everything afterwards is indented
for [y 10] | for [x 10]
print x y
; Lines starting with @ are not wrapped as lists
let fib | λ [n]
if (n ≤ 2) 1
@ ([fib (n - 1)] + [fib (n - 2)])
; Object syntax
obj
@ name "Tim"
@ age 33
; Object set, get
get person "name"
@ person.name
set person "name" "Tim"
; Sample program: maze generator
; Sample output for 3x3 maze
; ██████████████
; ██ ██ ██
; ██ ██████ ██
; ██ ██
; ██ ██ ██████
; ██ ██ ██
; ██████████████
let width 30
let height 30
let size (width × height)
; Cells letine the maze
let cells | map [i size] | table
; parent is initially null
@ parent nil
; right and down walls are initially filled
@ right true
@ down true
; Define the sequence of index and right/left
let ww (width - 1)
let hh (height - 1)
; Create a list of actions to perform in shuffled order
let sequence | shuffle | concat
map [i size] | if ((i % width) < ww) | table
@ cell (cells get i)
@ direction "right"
map [i size] | if ((i ÷ width) < hh) | table
@ cell (cells get i)
@ direction "down"
; Find the root of a set cell -> cell
let find-root | λ [cell] | if cell.parent
find-root cell.parent
@ cell
for [item sequence]
let direction item.direction
let root | find-root (cells . i)
let horizontal | ? (item . 0)
let other | find-root (cells . (i + [? (item . 0) 1 width)))
(if (≠ (. root 0) (. other 0))
(. root 1 other)
(. (. walls i) (? (. item 0) 0 1) false)
)
)
let w (width × 2)
let h (height × 2)
join "\n" | map [y (h + 1)]
join "" | map [x (w + 1)]
¿ " " "██" | or
; Four outer edges are always true
= x 0
= y 0
= x w
= y h
; Inner cells are more complicated
? (y % 2)
? (x % 2)
; cell middle
false
; cell right
(. (. walls (+ (÷ (- x 1) 2) (× (÷ y 2) width))) 0)
)
(? (% x 2)
; cell down
(. (. walls (+ (÷ x 2) (× (÷ (- y 1) 2) width))) 1)
; cell corner
true
)
)
))
))
))
@jeapostrophe
Copy link

Implement it in Racket and see how it works out for real programs. it is easy to make a new reader at the #lang level and just use the rest of Racket syntax. Make sure you read about the history of paren-less LISP though, such as sweet.

@creationix
Copy link
Author

@jeapostrophe you mean like? http://readable.sourceforge.net/

I've read that and it's where I got the idea of an infix syntax using a different bracket. I decided I prefer round parens for infix and square for regular lists.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment