12
\$\begingroup\$

What general tips are these for golfing in Lisp (any dialect)? Please post one tip per answer, and only answers that are specific to a dialect of Lisp (e.g. "remove comments" is not an answer).

Please post the dialect of Lisp your tip applies to with your tip.

\$\endgroup\$
3
  • 4
    \$\begingroup\$ xkcd.com/297 \$\endgroup\$
    – DJMcMayhem
    May 10, 2016 at 23:50
  • 1
    \$\begingroup\$ Do you imagine these will be distinct from the tips for golfing in Scheme and Racket? \$\endgroup\$
    – Alex A.
    May 11, 2016 at 0:09
  • 2
    \$\begingroup\$ I would advise using tinylisp, a smaller, stripped-down version of Lisp for your golfing pleasure. \$\endgroup\$
    – ckjbgames
    Feb 1, 2017 at 23:12

5 Answers 5

4
\$\begingroup\$

Order function parameters to minimize whitespace

Instead of

(defun f(a b)(...))
...
(f x(1+ y))

try something like

(defun f(b a)(...))
...
(f(1+ y)x)
\$\endgroup\$
4
\$\begingroup\$

Conditional Output

GNU Common Lisp

~v^

The up-and-out directive ~^ is most commonly used in a list formatting operation to terminate after the last list item. However, it can also be used with a v modifier to consume an argument, in which case it terminates if that argument is zero. This is particularly useful for dealing with the zero produced by dotimes.

(loop as n from 1 to 10 do(format t"~d~%"n))

(dotimes(n 11)(if(> n 0)(format t"~d~%"n)))

(dotimes(n 11)(format t"~v^~d~%"n n))

format(condition)

The first argument to format can be one of t, nil a.k.a. (), or a stream. If passed t, it will output to stdout, if nil it will return the formatted output as a string. This can be used conditionally output. The above example could be written equally as short as:

(dotimes(n 11)(format(> n 0)"~d~%"n))

If a value was output, the return value will be nil. Because of this, it can also be used as the terminating condition for a do loop:

(do((n 11))((<(decf n)1))(format t"~d~%"n))

(do((n 11))((format(>(decf n)0)"~d~%"n)))

~[...~]

The conditional formatter consumes an argument, and selects a formatting string from a list by index. A common use case is with the default formatter ~:; to select between zero and not zero.

(dotimes(n 11)(format t"~v^~[~r~:;~d~]~%"n(mod n 3)n))

Conditional formatters can also be nested, in which case each will consume an argument in turn.


~&

In each of the examples above, ~% is used to emit a newline. In most cases, this could be replaced by a literal newline. Another option is to use ~&, which will emit a newline if and only if the output cursor is not at the start of a line, a.k.a. a fresh-line.

Both ~% and ~& can also take an argument, with a v modifier or as a constant, and will produce as many newlines. They will also both happily accept a negative argument, in which case they emit nothing.


External References

Practical Common Lisp
18. A Few FORMAT Recipes

Common Lisp the Language, 2nd Edition
22.3.3. Formatted Output to Character Streams

\$\endgroup\$
2
\$\begingroup\$

Use loop and format, which is like printf on steroids. format includes iteration and conditions, as well as roman numerals, English numbers and English plurals. It is very, very ugly, and very compact.

\$\endgroup\$
1
\$\begingroup\$

Print strings consisting of capital letters via printing atoms

The princ function in Common Lisp is short, and will print objects without escape characers. If you print Common Lisp symbols, which have the synax 'symbol-name, this saves you from needing quotes around what you want to print, and can also save on whitespace. Note that when printing symbols, they will be capitalized. Also, it does not add a newline or a space, so you don't need concatenation.

For example,

(princ'hai)

will print HAI.

And

(princ'hai)(princ(read))

will print HAI, ask for input, and print it back out, e.g. if you type hello, the result is

HAIhellohello
\$\endgroup\$
1
\$\begingroup\$

Use 1+ and 1- for increment and decrement

Instead of (+ a 1) or (- b 1) try (1+ a) or (1- b).

\$\endgroup\$
4
  • \$\begingroup\$ I don't understand this. Isn't 1+ parsed as two tokens, 1 and +? I thought it was +1. \$\endgroup\$ Apr 24, 2017 at 7:19
  • \$\begingroup\$ @Challenger5 1+ and 1- are parsed as a single token Common Lisp HyperSpec Function 1+, 1- \$\endgroup\$
    – ceilingcat
    May 18, 2017 at 3:59
  • \$\begingroup\$ I thought that names couldn't start with digits? \$\endgroup\$ May 18, 2017 at 6:58
  • \$\begingroup\$ @EsolangingFruit this is Lisp... \$\endgroup\$
    – ASCII-only
    May 18, 2018 at 7:51

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.