Basic tips
{and}are special names that break up tokens without needing whitespace:(let(({1)(}2))(+{})instead of(let((a 1)(b 2))(+ a b)- Symbols can sometimes be used instead of strings:
(display'Foo)instead of(display"Foo") - Use
(cdr(command-line))instead of(command-line-arguments) (length(memq(…)(…)))can be used to find the index of an item in a list- The
#eprefix converts float literals to exact integers/rationals.
Many tips from the Common Lisp page also apply to Scheme. Some general differences worth remembering when attempting to port from one to the other:
- Scheme raises an error on invalid
car/cdrcalls or other element accesses, while Common Lisp returnsnil. - Scheme is a Lisp-1 (variables and functions are in the same scope), while Common Lisp is a Lisp-2 (variables and functions are separated)
- Scheme does not casefold symbols, while Common Lisp pretends everything is uppercase
- Scheme is very picky about sequence typing, while most Common Lisp functions that accept lists can accept any sequence type
- Scheme and Common Lisp use nearly the same format strings (see the dedicated section below)
- Scheme's parser is generally looser than Common Lisp with regards to whitespace and syntax transformations
- Scheme allows sharpsign macros to be defined at any invocation, while Common Lisp requires them to be defined at their first appearance
Looping
Looping over a range
The most generic and powerful iteration construct in Scheme is do:
;; Add all numbers between 1 and 10:
(do ((i 1 (1+ i))
(sum 0 (+ sum i)))
((> i 10) sum) ; if i>10: break and return sum (55)
(display sum)
(newline))
See the Common Lisp page or the Chez Scheme User Guide for more details and use cases.
If looping from 0 to n-1, you might consider (iota n) or (enumerate ls) (equivalent to (iota (length ls))) in conjunction with the list iteration strategies below.
Looping over a list
There are several ways one can loop over a list, perform some operation, and output the results. Here are a few ways one could print all the arguments to a hole in uppercase:
(do((a(cdr(command-line))(cdr a)))((null? a))(printf"~a~n"(string-upcase(car a))))
(for-each(lambda(a)(printf"~a~n"(string-upcase a)))(cdr(command-line)))
(printf"~{~a~n~}"(map(lambda(a)(string-upcase a))(cdr(command-line))))
(andmap(lambda(a)(printf"~a~n"(string-upcase a)))(cdr(command-line)))
(memp(lambda(a)(printf"~a~n"(string-upcase a))#f)(cdr(command-line)))
(printf"~{~a~n~}"(map string-upcase(cdr(command-line))))
(printf"~:@(~{~a~n~}~)"(cdr(command-line)))
Note that andmap and memp above cannot be replaced by map, as map does not necessarily iterate over its arguments in order.
Splitting a string
The shortest way to split a string on spaces:
(read(open-input-string(format"(~a)"x)))
This yields a list of numbers and symbols, the latter of which can be converted to strings via symbol->string. If you process the split items in-order, you may instead make use of repeated read calls (without format). If you need to split on something besides spaces, try using memq.
Format strings
printf and format use Lisp format directives, which are very powerful for golfing.
; Scheme
(printf "string")
(format "string")
(format condition "string")
; Lisp
(format t "string")
(format nil "string")
(format condition "string")
However, there are some minor differences between Common Lisp and Scheme's implementations:
~[accepts any type in Scheme, but only integers in Common Lisp- Alignment parameters such as
~vaaccept any numeric type in Common Lisp, but only integers in Scheme ~@(capitalizes the first character that appears in Scheme (if it can be), but the first letter in Common Lisp~rincludes the word "and" after the hundreds place in Common Lisp (which is what the hole requires), but not in Scheme~@[and~:[check for#fin Scheme butnilin Common Lisp; this is notable since Scheme has a distinctvoidtype- Count arguments like
~v%must be non-negative in Scheme, while Common Lisp treats negatives like zero ~^terminates the current iteration step of~{in Scheme, while in Common Lisp the entire iteration is ended- Three-argument
~^is not supported in Scheme (which seemingly contradicts the spec) - Justification with
~<~>always inserts spaces starting on the left in Common Lisp, but "balances" the left and right ends in Scheme - As stated in the CSUG, Lisp pretty printer operations are not supported by Scheme
2:1 Packer (written in Ruby)
print '(eval(read(open-input-string(utf8->string(string->utf16"',
"(display 10)".encode('utf-8', 'utf-16be'),
'")))))'
Reference
- The Chez Scheme Summary of Forms is an alphabetical list of functions and syntactic elements.