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
#e
prefix 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
/cdr
calls 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
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~@(
capitalizes the first character that appears in Scheme (if it can be), but the first letter in Common Lisp~r
includes the word "and" after the hundreds place in Common Lisp (which is what the hole requires), but not in Scheme~@[
and~:[
check for#f
in Scheme butnil
in Common Lisp; this is notable since Scheme has a distinctvoid
type- 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.