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.

DLosc
40.7k6 gold badges87 silver badges142 bronze badges
asked May 10, 2016 at 22:50
\$\endgroup\$
3
  • 4
    \$\begingroup\$ xkcd.com/297 \$\endgroup\$ Commented 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\$ Commented 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\$ Commented 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)
answered Mar 17, 2017 at 6:18
\$\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

answered Dec 15, 2018 at 6:42
\$\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.

answered Mar 17, 2017 at 8:28
\$\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).

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

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.