Skip to content

benhsz/parless

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 

Repository files navigation

Parless

Parless is a DrRacket plugin that aims to implement Adaptive Code Visualization, first described in this blog post.

The goal is to improve the user experience of programming languages with parenthesized syntax, such as Racket, Scheme, Common Lisp, etc.

Work In Progress

No working implementation as of yet.

What Does It Do?

Parless aims to provide an alternative view of Lisp code. Or rather, an enhanced view of Lisp code. The idea is that the editor re-dresses parentheses. This would (hopefully) make Lisp code easier to read and write.

The functionality is similar to syntax highlighting in that it changes the appearance of code but not the actual syntax.

More specifically, the functionality could variously visualize parentheses as:

  1. 'Imbalanced parenthesis' characters
  2. 'Padding' characters
  3. Space characters

How parless goes about re-dressing parentheses depends on the formatting and structure of the code, and user configuration.

For example, visualizing parentheses here as space characters would be ambiguous:

 cons 1  cons 2  cons 3 '()

But not if each expression were on its own line and indented:

 cons 1
   cons 2
     cons 3 '()

If each expression were on its own line and not indented, parentheses would again be the more appropriate visualization:

(cons 1
(cons 2
(cons 3 '())))

Editors already keep track of how code is formatted and structured. Parless uses that information to dynamically provide the appropriate view.

Note that while some examples and mock-ups below may look very similar to other attemps to change Lisp code (i.e. sweet-expressions) parless does not involve any syntax changes such as significant indentation. This mean the programmer will input just as many parentheses as before. The alternative view parless provides should be compatible with all existing Lisp code.

Examples & Mock-ups

For instance, this code:

(define (factorial n)
  (if (zero? n)
      1
      (* n (factorial (sub1 n)))))

Could be re-dressed as:

example code

The same example, but with one closing parenthesis missing:

◖define (factorial n)
   if ▹zero? n
      1
      ▹* n (factorial (sub1 n)

Four missing closing parentheses:

◖define (factorial n)
  ◖if ▹zero? n
      1
      ◖* n ◖factorial (sub1 n)

Or with the right amount of parentheses but false indentation:

define (factorial n)
    → if ▹zero? n
      1
      ▹* n (factorial (sub1 n)

What allows the parentheses to be visually omitted without introducing ambiguity is the availability of these visual cues. They will only visualize when certain conditions are met (e.g. a missing closing parenthesis). Once everything is in order (balanced parentheses, correct indentation) the code will appear clean and unambiguous.

With a decent amount of parentheses being outright invisible, it could be awkward if the user wishes to manually select and edit code as text with the cursor. One possibility is to have hidden parentheses re-appear with the presence of a mouse cursor, as in this animated mockup:

animation

Parless could also provide options to configure the view.

If the above examples were too minimalist, you could have parentheses turn into dots instead of whitespace.

·define (factorial n)
  ·if ·zero? n·
      1
      ·* n (factorial (sub1 n)····

A larger example in Common Lisp (source from http://norvig.com/python-lisp.html)

 defparameter *grammar*
  '(▹sentence -> (noun-phrase verb-phrase)
     noun-phrase -> (Article Noun)
     verb-phrase -> (Verb noun-phrase)
     Article -> the a
     Noun -> man ball woman table
     Verb -> hit took saw liked)
  "A grammar for a trivial subset of English."

 defun generate (phrase)
  "Generate a random sentence or phrase"
   cond (▹listp phrase
          mappend #'generate phrase)
        (▹rewrites phrase
          generate (random-elt (rewrites phrase)
        (t (list phrase)

 defun generate-tree (phrase)
  "Generate a random sentence or phrase,
  with a complete parse tree."
   cond (▹listp phrase
          mapcar #'generate-tree phrase)
        (▹rewrites phrase
          cons phrase
               (generate-tree (random-elt (rewrites phrase)
        (t (list phrase)

 defun mappend (fn list)
  "Append the results of calling fn on each element of list.
  Like mapcon, but uses append instead of nconc."
   apply #'append (mapcar fn list)

 defun rule-rhs (rule)
  "The right hand side of a rule."
   rest (rest rule)

 defun rewrites (category)
  "Return a list of the possible rewrites for this category."
   rule-rhs (assoc category *grammar*)

 defun random-elt (choices)
  "Choose an element from a list at random."
   elt choices (random (length choices)

License

MIT License

About

A DrRacket plugin to streamline how code appears in the editor

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published