Related
I know that you can use ' (aka quote) to create a list, and I use this all the time, like this:
> (car '(1 2 3))
1
But it doesn’t always work like I’d expect. For example, I tried to create a list of functions, like this, but it didn’t work:
> (define math-fns '(+ - * /))
> (map (lambda (fn) (fn 1)) math-fns)
application: not a procedure;
expected a procedure that can be applied to arguments
given: '+
When I use list, it works:
> (define math-fns (list + - * /))
> (map (lambda (fn) (fn 1)) math-fns)
'(1 -1 1 1)
Why? I thought ' was just a convenient shorthand, so why is the behavior different?
TL;DR: They are different; use list when in doubt.
A rule of thumb: use list whenever you want the arguments to be evaluated; quote “distributes” over its arguments, so '(+ 1 2) is like (list '+ '1 '2). You’ll end up with a symbol in your list, not a function.
An in-depth look at list and quote
In Scheme and Racket, quote and list are entirely different things, but since both of them can be used to produce lists, confusion is common and understandable. There is an incredibly important difference between them: list is a plain old function, while quote (even without the special ' syntax) is a special form. That is, list can be implemented in plain Scheme, but quote cannot be.
The list function
The list function is actually by far the simpler of the two, so let’s start there. It is a function that takes any number of arguments, and it collects the arguments into a list.
> (list 1 2 3)
(1 2 3)
This above example can be confusing because the result is printed as a quoteable s-expression, and it’s true, in this case, the two syntaxes are equivalent. But if we get slightly more complicated, you’ll see that it is different:
> (list 1 (+ 1 1) (+ 1 1 1))
(1 2 3)
> '(1 (+ 1 1) (+ 1 1 1))
(1 (+ 1 1) (+ 1 1 1))
What’s going on in the quote example? Well, we’ll discuss that in a moment, but first, take a look at list. It’s just an ordinary function, so it follows standard Scheme evaluation semantics: it evaluates each of its arguments before they get passed to the function. This means that expressions like (+ 1 1) will be reduced to 2 before they get collected into the list.
This behavior is also visible when supplying variables to the list function:
> (define x 42)
> (list x)
(42)
> '(x)
(x)
With list, the x gets evaluated before getting passed to list. With quote, things are more complicated.
Finally, because list is just a function, it can be used just like any other function, including in higher-order ways. For example, it can be passed to the map function, and it will work appropriately:
> (map list '(1 2 3) '(4 5 6))
((1 4) (2 5) (3 6))
The quote form
Quotation, unlike list, is a special part of Lisps. The quote form is special in part because it gets a special reader abbreviation, ', but it’s also special even without that. Unlike list, quote is not a function, and therefore it does not need to behave like one—it has rules of its own.
A brief discussion of Lisp source code
In Lisp, of which Scheme and Racket are derivatives, all code is actually made up of ordinary data structures. For example, consider the following expression:
(+ 1 2)
That expression is actually a list, and it has three elements:
the + symbol
the number 1
the number 2
All of these values are normal values that can be created by the programmer. It’s really easy to create the 1 value because it evaluates to itself: you just type 1. But symbols and lists are harder: by default, a symbol in the source code does a variable lookup! That is, symbols are not self-evaluating:
> 1
1
> a
a: undefined
cannot reference undefined identifier
As it turns out, though, symbols are basically just strings, and in fact we can convert between them:
> (string->symbol "a")
a
Lists do even more than symbols, because by default, a list in the source code calls a function! Doing (+ 1 2) looks at the first element in the list, the + symbol, looks up the function associated with it, and invokes it with the rest of the elements in the list.
Sometimes, though, you might want to disable this “special” behavior. You might want to just get the list or get the symbol without it being evaluated. To do this, you can use quote.
The meaning of quotation
With all this in mind, it’s pretty obvious what quote does: it just “turns off” the special evaluation behavior for the expression that it wraps. For example, consider quoteing a symbol:
> (quote a)
a
Similarly, consider quoteing a list:
> (quote (a b c))
(a b c)
No matter what you give quote, it will always, always spit it back out at you. No more, no less. That means if you give it a list, none of the subexpressions will be evaluated—do not expect them to be! If you need evaluation of any kind, use list.
Now, one might ask: what happens if you quote something other than a symbol or a list? Well, the answer is... nothing! You just get it back.
> (quote 1)
1
> (quote "abcd")
"abcd"
This makes sense, since quote still just spits out exactly what you give it. This is why “literals” like numbers and strings are sometimes called “self-quoting” in Lisp parlance.
One more thing: what happens if you quote an expression containing quote? That is, what if you “double quote”?
> (quote (quote 3))
'3
What happened there? Well, remember that ' is actually just a direct abbreviation for quote, so nothing special happened at all! In fact, if your Scheme has a way to disable the abbreviations when printing, it will look like this:
> (quote (quote 3))
(quote 3)
Don’t be fooled by quote being special: just like (quote (+ 1)), the result here is just a plain old list. In fact, we can get the first element out of the list: can you guess what it will be?
> (car (quote (quote 3)))
quote
If you guessed 3, you are wrong. Remember, quote disables all evaluation, and an expression containing a quote symbol is still just a plain list. Play with this in the REPL until you are comfortable with it.
> (quote (quote (quote 3)))
''3
(quote (1 2 (quote 3)))
(1 2 '3)
Quotation is incredibly simple, but it can come off as very complex because of how it tends to defy our understanding of the traditional evaluation model. In fact, it is confusing because of how simple it is: there are no special cases, there are no rules. It just returns exactly what you give it, precisely as stated (hence the name “quotation”).
Appendix A: Quasiquotation
So if quotation completely disables evaluation, what is it good for? Well, aside from making lists of strings, symbols, or numbers that are all known ahead of time, not much. Fortunately, the concept of quasiquotation provides a way to break out of the quotation and go back into ordinary evaluation.
The basics are super simple: instead of using quote, use quasiquote. Normally, this works exactly like quote in every way:
> (quasiquote 3)
3
> (quasiquote x)
x
> (quasiquote ((a b) (c d)))
((a b) (c d))
What makes quasiquote special is that is recognizes a special symbol, unquote. Wherever unquote appears in the list, then it is replaced by the arbitrary expression it contains:
> (quasiquote (1 2 (+ 1 2)))
(1 2 (+ 1 2))
> (quasiquote (1 2 (unquote (+ 1 2))))
(1 2 3)
This lets you use quasiquote to construct templates of sorts that have “holes” to be filled in with unquote. This means it’s possible to actually include the values of variables inside of quoted lists:
> (define x 42)
> (quasiquote (x is: (unquote x)))
(x is: 42)
Of course, using quasiquote and unquote is rather verbose, so they have abbreviations of their own, just like '. Specifically, quasiquote is ` (backtick) and unquote is , (comma). With those abbreviations, the above example is much more palatable.
> `(x is: ,x)
(x is: 42)
One final point: quasiquote actually can be implemented in Racket using a rather hairy macro, and it is. It expands to usages of list, cons, and of course, quote.
Appendix B: Implementing list and quote in Scheme
Implementing list is super simple because of how “rest argument” syntax works. This is all you need:
(define (list . args)
args)
That’s it!
In contrast, quote is a lot harder—in fact, it’s impossible! It would seem totally feasible, since the idea of disabling evaluation sounds a lot like macros. Yet a naïve attempt reveals the trouble:
(define fake-quote
(syntax-rules ()
((_ arg) arg)))
We just take arg and spit it back out... but this doesn’t work. Why not? Well, the result of our macro will be evaluated, so all is for naught. We might be able to expand to something sort of like quote by expanding to (list ...) and recursively quoting the elements, like this:
(define impostor-quote
(syntax-rules ()
((_ (a . b)) (cons (impostor-quote a) (impostor-quote b)))
((_ (e ...)) (list (impostor-quote e) ...))
((_ x) x)))
Unfortunately, though, without procedural macros, we can’t handle symbols without quote. We could get closer using syntax-case, but even then, we would only be emulating quote’s behavior, not replicating it.
Appendix C: Racket printing conventions
When trying the examples in this answer in Racket, you may find that they do not print as one would expect. Often, they may print with a leading ', such as in this example:
> (list 1 2 3)
'(1 2 3)
This is because Racket, by default, prints results as expressions when possible. That is, you should be able to type the result into the REPL and get the same value back. I personally find this behavior nice, but it can be confusing when trying to understand quotation, so if you want to turn it off, call (print-as-expression #f), or change the printing style to “write” in the DrRacket language menu.
The behavior you are seeing is a consequence of Scheme not treating symbols as functions.
The expression '(+ - * /) produces a value which is a list of symbols. That's simply because (+ - * /) is a list of symbols, and we are just quoting it to suppress evaluation in order to get that object literally as a value.
The expression (list + - * /) produces a list of functions. This is because it is a function call. The symbolic expressions list, +, -, * and / are evaluated. They are all variables which denote functions, and so are reduced to those functions. The list function is then called, and returns a list of those remaining four functions.
In ANSI Common Lisp, calling symbols as functions works:
[1]> (mapcar (lambda (f) (funcall f 1)) '(+ - * /))
(1 -1 1 1)
When a symbol is used where a function is expected, the top-level function binding of the symbol is substituted, if it has one, and everything is cool. In effect, symbols are function-callable objects in Common Lisp.
If you want to use list to produce a list of symbols, just like '(+ - * /), you have to quote them individually to suppress their evaluation:
(list '+ '- '* '/)
Back in the Scheme world, you will see that if you map over this, it will fail in the same way as the original quoted list. The reason is the same: trying to use a symbol objects as a functions.
The error message you are being shown is misleading:
expected a procedure that can be applied to arguments
given: '+
This '+ being shown here is (quote +). But that's not what the application was given; it was given just +, the issue being that the symbol object + isn't usable as a function in that dialect.
What's going on here is that the diagnostic message is printing the + symbol in "print as expression" mode, a feature of Racket, which is what I guess you're using.
In "print as expression" mode, objects are printed using a syntax which must be read and evaluated to produce a similar object. See the StackOverflow question "Why does the Racket interpreter write lists with an apostroph before?"
Suppose I have a list of arguments args and a macro/syntax f that takes a variable number of arguments. How do I apply f to args? Apparently apply doesn't work here.
For example, suppose I have a list of values bs and I want to know if they're all true, so I try (apply and bs) but I get the error "and: bad syntax". The workaround I came up with is (eval `(and . ,bs)) but I'm wondering if there is some standard way to achieve this sort of thing.
Update
A bunch of possible duplicates have been suggested, but most of them are just about the and example. This suggested question seems to be the same as mine, but the answer there is not very helpful: it basically says "don't do this!".
So maybe the point is that in practice this "apply + macro" question only comes up for macros like and and or, and there is no useful general question? I certainly ran into this issue with and, and don't have much Scheme experience, certainly no other examples of this phenomenon.
This is an XY problem. Macros are part of the syntax of the language: they're not functions and you can't apply them to arguments. Conceptually, macros are like functions which map source code to other source code, and which are called at compile time, not run time: trying to use them at run time is a category error. (In Common Lisp macros are, quite literally, functions which map source code to other source code: in Scheme I'm not quite so clear about that).
So if you have a list and you want to know if all its elements are true, you call a function on the list to do that.
It's easy to write such a function:
(define (all-true? things)
(cond [(null? things)
#t]
[(first things)
(all-true? (rest things))]
[else #f]))
However Racket provides a more general function: andmap: (andmap identity things) will either return false if one of things is not true, or it will return the value of the last thing in the list (or #t if the list is empty). (andmap (lambda (x) (and (integer? x) (even? x))) ...) will tell you if all the elements in a list are even integers, for instance.
There is also every which comes from SRFI 1 and which you can use in Racket after (require srfi/1). It is mostly (exactly?) the same as andmap.
One thing people sometimes try to do (and which you seem to be tempted to do) is to use eval. It may not be immediately clear how awful the eval 'solution; is. It is awful because
it doesn't, in fact, work at all;
insofar as it does work it prevents any kind of compilation and optimisation;
last but not least, it's a pathway to code injection attacks.
Let's see how bad it is. Start with this:
> (let ([args '(#t #t #f)])
(eval `(and ,#args)))
#f
OK, that looks good, right? Well, what if I have a list which is (a a a b): none of the elements in that are false, so, let's try that:
> (let ([args '(a a b)])
(eval `(and ,#args)))
; a: undefined;
; cannot reference an identifier before its definition
Oh, well, can I fix that?
> (let ([args '(a a b)]
[a 1] [b 2])
(eval `(and ,#args)))
; a: undefined;
; cannot reference an identifier before its definition
No, I can't. To make that work, I'd need this:
> (define a 1)
> (define b 2)
> (let ([args '(a a b)])
(eval `(and ,#args)))
2
or this
> (let ([args '('a 'a 'b)])
(eval `(and ,#args)))
'b
Yes, those are quotes inside the quoted list.
So that's horrible: the only two cases it's going to work for is where everything is either defined at the top level as eval has no access to the lexical scope where it is called, or a literal within the object which may already be a literal as it is here, because everything is now getting evaluated twice.
So that's just horrible. To make things worse, eval evaluates Scheme source code. So forget about compiling, performance, or any of that good stuff: it's all gone (maybe if you have a JIT compiler, maybe it might not be so awful).
Oh, yes, and eval evaluates Scheme source code, and it evaluates all of it.
So I have this convenient list:
(define args
'((begin (delete-all-my-files)
(publish-all-my-passwords-on-the-internet)
(give-all-my-money-to-tfb)
#t)
(launch-all-the-nuclear-missiles)))
It's just a list of lists of symbols and #t, right? So
> (eval `(and #,args)
; Error: you are not authorized to launch all the missiles
; (but all your files are gone, your passwords are now public,
; and tfb thanks you for your kind donation of all your money)
Oops.
It would be nice to be able to say, if I have a list that I want to check some property of that doing so would not send all my money to some person on the internet. Indeed, it would be nice to know that checking the property of the list would simply halt, at all. But if I use eval I can't know that: checking that every element of the list is (evaluates to) true may simply never terminate, or may launch nuclear weapons, and I can generally never know in advance whether it will terminate, or whether it will launch nuclear weapons. That's an ... undesirable property.
At the very least I would need to do something like this to heavily restrict what can appear in the list:
(define (safely-and-list l)
(for ([e (in-list l)])
(unless
(or (number? e)
(boolean? e))
(error 'safely-and-list "bad list")))
(eval `(and ,#l)))
But ... wait: I've just checked every element of the list: why didn't I just, you know, check they were all true then?
This is why eval is never the right solution for this problem. The thing eval is the right solution for is, well, evaluating Scheme. If you want to write some program that reads user input and evaluates, it, well, eval is good for that:
(define (repl (exit 'exit))
(display "feed me> ")
(flush-output)
(let ([r (read)])
(unless (eqv? r exit)
(writeln (eval r))
(repl exit))))
But if you think you want to apply a macro to some arguments then you almost certainly have an XY problem: you want to do something else, and you likely don't understand macros.
I'm triying to use when in Scheme but i dont know why at the last element of my list appears .#void>.
Here is my code
(define (genlist x y)
(when
(< x y)
(cons x (genlist (+ x 1) y))))
And this is my output =>
(2 3 4 5 6 7 8 9 . #void>)
We use when when we need to write an if without an else part, and/or when we need to write more than one expression inside the if. Only the last expression's value gets returned, hence we use it mostly for the side effects. To understand it better, in Racket this:
(when <condition>
<exp1>
<exp2>
<exp3>)
Is equivalent to this:
(if <condition>
(begin
<exp1>
<exp2>
<exp3>)
(void)) ; implementation-dependent
The same considerations apply to unless, except that the condition is surrounded with a (not ...).
The source of your problems (and the reason why it's a code smell to have an if without an else) is that your code is not handling the case when (>= x y). Ask yourself, what should you do in that case? Simple, return an empty list! that's the base case of the recursion that's missing from your code.
You would need to use (if (< x y) (cons ...) '()) to produce a proper list.
when (and it's counterpart unless) is mostly for doing side effects (like printing something out) in a context where the result is not used.
e.g. (when debug-mode? (print "got here"))
when is an one armed ifs with implicit begin. The following examples are the same:
(if (any odd? lst)
(begin
(set! some-binding #t)
(display "Found an odd element")))
(when (any odd? lst)
(set! some-binding #t)
(display "Found an odd element"))
And you can use unless instead of using not in the predicate:
(if (not (any odd? lst))
(set! some-binding #f))
(unless (any odd? lst)
(set! some-binding #f))
Peter Norvig made a nice book about Lisp style and in it he addresses this:
Be as specific as your data abstractions warrant, but no more.
if for two-branch expression
when, unless for one-branch statement
and, or for boolean value only
cond for multi-branch statement or expression
So while you can write all your logic using if it will not be the easiest code to read. Other might use the term principle of least surprise. Even though the book is for Common Lisp much of it can be used in Scheme as well. It's a good read if you want to program any lisp dialect professionaly.
For when and unless this is applies much better to Scheme as you have no idea what an implementation might return in the event the predicate evaluates to #f while in CL you could abuse when since it's destined to return nil in such cases.
In you code you are trying to return something and letting the implementation choose what should happen when the predicate failes is what causes the #<void>. When the return matter you should always use two armed if:
(if test-expression
then-expression
else-expression)
Note there is no else keyword.
I know that you can use ' (aka quote) to create a list, and I use this all the time, like this:
> (car '(1 2 3))
1
But it doesn’t always work like I’d expect. For example, I tried to create a list of functions, like this, but it didn’t work:
> (define math-fns '(+ - * /))
> (map (lambda (fn) (fn 1)) math-fns)
application: not a procedure;
expected a procedure that can be applied to arguments
given: '+
When I use list, it works:
> (define math-fns (list + - * /))
> (map (lambda (fn) (fn 1)) math-fns)
'(1 -1 1 1)
Why? I thought ' was just a convenient shorthand, so why is the behavior different?
TL;DR: They are different; use list when in doubt.
A rule of thumb: use list whenever you want the arguments to be evaluated; quote “distributes” over its arguments, so '(+ 1 2) is like (list '+ '1 '2). You’ll end up with a symbol in your list, not a function.
An in-depth look at list and quote
In Scheme and Racket, quote and list are entirely different things, but since both of them can be used to produce lists, confusion is common and understandable. There is an incredibly important difference between them: list is a plain old function, while quote (even without the special ' syntax) is a special form. That is, list can be implemented in plain Scheme, but quote cannot be.
The list function
The list function is actually by far the simpler of the two, so let’s start there. It is a function that takes any number of arguments, and it collects the arguments into a list.
> (list 1 2 3)
(1 2 3)
This above example can be confusing because the result is printed as a quoteable s-expression, and it’s true, in this case, the two syntaxes are equivalent. But if we get slightly more complicated, you’ll see that it is different:
> (list 1 (+ 1 1) (+ 1 1 1))
(1 2 3)
> '(1 (+ 1 1) (+ 1 1 1))
(1 (+ 1 1) (+ 1 1 1))
What’s going on in the quote example? Well, we’ll discuss that in a moment, but first, take a look at list. It’s just an ordinary function, so it follows standard Scheme evaluation semantics: it evaluates each of its arguments before they get passed to the function. This means that expressions like (+ 1 1) will be reduced to 2 before they get collected into the list.
This behavior is also visible when supplying variables to the list function:
> (define x 42)
> (list x)
(42)
> '(x)
(x)
With list, the x gets evaluated before getting passed to list. With quote, things are more complicated.
Finally, because list is just a function, it can be used just like any other function, including in higher-order ways. For example, it can be passed to the map function, and it will work appropriately:
> (map list '(1 2 3) '(4 5 6))
((1 4) (2 5) (3 6))
The quote form
Quotation, unlike list, is a special part of Lisps. The quote form is special in part because it gets a special reader abbreviation, ', but it’s also special even without that. Unlike list, quote is not a function, and therefore it does not need to behave like one—it has rules of its own.
A brief discussion of Lisp source code
In Lisp, of which Scheme and Racket are derivatives, all code is actually made up of ordinary data structures. For example, consider the following expression:
(+ 1 2)
That expression is actually a list, and it has three elements:
the + symbol
the number 1
the number 2
All of these values are normal values that can be created by the programmer. It’s really easy to create the 1 value because it evaluates to itself: you just type 1. But symbols and lists are harder: by default, a symbol in the source code does a variable lookup! That is, symbols are not self-evaluating:
> 1
1
> a
a: undefined
cannot reference undefined identifier
As it turns out, though, symbols are basically just strings, and in fact we can convert between them:
> (string->symbol "a")
a
Lists do even more than symbols, because by default, a list in the source code calls a function! Doing (+ 1 2) looks at the first element in the list, the + symbol, looks up the function associated with it, and invokes it with the rest of the elements in the list.
Sometimes, though, you might want to disable this “special” behavior. You might want to just get the list or get the symbol without it being evaluated. To do this, you can use quote.
The meaning of quotation
With all this in mind, it’s pretty obvious what quote does: it just “turns off” the special evaluation behavior for the expression that it wraps. For example, consider quoteing a symbol:
> (quote a)
a
Similarly, consider quoteing a list:
> (quote (a b c))
(a b c)
No matter what you give quote, it will always, always spit it back out at you. No more, no less. That means if you give it a list, none of the subexpressions will be evaluated—do not expect them to be! If you need evaluation of any kind, use list.
Now, one might ask: what happens if you quote something other than a symbol or a list? Well, the answer is... nothing! You just get it back.
> (quote 1)
1
> (quote "abcd")
"abcd"
This makes sense, since quote still just spits out exactly what you give it. This is why “literals” like numbers and strings are sometimes called “self-quoting” in Lisp parlance.
One more thing: what happens if you quote an expression containing quote? That is, what if you “double quote”?
> (quote (quote 3))
'3
What happened there? Well, remember that ' is actually just a direct abbreviation for quote, so nothing special happened at all! In fact, if your Scheme has a way to disable the abbreviations when printing, it will look like this:
> (quote (quote 3))
(quote 3)
Don’t be fooled by quote being special: just like (quote (+ 1)), the result here is just a plain old list. In fact, we can get the first element out of the list: can you guess what it will be?
> (car (quote (quote 3)))
quote
If you guessed 3, you are wrong. Remember, quote disables all evaluation, and an expression containing a quote symbol is still just a plain list. Play with this in the REPL until you are comfortable with it.
> (quote (quote (quote 3)))
''3
(quote (1 2 (quote 3)))
(1 2 '3)
Quotation is incredibly simple, but it can come off as very complex because of how it tends to defy our understanding of the traditional evaluation model. In fact, it is confusing because of how simple it is: there are no special cases, there are no rules. It just returns exactly what you give it, precisely as stated (hence the name “quotation”).
Appendix A: Quasiquotation
So if quotation completely disables evaluation, what is it good for? Well, aside from making lists of strings, symbols, or numbers that are all known ahead of time, not much. Fortunately, the concept of quasiquotation provides a way to break out of the quotation and go back into ordinary evaluation.
The basics are super simple: instead of using quote, use quasiquote. Normally, this works exactly like quote in every way:
> (quasiquote 3)
3
> (quasiquote x)
x
> (quasiquote ((a b) (c d)))
((a b) (c d))
What makes quasiquote special is that is recognizes a special symbol, unquote. Wherever unquote appears in the list, then it is replaced by the arbitrary expression it contains:
> (quasiquote (1 2 (+ 1 2)))
(1 2 (+ 1 2))
> (quasiquote (1 2 (unquote (+ 1 2))))
(1 2 3)
This lets you use quasiquote to construct templates of sorts that have “holes” to be filled in with unquote. This means it’s possible to actually include the values of variables inside of quoted lists:
> (define x 42)
> (quasiquote (x is: (unquote x)))
(x is: 42)
Of course, using quasiquote and unquote is rather verbose, so they have abbreviations of their own, just like '. Specifically, quasiquote is ` (backtick) and unquote is , (comma). With those abbreviations, the above example is much more palatable.
> `(x is: ,x)
(x is: 42)
One final point: quasiquote actually can be implemented in Racket using a rather hairy macro, and it is. It expands to usages of list, cons, and of course, quote.
Appendix B: Implementing list and quote in Scheme
Implementing list is super simple because of how “rest argument” syntax works. This is all you need:
(define (list . args)
args)
That’s it!
In contrast, quote is a lot harder—in fact, it’s impossible! It would seem totally feasible, since the idea of disabling evaluation sounds a lot like macros. Yet a naïve attempt reveals the trouble:
(define fake-quote
(syntax-rules ()
((_ arg) arg)))
We just take arg and spit it back out... but this doesn’t work. Why not? Well, the result of our macro will be evaluated, so all is for naught. We might be able to expand to something sort of like quote by expanding to (list ...) and recursively quoting the elements, like this:
(define impostor-quote
(syntax-rules ()
((_ (a . b)) (cons (impostor-quote a) (impostor-quote b)))
((_ (e ...)) (list (impostor-quote e) ...))
((_ x) x)))
Unfortunately, though, without procedural macros, we can’t handle symbols without quote. We could get closer using syntax-case, but even then, we would only be emulating quote’s behavior, not replicating it.
Appendix C: Racket printing conventions
When trying the examples in this answer in Racket, you may find that they do not print as one would expect. Often, they may print with a leading ', such as in this example:
> (list 1 2 3)
'(1 2 3)
This is because Racket, by default, prints results as expressions when possible. That is, you should be able to type the result into the REPL and get the same value back. I personally find this behavior nice, but it can be confusing when trying to understand quotation, so if you want to turn it off, call (print-as-expression #f), or change the printing style to “write” in the DrRacket language menu.
The behavior you are seeing is a consequence of Scheme not treating symbols as functions.
The expression '(+ - * /) produces a value which is a list of symbols. That's simply because (+ - * /) is a list of symbols, and we are just quoting it to suppress evaluation in order to get that object literally as a value.
The expression (list + - * /) produces a list of functions. This is because it is a function call. The symbolic expressions list, +, -, * and / are evaluated. They are all variables which denote functions, and so are reduced to those functions. The list function is then called, and returns a list of those remaining four functions.
In ANSI Common Lisp, calling symbols as functions works:
[1]> (mapcar (lambda (f) (funcall f 1)) '(+ - * /))
(1 -1 1 1)
When a symbol is used where a function is expected, the top-level function binding of the symbol is substituted, if it has one, and everything is cool. In effect, symbols are function-callable objects in Common Lisp.
If you want to use list to produce a list of symbols, just like '(+ - * /), you have to quote them individually to suppress their evaluation:
(list '+ '- '* '/)
Back in the Scheme world, you will see that if you map over this, it will fail in the same way as the original quoted list. The reason is the same: trying to use a symbol objects as a functions.
The error message you are being shown is misleading:
expected a procedure that can be applied to arguments
given: '+
This '+ being shown here is (quote +). But that's not what the application was given; it was given just +, the issue being that the symbol object + isn't usable as a function in that dialect.
What's going on here is that the diagnostic message is printing the + symbol in "print as expression" mode, a feature of Racket, which is what I guess you're using.
In "print as expression" mode, objects are printed using a syntax which must be read and evaluated to produce a similar object. See the StackOverflow question "Why does the Racket interpreter write lists with an apostroph before?"
I know that you can use ' (aka quote) to create a list, and I use this all the time, like this:
> (car '(1 2 3))
1
But it doesn’t always work like I’d expect. For example, I tried to create a list of functions, like this, but it didn’t work:
> (define math-fns '(+ - * /))
> (map (lambda (fn) (fn 1)) math-fns)
application: not a procedure;
expected a procedure that can be applied to arguments
given: '+
When I use list, it works:
> (define math-fns (list + - * /))
> (map (lambda (fn) (fn 1)) math-fns)
'(1 -1 1 1)
Why? I thought ' was just a convenient shorthand, so why is the behavior different?
TL;DR: They are different; use list when in doubt.
A rule of thumb: use list whenever you want the arguments to be evaluated; quote “distributes” over its arguments, so '(+ 1 2) is like (list '+ '1 '2). You’ll end up with a symbol in your list, not a function.
An in-depth look at list and quote
In Scheme and Racket, quote and list are entirely different things, but since both of them can be used to produce lists, confusion is common and understandable. There is an incredibly important difference between them: list is a plain old function, while quote (even without the special ' syntax) is a special form. That is, list can be implemented in plain Scheme, but quote cannot be.
The list function
The list function is actually by far the simpler of the two, so let’s start there. It is a function that takes any number of arguments, and it collects the arguments into a list.
> (list 1 2 3)
(1 2 3)
This above example can be confusing because the result is printed as a quoteable s-expression, and it’s true, in this case, the two syntaxes are equivalent. But if we get slightly more complicated, you’ll see that it is different:
> (list 1 (+ 1 1) (+ 1 1 1))
(1 2 3)
> '(1 (+ 1 1) (+ 1 1 1))
(1 (+ 1 1) (+ 1 1 1))
What’s going on in the quote example? Well, we’ll discuss that in a moment, but first, take a look at list. It’s just an ordinary function, so it follows standard Scheme evaluation semantics: it evaluates each of its arguments before they get passed to the function. This means that expressions like (+ 1 1) will be reduced to 2 before they get collected into the list.
This behavior is also visible when supplying variables to the list function:
> (define x 42)
> (list x)
(42)
> '(x)
(x)
With list, the x gets evaluated before getting passed to list. With quote, things are more complicated.
Finally, because list is just a function, it can be used just like any other function, including in higher-order ways. For example, it can be passed to the map function, and it will work appropriately:
> (map list '(1 2 3) '(4 5 6))
((1 4) (2 5) (3 6))
The quote form
Quotation, unlike list, is a special part of Lisps. The quote form is special in part because it gets a special reader abbreviation, ', but it’s also special even without that. Unlike list, quote is not a function, and therefore it does not need to behave like one—it has rules of its own.
A brief discussion of Lisp source code
In Lisp, of which Scheme and Racket are derivatives, all code is actually made up of ordinary data structures. For example, consider the following expression:
(+ 1 2)
That expression is actually a list, and it has three elements:
the + symbol
the number 1
the number 2
All of these values are normal values that can be created by the programmer. It’s really easy to create the 1 value because it evaluates to itself: you just type 1. But symbols and lists are harder: by default, a symbol in the source code does a variable lookup! That is, symbols are not self-evaluating:
> 1
1
> a
a: undefined
cannot reference undefined identifier
As it turns out, though, symbols are basically just strings, and in fact we can convert between them:
> (string->symbol "a")
a
Lists do even more than symbols, because by default, a list in the source code calls a function! Doing (+ 1 2) looks at the first element in the list, the + symbol, looks up the function associated with it, and invokes it with the rest of the elements in the list.
Sometimes, though, you might want to disable this “special” behavior. You might want to just get the list or get the symbol without it being evaluated. To do this, you can use quote.
The meaning of quotation
With all this in mind, it’s pretty obvious what quote does: it just “turns off” the special evaluation behavior for the expression that it wraps. For example, consider quoteing a symbol:
> (quote a)
a
Similarly, consider quoteing a list:
> (quote (a b c))
(a b c)
No matter what you give quote, it will always, always spit it back out at you. No more, no less. That means if you give it a list, none of the subexpressions will be evaluated—do not expect them to be! If you need evaluation of any kind, use list.
Now, one might ask: what happens if you quote something other than a symbol or a list? Well, the answer is... nothing! You just get it back.
> (quote 1)
1
> (quote "abcd")
"abcd"
This makes sense, since quote still just spits out exactly what you give it. This is why “literals” like numbers and strings are sometimes called “self-quoting” in Lisp parlance.
One more thing: what happens if you quote an expression containing quote? That is, what if you “double quote”?
> (quote (quote 3))
'3
What happened there? Well, remember that ' is actually just a direct abbreviation for quote, so nothing special happened at all! In fact, if your Scheme has a way to disable the abbreviations when printing, it will look like this:
> (quote (quote 3))
(quote 3)
Don’t be fooled by quote being special: just like (quote (+ 1)), the result here is just a plain old list. In fact, we can get the first element out of the list: can you guess what it will be?
> (car (quote (quote 3)))
quote
If you guessed 3, you are wrong. Remember, quote disables all evaluation, and an expression containing a quote symbol is still just a plain list. Play with this in the REPL until you are comfortable with it.
> (quote (quote (quote 3)))
''3
(quote (1 2 (quote 3)))
(1 2 '3)
Quotation is incredibly simple, but it can come off as very complex because of how it tends to defy our understanding of the traditional evaluation model. In fact, it is confusing because of how simple it is: there are no special cases, there are no rules. It just returns exactly what you give it, precisely as stated (hence the name “quotation”).
Appendix A: Quasiquotation
So if quotation completely disables evaluation, what is it good for? Well, aside from making lists of strings, symbols, or numbers that are all known ahead of time, not much. Fortunately, the concept of quasiquotation provides a way to break out of the quotation and go back into ordinary evaluation.
The basics are super simple: instead of using quote, use quasiquote. Normally, this works exactly like quote in every way:
> (quasiquote 3)
3
> (quasiquote x)
x
> (quasiquote ((a b) (c d)))
((a b) (c d))
What makes quasiquote special is that is recognizes a special symbol, unquote. Wherever unquote appears in the list, then it is replaced by the arbitrary expression it contains:
> (quasiquote (1 2 (+ 1 2)))
(1 2 (+ 1 2))
> (quasiquote (1 2 (unquote (+ 1 2))))
(1 2 3)
This lets you use quasiquote to construct templates of sorts that have “holes” to be filled in with unquote. This means it’s possible to actually include the values of variables inside of quoted lists:
> (define x 42)
> (quasiquote (x is: (unquote x)))
(x is: 42)
Of course, using quasiquote and unquote is rather verbose, so they have abbreviations of their own, just like '. Specifically, quasiquote is ` (backtick) and unquote is , (comma). With those abbreviations, the above example is much more palatable.
> `(x is: ,x)
(x is: 42)
One final point: quasiquote actually can be implemented in Racket using a rather hairy macro, and it is. It expands to usages of list, cons, and of course, quote.
Appendix B: Implementing list and quote in Scheme
Implementing list is super simple because of how “rest argument” syntax works. This is all you need:
(define (list . args)
args)
That’s it!
In contrast, quote is a lot harder—in fact, it’s impossible! It would seem totally feasible, since the idea of disabling evaluation sounds a lot like macros. Yet a naïve attempt reveals the trouble:
(define fake-quote
(syntax-rules ()
((_ arg) arg)))
We just take arg and spit it back out... but this doesn’t work. Why not? Well, the result of our macro will be evaluated, so all is for naught. We might be able to expand to something sort of like quote by expanding to (list ...) and recursively quoting the elements, like this:
(define impostor-quote
(syntax-rules ()
((_ (a . b)) (cons (impostor-quote a) (impostor-quote b)))
((_ (e ...)) (list (impostor-quote e) ...))
((_ x) x)))
Unfortunately, though, without procedural macros, we can’t handle symbols without quote. We could get closer using syntax-case, but even then, we would only be emulating quote’s behavior, not replicating it.
Appendix C: Racket printing conventions
When trying the examples in this answer in Racket, you may find that they do not print as one would expect. Often, they may print with a leading ', such as in this example:
> (list 1 2 3)
'(1 2 3)
This is because Racket, by default, prints results as expressions when possible. That is, you should be able to type the result into the REPL and get the same value back. I personally find this behavior nice, but it can be confusing when trying to understand quotation, so if you want to turn it off, call (print-as-expression #f), or change the printing style to “write” in the DrRacket language menu.
The behavior you are seeing is a consequence of Scheme not treating symbols as functions.
The expression '(+ - * /) produces a value which is a list of symbols. That's simply because (+ - * /) is a list of symbols, and we are just quoting it to suppress evaluation in order to get that object literally as a value.
The expression (list + - * /) produces a list of functions. This is because it is a function call. The symbolic expressions list, +, -, * and / are evaluated. They are all variables which denote functions, and so are reduced to those functions. The list function is then called, and returns a list of those remaining four functions.
In ANSI Common Lisp, calling symbols as functions works:
[1]> (mapcar (lambda (f) (funcall f 1)) '(+ - * /))
(1 -1 1 1)
When a symbol is used where a function is expected, the top-level function binding of the symbol is substituted, if it has one, and everything is cool. In effect, symbols are function-callable objects in Common Lisp.
If you want to use list to produce a list of symbols, just like '(+ - * /), you have to quote them individually to suppress their evaluation:
(list '+ '- '* '/)
Back in the Scheme world, you will see that if you map over this, it will fail in the same way as the original quoted list. The reason is the same: trying to use a symbol objects as a functions.
The error message you are being shown is misleading:
expected a procedure that can be applied to arguments
given: '+
This '+ being shown here is (quote +). But that's not what the application was given; it was given just +, the issue being that the symbol object + isn't usable as a function in that dialect.
What's going on here is that the diagnostic message is printing the + symbol in "print as expression" mode, a feature of Racket, which is what I guess you're using.
In "print as expression" mode, objects are printed using a syntax which must be read and evaluated to produce a similar object. See the StackOverflow question "Why does the Racket interpreter write lists with an apostroph before?"