The material on this page is licensed under the terms of the GNU Free Documentation License. See scheme-faq-license for more information about this.
general | language | macros | misc | programming | standards
R5RS states that identifiers and symbols read via the Scheme reader (i.e. when reading Scheme programs) are case-insensitive and may get their case changed. Hence (eq? 'a 'A) is the same as (EQ? 'a 'A) and returns #t. Note though that it is considered bad style to write programs that rely on this, e.g. by defining a function foo and then calling it using (Foo) or (FOO).
Symbols created using string->symbol retain their case:
(eq? (string->symbol "a") (string->symbol "A")) ;=> #f
Therefore, when the case of symbols is important, e.g. when treating them as part of data rather than programs, one needs to use string->symbol instead of literal symbols. Some Schemes have some syntactic sugar for writing case-preserving symbol literals, e.g. symbols enclosed in vertical bars ('|FooBar|) are considered to be case-sensitive. The same Schemes (and some others) also allow you to set a flag which makes the reader case-sensitive (or case-insensitive, if being case-sensitive is the default). Any Scheme that supports DSSSL (see here) must have a case-sensitive reader mode since DSSSL is case-sensitive. Check out http://metapaper.net/lisovsky/scheme/casesens/index.html for a list of Schemes and their case-sensitivity behaviour.
Oleg has written a low-level macro that evaluates '"FooBar" inside the body of the macro as (string->symbol "FooBar") at compile time. See http://pobox.com/~oleg/ftp/Scheme/universally-CooL-symbols.html for details.
Petrofsky offered an alternative, more portable solution that uses standard R5RS macros to translates occurrences of string literals in quote, quasiquote and case at run time:
(define-syntax run-test (syntax-rules () ((_ (q (qq case)) . tests) (letrec-syntax ((q (syntax-rules (q) ((_ x) (generic-quote q x)))) (qq (syntax-rules (q qq unquote unquote-splicing) ((_ ,x) x) ((_ (,@x . y)) (append x (qq y))) ((_ (qq x) . depth) (list 'qq (qq x depth))) ((_ ,x depth) (list 'unquote (qq x . depth))) ((_ ,@x depth) (list 'unquote-splicing (qq x . depth))) ((_ x . depth) (generic-quote qq x . depth)))) (generic-quote (syntax-rules (q) ((_ q/qq (q x) . rest) (cond ((string? 'x) (string->symbol 'x)) (else (cons 'q (q/qq (x) . rest))))) ((_ q/qq (x . y) . rest) (cons (q/qq x . rest) (q/qq y . rest))) ((_ . rest) (run-test "dots" . rest)))) (case (syntax-rules (else) ((_ (x . y) . clauses) (let ((key (x . y))) (case key . clauses))) ((_ key) 'unspecified) ((_ key (else . exps)) (begin . exps)) ((_ key (atoms . exps) . clauses) (cond ((memv key (q atoms)) . exps) (else (case key . clauses))))))) (begin . tests))) ;; These rules need to be out here because of r5rs ellipsis shortcomings. ((_ "dots" q/qq #(elt ...) . rest) (list->vector (q/qq (elt ...) . rest))) ((_ "dots" q/qq x . rest) 'x)))
The use of dots in function application is not part of the R5RS grammar but, like most error situations, Schemes are allowed to do whatever they like when encountering such a construct, including interpreting it as (apply foo bar baz). No known Schemes do this and in any case such code would not be portable.
Note, however, that most Schemes expand literal lists occurring in function applications, e.g. (foo bar . (1 2 3)) is expanded into (foo bar 1 2 3) by the reader. It is not entirely clear whether this is a consequence of the standard - the notation is not part of the R5RS grammar but there is strong evidence to suggest a Scheme implementation cannot comply with all of R5RS without performing this transformation.
The short answer: No.
The long answer: There are several different contexts in which you may want to use so-called "degenerate" dotted lists:
Instead of (lambda (. foo) ...) you must write (lambda foo ...) Some Schemes are lenient and accept the former notation.
You might expect (let ((app (list foo bar baz))) (. app)) to be equivalent to (foo bar baz) but this is not the case. Instead you have to write something along the lines of (let ((app (list foo bar baz))) (apply (car app) (cdr app))) See here for a related issue.
You cannot write '(. foo) Note however that `(,@'() . foo) is legal and yields 'foo.
Some Schemes allow you to use square brackets (i.e. ) interchangeably with parentheses in order to enhance the visual representation of Scheme code, e.g.
(let ([foo (f1)] [bar (f2)]) (baz foo bar) (+ foo bar))
R5RS states that square brackets are "reserved characters". However, the standard does not specify what an implementation is supposed to do when encountering reserved characters. Thus, Schemes using the above convention are standards-compliant, but code written for them may not be readable by other implementations.
The Scheme standard allows the specification of rest arguments via a dotted parameter list notation, which, with some work, can also be employed to handle optional arguments:
(define (opt-arg args n default) (if (< n (length args)) (list-ref args n) default)) ;;example (define (foo . args) (let ((x (opt-arg args 0 #f)) (y (opt-arg args 1 '()))) (cons x y))) (foo) ;=> '(#f) (foo 1) ;=> '(1) (foo 1 '(2 3)) ;=> '(1 2 3)
Since extracting the arguments this way can be a bit cumbersome, SRFI-16 and several Schemes offer a case-lambda macro, originally invented by Kent Dybvig and Bob Hieb:
(define foo (case-lambda ((x) "no additional args") ((x y) "1 additional arg") ((x y z) "2 additional args") ((x . any) "even more additional args")))
Optional arguments with defaults can be handled by DSSSL-style parameter lists that are supported by some Schemes:
(define foo (lambda (x #!optional (y 2) (z 3) #!rest rest) (apply + x y z rest))) (foo 1) ;=> 6 (foo 1 1) ;=> 5 (foo 1 1 1) ;=> 3 (foo 1 1 1 1) ;=> 4
In these Schemes it is also possible to define keyword arguments:
(define foo (lambda (x #!key (y 2) (z 3)) (+ x y z))) (foo 1) ;=> 6 (foo 1 y: 1) ;=> 5 (foo 1 z: 1) ;=> 4
There are two ways to do this in standard Scheme. The most obvious one is to return a list, e.g.
(define (foo) (list 1 2)) (let ((r (foo))) (let ((res1 (car r)) (res2 (cadr r))) ...))
The problem with the above is that there is no obvious syntactic distinction between returning multiple values and returning a single list value. This is not only aesthetically unpleasant but prevents any optimisation that could otherwise be applied. Furthermore, extracting the results from the list is cumbersome. Scheme therefore has a set of constructs specifically designed to deal with multiple return values: call-with-values and values. Using them the above program can be rewritten as follows:
(define (foo) (values 1 2)) (call-with-values foo (lambda (res1 res2) ...))
SRFI-11 provides some syntactic sugar in the form of let-values and let*-values constructs that reduce the clutter resulting from using call-with-values:
(define (foo) (values 1 2)) (let-values (((x y) (foo))) ...)
Some Schemes extend the SRFI by providing letrec-values and letrec*-values. Petrofsky has come up with another extension - "named"let-values which operates analogous to named let:
(define-syntax let-values (syntax-rules () ((_ (mvbinding ...) . body) (let-values foo (mvbinding ...) . body)) ((_ name () . body) (let name () . body)) ((_ name ((vars mv) . mvbindings) . body) (call-with-values (lambda () mv) (lambda temp (apply (let-values name mvbindings (lambda vars (let-syntax ((name (syntax-rules () ((_ arg . args) (call-with-values (lambda () arg) (lambda temp (apply (name . args) temp))))))) . body))) temp))))))
Some Schemes support the notion of "boxing":
(define (foo x) (set-box! x (+ (unbox x) 1))) (let ((v (box 1))) (foo v) (unbox v)) ;=> 2
The observant reader will have noticed that the above is just syntactic sugar - boxes can be implemented using lists, in which case box is list, unbox is car, and set-box! is set-car!. However, implementing boxes natively is more efficient than using lists.
Here is a definition of curry that takes a function and number of parameters as an argument and returns a curried function that can be invoked with any number of arguments up to the specified number of parameters:
(define (curry f n) (if (zero? n) (f) (lambda args (curry (lambda rest (apply f (append args rest))) (- n (length args)))))) (define foo (curry + 4)) ((((foo 1) 2) 3) 4) ;=> 10 ((foo 1 2 3) 4) ;=> 10 (foo 1 2 3 4) ;=> 10
In Common Lisp, the defun construct always creates a top-level definition, e.g.
(let ((counter 0)) (defun inc-counter-by (n) (incr counter n)) (defun inc-counter () (inc-counter-by 1)) (defun counter-value () counter))
The naive translation into Scheme
(let ((counter 0)) (define (inc-counter-by n) (set! counter (+ counter n))) (define (inc-counter) (inc-counter-by 1)) (define (counter-value) counter))
does not work, because the defines establish local definitions rather than top-level definitions. Instead the following needs to be used:
(define inc-counter-by #f) (define inc-counter #f) (define counter-value #f) (let ((counter 0)) (set! inc-counter-by (lambda (n) (set! counter (+ counter n)))) (set! inc-counter (lambda () (inc-counter-by 1))) (set! counter-value (lambda () counter)))
For defining just a single top-level closure this can be shortened to
(define inc-counter (let ((counter 0)) (lambda () (set! counter (+ counter 1)))))
In Schemes that support define-values (see here) the following construction, which is very close to the Common Lisp original, can be used:
(define-values (inc-counter-by inc-counter counter-value) (let ((counter 0)) (define (inc-counter-by n) (set! counter (+ counter n))) (define (inc-counter) (inc-counter-by 1)) (define (counter-value) counter) (values inc-counter-by inc-counter counter-value)))
The only standardized way of introducing top-level definitions is via a define construct (or the application of a macro that expands into one) at the top-level. This is essentially a static binding since it is not possible to dynamically decide whether to establish the binding, or what identifier to bind.
Some Schemes provide means of programmatically inspecting and modifying the top-level environment, thus making it possible to dynamically establish new bindings. In R5RS Schemes the following trick can be used:
(eval `(define ,name ,value) (interaction-environment))
but note that in R5RS the function interaction-environment is optional, eval is only required to evaluate expressions, not definitions, and the standard is rather unclear about exactly what environment interaction-environment represents. Also, if the value of the binding is a procedure or something else not allowed in a quote expression, the above needs to be modified as follows:
((eval `(begin (define ,name #f) (lambda (val) (set! ,name val))) (interaction-environment)) value)
Section 3.4 of R5RS states that it is an error to attempt to modify an immutable object, such as a literal list. Not all Schemes report this as an error though and instead do modify the literal list, e.g.
(define (foo) '(1 2 3)) (foo) ;=> (1 2 3) (set-car! (foo) 0) (foo) ;=> (0 2 3)
The question is answered in section 6.4 of R5RS: "Except for continuations created by the call-with-values procedure, all continuations take exactly one value.". Therefore, Schemes are not required to accept multi-values expressions at the top-level or inside a body other than in the last position. However, they can certainly choose to do so.
The Scheme standard has little to say on this matter. Most Schemes do perform garbage-collection of symbols, since otherwise programs using string->symbol to dynamically create symbols would consume ever increasing amounts of memory even if the created symbols are no longer being used.
The shorthand syntax of quasiquotation, i.e. the use of `<expression>, ,<expression> and ,@<expression>, must be recognized by the Scheme reader and translated into the equivalent (quasiquote <expression>), (unquote <expression;>) and (unquote-splicing <expression>) respectively - this is mandated by section 4.2.6 of R5RS and cannot be done by a macro.
The "long hand" syntax can indeed be implemented in terms of macros that transform them into expressions that construct lists and vectors:
(define-syntax quasiquote (syntax-rules (unquote unquote-splicing quasiquote) ((_ (unquote form)) form) ((_ ((unquote-splicing form) . rest)) (append form (quasiquote rest))) ((_ (quasiquote form) . depth) (list 'quasiquote (quasiquote form #f . depth))) ((_ (unquote form) x . depth) (list 'unquote (quasiquote form . depth))) ((_ (unquote-splicing form) x . depth) (list 'unquote-splicing (quasiquote form . depth))) ((_ (car . cdr) . depth) (cons (quasiquote car . depth) (quasiquote cdr . depth))) ((_ #(elt ...) . depth) (list->vector (quasiquote (elt ...) . depth))) ((_ atom . depth) 'atom)))
The expansion is not "optimal" - it does not exploit Scheme's abilitity to represent constant lists and vectors as literals. It is possible to write a macro that does that, but it is rather long and hence not included here.
Firstly, eval should only be used when its absolutely necessary - "eval is evil" is a common saying among Schemers. Beginners often make the mistake of employing eval when a combination of closures, quasiquotation and macros would achieve the same effect.
There are however some cases where eval is the only option of accomplishing a particular task - see for instance here for examples. eval only became a mandatory part of the Scheme standard with the R5RS revision. Hence some Schemes do not support it. Petrofsky posted an implementation of eval in Scheme itself - see http://groups.google.com/groups?selm=876617n453.fsf%40radish.petrofsky.org - and it should be possible to retrofit this to existing Schemes that do not have eval.
Scheme keywords, i.e. keywords featured in primitive expression types such as lambda and derived expression types such as cond can be redefined or shadowed by a syntax definition, e.g.
(let-syntax ((lambda (syntax-rules () ((_ (x) . body) (lambda x . body))))) ((lambda (x) x) 'foo 'bar)) ;=>'(foo bar)
Note that it is not possible for top-level redefinitions to access to original definitions, e.g. an attempt to convert the above examples into global redefinitions of lambda using define-syntax would fail.
According to the formal definition in R5RS of the lexical structure of Scheme it is a illegal to redefine or shadow a Scheme keyword to/with anything other than syntax, i.e. Scheme keywords must not appear on the left-hand-side of define, set!, and in the formal parameter list of lambda, and in derived syntax like let and letrec. However, the R5RS authors acknowledge that that this restriction is in fact a remnant of earlier versions of the standard and no longer applies.