9
\$\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
    \$\begingroup\$ xkcd.com/297 \$\endgroup\$ – DJMcMayhem May 10 '16 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 '16 at 0:09
  • 1
    \$\begingroup\$ I would advise using tinylisp, a smaller, stripped-down version of Lisp for your golfing pleasure. \$\endgroup\$ – ckjbgames Feb 1 '17 at 23:12
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\$
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\$
  • \$\begingroup\$ I don't understand this. Isn't 1+ parsed as two tokens, 1 and +? I thought it was +1. \$\endgroup\$ – Esolanging Fruit Apr 24 '17 at 7:19
  • \$\begingroup\$ @Challenger5 1+ and 1- are parsed as a single token Common Lisp HyperSpec Function 1+, 1- \$\endgroup\$ – ceilingcat May 18 '17 at 3:59
  • \$\begingroup\$ I thought that names couldn't start with digits? \$\endgroup\$ – Esolanging Fruit May 18 '17 at 6:58
  • \$\begingroup\$ @EsolangingFruit this is Lisp... \$\endgroup\$ – ASCII-only May 18 '18 at 7:51
1
\$\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\$

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\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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