The topic of parenthesis paralysis arose in some circles I
frequent in relation to Lisp. This is a semi-mythical notion that somehow the
use of parentheses in Lisp contributes to cognitive difficulty or the seizing
of thought. It is usually used as an excuse not to learn Lisp or make fun of
it.
Related to this idea, a person by the name of Alessio Stalla hacked
the Lisp reader to try and present a syntax that is more "newbie friendly".
The actual hack is pretty cool.
His altering of the syntax of lisp made it look like what follows. I have some
fundamental disagreements about the syntax--in particular the
if expression consequence and alternate both being grouped by
the { } characters associated with the if form. But that conversation is for
another day...
with-output-to-string (str) {
print #\c str;
if (> foo 45) {
progn { print 3; print 4; }
print 5;
}
}
This generated some discussion and I decided to extend a post I had done in
Usenet into a blog entry.
I've hacked scheme for a long time and lisp for a little while. I believe there
is such a thing as parenthesis-paralysis. After some careful introspection
upon it over the years, I've come to a belief about how it arises and presents.
It appears to me to happen because of two concepts:
- Indention style
- Destructuring bind, as performed by a human reading code.
Indention style, especially in lisp, is extremely important and
emacs/slime is the only thing that culturally "does it correctly out of the
box". It does it correctly, because the cultural indention style of Lisp
appears to be exactly defined as what SLIME produces!
Most editor's notion of auto-indention is that when you hit return, you align
with the first non-whitespace character on the previous line OR you just indent
X columns. Combine this with a regular Joe's idea of indention being TAB, and
you have a disastrous situation. For example suppose my tab stops are set to 4
in the following example. Every place you see a period is where I hit tab:
(let ((thing 42)
. (stuff 99)
. (qux 100))
. (format t "Hi~%"))
Looks like crap doesn't it?
In other block structured languages, a simple tab is sufficient for code
readability, e.g., C:
void foo(void)
{
. int thing = 42;
. int stuff = 99;
. int qux = 100
. printf("Hi\n");
}
Notice, from a mental model of indention, I did exactly the same
behavior. I indented the bindings, left a space, then indented the body.
People use the same mental model of indention for similar languages.
This realization is the key to why people entering lisp for the first
time have such a hard time about it.
Let's take a look at Alessio Stalla's precipitating example. If your tab stop
is set to 2, then this is exactly how you would type it using a
regular editor's default notion of indention and the TAB key.
with-output-to-string (str) {
. print #\c str;
. if (> foo 45) {
. . progn { print 3; print 4; }
. . print 5;
. }
}
We can hypothesize that the author's mental model of code indention appears to
follow to the default behavior of their editor and that they write in block
structured imperative languages more often than not. I believe the author of
the code view this indention model as "correct". I put that in quotes, since it
is purely subjective.
In C, C++, PHP, perl, Java, Python, Fortran 90, etc, etc, etc, applying the
same mental indention model is just fine and leads to pretty readable code.
Specifically in python, it is enshrined.
In Lisp (and somewhat scheme), the default behavior of the editor and/or the
mental model of indention is completely wrong. Why? Reason number 2.
Humans use visual whitespace and alignments of similar boundary markers to
block off semantically related entities. This helps them to destructure
the forms into semantically meaningful sections or elements.
The correctly indented lisp form for the above let form:
(let ((thing 42)
(stuff 99)
(qux 100))
(format t "Hi~%"))
You can see how the parentheses of the binding forms are aligned with each
other. The ( which "sticks out" on the left is the demarcation of the beginning
of the binding list. The fact the (format ...) is indented to the left of the
bindings, but the right of the let states the bindings are over and tells you
this is the body of the let.
Another one, more complex in lisp (done with the mental model of Algol-style
indention):
(do ((x 0 (1+ x))
. (y 10 (1- y))
. (z 0 (1+ z)))
. ((zerop y) (+ x z))
. (format t "Hi!~%"))
That is terrible, since the test condition vanishes into the step forms. Get
rid of the newline in the middle and it is a train wreck. The problem is
that this is how editors want to do it by default! I've seen the modern
generation of programmers lately. They use pico, notepad, gedit, or kde/gnome
stuff (mere toy code editors to me) to write their code and they don't even
realize there are others to choose from that are much better. The editors all
do this ham fisted auto-indent behavior and can't really be taught otherwise. I
can't imagine this while writing lisp. I would go insane. (Arguably, I may be
insane, but that's for the courts to figure out.)
Here is the correctly indented do form. Notice how the "nubs" of the left side
parentheses on the do visual block allow the eye to disambiguate the step and
test forms.
(do ((x 0 (1+ x))
(y 10 (1- y))
(z 0 (1+ z)))
((zerop y) (+ x z))
(format t "Hi~%"))
The crux of the indention issue is that culturally, lisp doesn't indent
at the same quanta of indention as other languages over the various semantic
forms of the language. Sometimes you need 1/4 of an indention, or 1/2
of one, or a one space difference. Programmers, when presented with such a
problem, spend their time laboriously aligning (instead of code writing)
parenthesis (often mixing tabs and spaces) so everything looks right--because
their editor doesn't do it for them! This is the first part of the paralysis.
If they don't know what looks right to begin with, they simply self converge to
a self-consistent form of indention and write all their code in it.
The paralysis continues when, not having been grounded in the cultural
indention style of lisp or not having an editor that performs it automatically,
you start reading other people's code. If you get unlucky and read a collection
of people's code that never learned the correct cultural style (each having
their own style), then the destructuring process gets amazingly difficult to
do. You end up reading character by character, parenthesis by parenthesis,
trying to figure out where semantic forms start and end. The most powerful
visual/spatial recognizer in your head (like 1/4 of your brain matter is
devoted to it!) sits completely idle!
I hacked my emacs/SLIME syntax coloring to be very detailed and show many
different classes of semantic ideas: comments, ANSI functions, macros, special
forms, type names, special variables, constants, etc, etc, etc to all be color
coordinated with each other using color theory to give me insight into what
I've written--and whether I'm writing it correctly!
The most important change I did was to make the parenthesis color nearly the
same as the background color. In a sense they vanish and I'm left with the
spatial blocks as an indention structure, which works just fine. I can always
resolve a specific parenthesis from the background if I have to to disambiguate
a form. Usually, if I screwed something up, the indention level of my code base
goes wrong and it is pretty easy to find where I missed a parenthesis.
Oddly, lisp is the only language for which I do this, all others are just white
text on a black background and I prefer it that way. Syntax/Semantics
highlighting is distracting to me in non lisp languages. It is a requirement for
lisp!
After determined use of the colorizing/indention system slime and my hacks
provide me, I occasionally find that looking at non-colorized, but correctly
indented Lisp, is hard. The parentheses make a visual heaviness that is hard to
ignore; I almost read it as ALL CAPS style yelling. If I'm looking at
non-colorized and non-culturally indented lisp, I revert to the "hunt and peck"
method of trying to destructure the semantic forms in my head. It gets
frustrating very quickly.
I honestly believe parenthesis-paralysis is real. The right editor will make
the paralysis completely disappear, but the wrong editor will accentuate it.
As a treat (maybe I'm using an esoteric definition of the word...), here is
some horrendously written emacs lisp which augments the Lisp syntax highlighter
in a certain color theme to in fact delineate various portions of the language
to me. It is by no means the whole of what I want out of a Lisp IDE, but is a
tiny step that saves me some heartache.
I searched through emacs' color themes for a long time, and mostly came to the
conclusion that most of those theme designers had never opened, let alone been
in the same state as, a book on color theory or color perception. Bold claims?
Sure, but I'm an idiot writing a blog, and that should be normal fare on the
Internet. This is why I don't have a comment section.
What I did was started with the idea of warm colors being near to the viewer,
cool colors being far. I also took into consideration complimentary colors,
color intensity, and a Western view of the general meaning of bare colors. Each
axis: warm to cool, color to compliment, and low to high intensity, cultural
meaning of color, has a reason to exist in the syntax highlighting. Once you
are aware of these meanings it becomes much easier to visually process the code
and get a handle of the dependencies in the code. This design isn't finished
yet, and over time I'm evolving it as I see what I actually care about when
writing Lisp.
Here are some rules about the things I wanted to emphasize or ensure I could
easily separate on my screen. These rules are not the complete set I wish
to do in my source, just the ones I was generally able to do given the tools
I had. Also, things like special forms and macros get the same color, because
I haven't found a reason to separate them.
- De-emphasize parentheses both to lower the light emanating from my
screen and to make the SLIME indention drive my comprehension. Leave
enough presence of the parentheses that I can disambiguate constructs
if needed.
- Emphasize special variables. Messing up their use is hard to debug!
- Since code and comments are very different, separate them in color.
- Anything relating to types or compiler optimizations should stand
out. They represent hard coded assumptions I shouldn't easily
ignore.
- Since macros cannot be applied to apply or funcall or passed to
things like mapcar, make them stand out from regular functions.
- If I type a known ANSI function/macro/symbol/condition/etc, I want
to know I typed it correctly.
- Keywords often represent symbols used at interface boundaries,
so make them very noticeable since one probably has them always in
one's mind.
- Constants should be marked as such. Careful with strings since they
can take up a lot of screen real estate.
- Anything which is little used or special in the language should be
marked with a little bit of emphasis so I know something strange is
going on there.
- I specifically want the boolean values to be highlighted since a hidden
use of them can change my expectation about the result a function
return, or to denote final clauses in cond or other
contexts.
- Conditions represent odd control flow, so intensify them.
- General code should be a basic conservative color so I know nothing
special is going on there. If I want to know what it does, I'll read
it.
Once one has the concrete plan about what one cares about in the Lisp code, you
go and start assigning colors. Emphasizing means higher intensity, and
separating means putting the concepts into color compliment domains. Choosing
colors on the grey/brown intensity scale mean you only care about emphasis in
between them, but they don't exist as compliments to other things. A
complimentary concept is like code and comments or special variables and
non-special variables. Use of warm and cool colors can give a sense of depth in
the code allowing once to inspect code quickly for important things, which
should be up front.
So, given the semantic plan and color knowledge, I went and assigned colors.
This is what I made.
Screenshot 1: Some code out of the MD5 implementation by Pierre R. Mai. Notice
how the coloring regularizes the text and makes it easy for your eye to wander
over the color blocks inspecting what is present.
Screenshot 2: Some code out of the MIDI library implementation by Mathieu
Chabanne, Camille Constant, Emmanuel Necibar, Stephanie Recco, Robert Strandh,
David Lewis, Marcus Pearce, and Christophe Rhodes. If I were looking at this
code, the special variable *time* would be most important to me. Good thing
it is a high intensity color.
This code was generated by me scraping the Common Lisp Hyperspec web pages,
munging the symbols and whatnot into the form you see below, and then
insufficiently reading the emacs lisp programming manual. It is built on top of
the comidia color theme, but I suspect if you change the colors can be
customized to another theme. There are some errors in the highlighting like 1+
doesn't get recognized probably because it looks like a +1+ constant in terms
of the regexes and I haven't figure out exactly how to fix it. There are other
limitations and omissions, like ,@*foo* not being highlighted correctly that I
need to figure out as well. I fix them when they annoy me enough.
There are some tasks like highlighting certain grouping parentheses when
the point is not in the extent of them that I have no idea how to do.
Some of the complex highlighting I want which is more semantics based, e.g.,
any symbol in a condition spot in a handler-case is colored a specific
color but only if it actually exists in the source, and symbols used
in functional places should be colored color A, but if used in another
namespace are colored according to that namespace, is impossible to do in
emacs since the language structure is not fully realized in the editor. Because
this simplistic highlighter is semanticly ignorant, if you have a habit of
choosing common lisp symbols and using them in other namespaces, this syntax
highlighter is probably going to overly upset you.
As for me, I use the non-terminal mode of emacs and I don't intersect namespace
boundaries on the same symbol. I don't care if this doesn't work in terminal
mode since I will most likely never use that mode. If you decide to use it,
good luck.
Frankly, the most useful thing out of this code is the 978 common lisp symbols
that have been categorized for your use in a different piece of code.
All the code I wrote in this blog post is under the *spins the wheel* Modified
BSD License.
;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; set up a color theme that is good enough for now.
;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(when (require 'color-theme nil 'noerror)
(color-theme-comidia))
;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Set up some highlighting rules for all known ANSI common lisp functions and
;; macro names, special operators, etc. This assumes color-theme-comidia.
;; This is always tinkerable....
;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defface ansi-lisp-boolean
'((t (:foreground "white")))
"Color all of the ANSI Common Lisp Booleans this specific color")
(defface ansi-lisp-constant
'((t (:foreground "orchid1")))
"Color all of the ANSI Common Lisp Constants this specific color")
(defface ansi-lisp-declaration
'((t (:foreground "indianred2")))
"Color all of the ANSI Common Lisp Declarations this specific color")
(defface ansi-lisp-condition-type
'((t (:foreground "indianred2")))
"Color all of the ANSI Common Lisp Condition Types this specific color")
(defface ansi-lisp-function
'((t (:foreground "pale green")))
"Color all of the ANSI Common Lisp Functions this specific color")
(defface ansi-lisp-generic-function
'((t (:foreground "cyan"))) ; same as the comida color-theme which I use.
"Color all of the ANSI Common Lisp Generic Functions this specific color")
(defface ansi-lisp-macro
'((t (:foreground "cyan"))) ; same as comida color-theme which I use.
"Color all of the ANSI Common Lisp Macros this specific color")
(defface ansi-lisp-special-operator
'((t (:foreground "cyan"))) ; same as macros and as the comida color-theme.
"Color all of the ANSI Common Lisp Special Operators this specific color")
(defface ansi-lisp-type
'((t (:foreground "red")))
"Color all of the ANSI Common Lisp Types this specific color")
(defface ansi-lisp-unknown
'((t (:foreground "red")))
"Color all of the ANSI Common Lisp this specific color")
(defface ansi-lisp-global-variable
'((t (:foreground "yellow2")))
"Color all of the ANSI Common Lisp Globals this specific color")
(defface ansi-lisp-expression
'((t (:foreground "indianred1")))
"Color all of the ANSI Common Lisp Expressions (like declare) this specific color")
(defface ansi-lisp-parenthesis
'((t (:foreground "#4d4d3d"))) ; grey25, but with more yellow in it
"Color all of the ANSI Common Lisp Parenthesis")
(defface ansi-lisp-numbers
'((t (:foreground "orchid1")))
"Color all of the ANSI Common Lisp Numbers")
;;; These are functions which produce the individual entries for each kind of
;;; symbol name according to what face they should have.
(defun ansi-boolean (x)
(list
(concatenate
'string "\\<\\(" (symbol-name x) "\\)\\>") 0 ''ansi-lisp-boolean))
(defun ansi-constant (x)
(list
(concatenate
'string "\\<\\(" (symbol-name x) "\\)\\>") 0 ''ansi-lisp-constant))
(defun ansi-declaration (x)
(list
(concatenate
'string "\\<\\(" (symbol-name x) "\\)\\>") 0 ''ansi-lisp-declaration))
(defun ansi-condition-type (x)
(list
(concatenate
'string "\\<\\(" (symbol-name x) "\\)\\>") 0 ''ansi-lisp-condition-type))
(defun ansi-function (x)
(list
(concatenate
'string "\\<\\(" (symbol-name x) "\\)\\>") 0 ''ansi-lisp-function))
(defun ansi-generic-function (x)
(list
(concatenate
'string "\\<\\(" (symbol-name x) "\\)\\>") 0 ''ansi-lisp-generic-function))
(defun ansi-macro (x)
(list
(concatenate
'string "\\<\\(" (symbol-name x) "\\)\\>") 0 ''ansi-lisp-macro))
(defun ansi-special-operator (x)
(list
(concatenate
'string "\\<\\(" (symbol-name x) "\\)\\>") 0 ''ansi-lisp-special-operator))
(defun ansi-type (x)
(list
(concatenate
'string "\\<\\(" (symbol-name x) "\\)\\>") 0 ''ansi-lisp-type))
(defun ansi-unknown (x)
(list
(concatenate
'string "\\<\\(" (symbol-name x) "\\)\\>") 0 ''ansi-lisp-unknown))
(defun ansi-global-variable (x)
(list
(concatenate
'string "\\<\\(" (symbol-name x) "\\)\\>") 0 ''ansi-lisp-global-variable))
(defun ansi-expression (x)
; used for things like declare
(list
(concatenate
'string "\\<\\(" (symbol-name x) "\\)\\>") 0 ''ansi-lisp-expression))
(when t ;; sometimes I need to disable this whole thing....
(add-hook 'lisp-mode-hook
(lambda ()
(font-lock-add-keywords
nil
(append
;; Conventional Constant Variables
'(("\\<\\([+][^ +]*[+]\\)\\>" 0 #'ansi-lisp-constant))
;; Conventional Global Variables, including ANSI ones
'(("\\<\\([*][^ *]*[*]\\)\\>" 0 #'ansi-lisp-global-variable))
;; Lisp Numbers, simple ones, just integers
'(("\\<\\([+-]?[0-9]+\\)\\>" 0 #'ansi-lisp-numbers))
;; I'm a psycho and want my parentheis color to be controlled.
'(("\\([()]\\)" 0 #'ansi-lisp-parenthesis))
;; These are often important to see, but I don't know how to
;; highlight the matching parenthesis with it
;;'(("\\([#][']\\)" 0 'ansi-lisp-boolean))
(mapcar #'ansi-boolean
'(nil t))
(mapcar #'ansi-constant '(array-dimension-limit
array-rank-limit array-total-size-limit
boole-1 boole-2 boole-and boole-andc1
boole-andc2 boole-c1 boole-c2 boole-clr
boole-eqv boole-ior boole-nand boole-nor
boole-orc1 boole-orc2 boole-set boole-xor
call-arguments-limit char-code-limit
double-float-epsilon
double-float-negative-epsilon
internal-time-units-per-second
lambda-list-keywords lambda-parameters-limit
least-negative-double-float
least-negative-long-float
least-negative-normalized-double-float
least-negative-normalized-long-float
least-negative-normalized-short-float
least-negative-normalized-single-float
least-negative-short-float
least-negative-single-float
least-positive-double-float
least-positive-long-float
least-positive-normalized-double-float
least-positive-normalized-long-float
least-positive-normalized-short-float
least-positive-normalized-single-float
least-positive-short-float
least-positive-single-float long-float-epsilon
long-float-negative-epsilon
most-negative-double-float
most-negative-fixnum most-negative-long-float
most-negative-short-float
most-negative-single-float
most-positive-double-float
most-positive-fixnum most-positive-long-float
most-positive-short-float
most-positive-single-float
multiple-values-limit pi short-float-epsilon
short-float-negative-epsilon
single-float-epsilon
single-float-negative-epsilon))
(mapcar #'ansi-declaration '(type compilation-speed
debug declaration dynamic-extent ftype
ignorable ignore inline notinline optimize
safety space special speed))
(mapcar #'ansi-condition-type '(arithmetic-error
cell-error condition control-error
division-by-zero end-of-file file-error
floating-point-inexact
floating-point-invalid-operation
floating-point-overflow
floating-point-underflow package-error
parse-error print-not-readable program-error
reader-error serious-condition
simple-condition simple-error
simple-type-error simple-warning
storage-condition stream-error style-warning
type-error unbound-slot unbound-variable
undefined-function warning))
(mapcar #'ansi-function '(- / \* \+ abort and atom bit
character complex cons continue eql error
float list logical-pathname member mod
muffle-warning not null pathname rational
store-value string use-value values vector /=
1- 1\+ < <= = > >= abs acons acos acosh adjoin
adjust-array adjustable-array-p alpha-char-p
alphanumericp append apply apropos
apropos-list aref arithmetic-error-operands
arithmetic-error-operation array-dimension
array-dimensions array-displacement
array-element-type array-has-fill-pointer-p
array-in-bounds-p array-rank
array-row-major-index array-total-size arrayp
ash asin asinh assoc assoc-if assoc-if-not
atan atanh bit-and bit-andc1 bit-andc2 bit-eqv
bit-ior bit-nand bit-nor bit-not bit-orc1
bit-orc2 bit-vector-p bit-xor boole
both-case-p boundp break
broadcast-stream-streams butlast byte
byte-position byte-size caaaar caaadr caaar
caadar caaddr caadr caar cadaar cadadr cadar
caddar cadddr caddr cadr call-next-method car
cdaaar cdaadr cdaar cdadar cdaddr cdadr cdar
cddaar cddadr cddar cdddar cddddr cdddr cddr
cdr ceiling cell-error-name cerror char
char-code char-downcase char-equal
char-greaterp char-int char-lessp char-name
char-not-equal char-not-greaterp
char-not-lessp char-upcase char/= char< char<=
char= char> char>= characterp cis class-of
clear-input clear-output close clrhash
code-char coerce compile compile-file
compile-file-pathname compiled-function-p
compiler-macro compiler-macro-function
complement complexp compute-restarts
concatenate concatenated-stream-streams
conjugate consp constantly constantp
copy-alist copy-list copy-pprint-dispatch
copy-readtable copy-seq copy-structure
copy-symbol copy-tree cos cosh count count-if
count-if-not decode-float
decode-universal-time delete delete-duplicates
delete-file delete-if delete-if-not
delete-package denominator deposit-field
describe describe-object digit-char
digit-char-p directory directory-namestring
disassemble documentation dpb dribble
echo-stream-input-stream
echo-stream-output-stream ed eighth elt
encode-universal-time endp enough-namestring
ensure-directories-exist
ensure-generic-function eq equal equalp eval
evenp every exp export expt fboundp fceiling
fdefinition ffloor fifth file-author
file-error-pathname file-length
file-namestring file-position
file-string-length file-write-date fill
fill-pointer find find-all-symbols find-class
find-if find-if-not find-package find-restart
find-symbol finish-output first float-digits
float-precision float-radix float-sign floatp
floor fmakunbound force-output format fourth
fresh-line fround ftruncate funcall
function-lambda-expression functionp gcd
gensym gentemp get get-decoded-time
get-dispatch-macro-character
get-internal-real-time get-internal-run-time
get-macro-character get-output-stream-string
get-properties get-setf-expansion
get-universal-time getf gethash graphic-char-p
hash-table-count hash-table-p
hash-table-rehash-size
hash-table-rehash-threshold hash-table-size
hash-table-test host-namestring identity
imagpart import input-stream-p inspect
integer-decode-float integer-length integerp
interactive-stream-p intern intersection
invalid-method-error invoke-debugger
invoke-restart invoke-restart-interactively
isqrt keywordp last lcm ldb ldb-test ldiff
length lisp-implementation-type
lisp-implementation-version list-all-packages
list-length list\* listen listp load
load-logical-pathname-translations log logand
logandc1 logandc2 logbitp logcount logeqv
logical-pathname-translations logior lognand
lognor lognot logorc1 logorc2 logtest logxor
long-site-name lower-case-p machine-instance
machine-type machine-version macro-function
macroexpand macroexpand-1 make-array
make-broadcast-stream make-concatenated-stream
make-condition make-dispatch-macro-character
make-echo-stream make-hash-table make-list
make-load-form-saving-slots make-package
make-pathname make-random-state make-sequence
make-string make-string-input-stream
make-string-output-stream make-symbol
make-synonym-stream make-two-way-stream
makunbound map map-into mapc mapcan mapcar
mapcon maphash mapl maplist mask-field max
member-if member-if-not merge merge-pathnames
method-combination-error min minusp mismatch
name-char namestring nbutlast nconc
next-method-p nintersection ninth notany
notevery nreconc nreverse nset-difference
nset-exclusive-or nstring-capitalize
nstring-downcase nstring-upcase nsublis nsubst
nsubst-if nsubst-if-not nsubstitute
nsubstitute-if nsubstitute-if-not nth nthcdr
numberp numerator nunion oddp open
open-stream-p output-stream-p
package-error-package package-name
package-nicknames package-shadowing-symbols
package-use-list package-used-by-list packagep
pairlis parse-integer parse-namestring
pathname-device pathname-directory
pathname-host pathname-match-p pathname-name
pathname-type pathname-version pathnamep
peek-char phase plusp position position-if
position-if-not pprint pprint-dispatch
pprint-fill pprint-indent pprint-linear
pprint-newline pprint-tab pprint-tabular prin1
prin1-to-string princ princ-to-string print
print-not-readable-object print-object
probe-file proclaim provide random
random-state-p rassoc rassoc-if rassoc-if-not
rationalize rationalp read read-byte read-char
read-char-no-hang read-delimited-list
read-from-string read-line
read-preserving-whitespace read-sequence
readtable-case readtablep realp realpart
reduce rem remhash remove remove-duplicates
remove-if remove-if-not remprop rename-file
rename-package replace require rest
restart-name revappend reverse room round
row-major-aref rplaca rplacd sbit scale-float
schar search second set set-difference
set-dispatch-macro-character set-exclusive-or
set-macro-character set-pprint-dispatch
set-syntax-from-char seventh shadow
shadowing-import short-site-name signal signum
simple-bit-vector-p
simple-condition-format-arguments
simple-condition-format-control
simple-string-p simple-vector-p sin sinh sixth
sleep slot-boundp slot-exists-p
slot-makunbound slot-value software-type
software-version some sort special-operator-p
sqrt stable-sort standard-char-p
stream-element-type stream-error-stream
stream-external-format streamp
string-capitalize string-downcase string-equal
string-greaterp string-left-trim string-lessp
string-not-equal string-not-greaterp
string-not-lessp string-right-trim string-trim
string-upcase string/= string< string<=
string= string> string>= stringp structure
sublis subseq subsetp subst subst-if
subst-if-not substitute substitute-if
substitute-if-not subtypep svref sxhash
symbol-function symbol-name symbol-package
symbol-plist symbol-value symbolp
synonym-stream-symbol tailp tan tanh tenth
terpri third translate-logical-pathname
translate-pathname tree-equal truename
truncate two-way-stream-input-stream
two-way-stream-output-stream type-error-datum
type-error-expected-type type-of typep
unbound-slot-instance unexport unintern union
unread-char unuse-package
upgraded-array-element-type
upgraded-complex-part-type upper-case-p
use-package user-homedir-pathname values-list
variable vector-pop vector-push
vector-push-extend vectorp warn
wild-pathname-p write write-byte write-char
write-line write-sequence write-string
write-to-string y-or-n-p yes-or-no-p zerop))
(mapcar #'ansi-generic-function '(add-method
allocate-instance change-class class-name
compute-applicable-methods find-method
function-keywords initialize-instance
make-instance make-instances-obsolete
make-load-form method-qualifiers
no-applicable-method no-next-method
reinitialize-instance remove-method
shared-initialize slot-missing slot-unbound
update-instance-for-different-class
update-instance-for-redefined-class))
(mapcar #'ansi-macro '(lambda or setf assert
call-method case ccase check-type cond
ctypecase decf declaim defclass defconstant
defgeneric define-compiler-macro
define-condition define-method-combination
define-modify-macro define-setf-expander
define-symbol-macro defmacro defmethod
defpackage defparameter defsetf defstruct
deftype defun defvar destructuring-bind do
do-all-symbols do-external-symbols do-symbols
do\* dolist dotimes ecase etypecase formatter
handler-bind handler-case ignore-errors
in-package incf loop loop-finish make-method
multiple-value-bind multiple-value-list
multiple-value-setq nth-value otherwise pop
pprint-exit-if-list-exhausted
pprint-logical-block pprint-pop
print-unreadable-object prog prog1 prog2
prog\* psetf psetq push pushnew remf
restart-bind restart-case return rotatef
shiftf step time trace typecase unless untrace
when with-accessors with-compilation-unit
with-condition-restarts
with-hash-table-iterator
with-input-from-string with-open-file
with-open-stream with-output-to-string
with-package-iterator with-simple-restart
with-slots with-standard-io-syntax))
(mapcar #'ansi-special-operator '(function block catch
eval-when flet go if labels let let\*
load-time-value locally macrolet
multiple-value-call multiple-value-prog1 progn
progv quote return-from setq symbol-macrolet
tagbody the throw unwind-protect))
(mapcar #'ansi-type '(array base-char base-string
bignum bit-vector boolean broadcast-stream
built-in-class class compiled-function
concatenated-stream double-float echo-stream
extended-char file-stream fixnum
generic-function hash-table integer keyword
long-float method number package random-state
ratio readtable real restart satisfies
sequence short-float signed-byte simple-array
simple-base-string simple-bit-vector
simple-string simple-vector single-float
standard-char standard-class
standard-generic-function standard-method
standard-object stream string-stream
structure-class structure-object symbol
synonym-stream two-way-stream unsigned-byte))
(mapcar #'ansi-unknown
'(method-combination))
(mapcar #'ansi-global-variable '(// /// \*\* \*\*\*
\*break-on-signals\* \*compile-file-pathname\*
\*compile-file-truename\* \*compile-print\*
\*compile-verbose\* \*debug-io\*
\*debugger-hook\*
\*default-pathname-defaults\* \*error-output\*
\*features\* \*gensym-counter\*
\*load-pathname\* \*load-print\*
\*load-truename\* \*load-verbose\*
\*macroexpand-hook\* \*modules\* \*package\*
\*print-array\* \*print-base\* \*print-case\*
\*print-circle\* \*print-escape\*
\*print-gensym\* \*print-length\*
\*print-level\* \*print-lines\*
\*print-miser-width\*
\*print-pprint-dispatch\* \*print-pretty\*
\*print-radix\* \*print-readably\*
\*print-right-margin\* \*query-io\*
\*random-state\* \*read-base\*
\*read-default-float-format\* \*read-eval\*
\*read-suppress\* \*readtable\*
\*standard-input\* \*standard-output\*
\*terminal-io\* \*trace-output\* \+\+ \+\+\+))
(mapcar #'ansi-expression
'(declare))
)))))
End of Line.