doc edits
svn: r6255
This commit is contained in:
parent
8ab6ad2c9c
commit
49740192d5
|
@ -45,10 +45,10 @@ Many predefined procedures operate on lists. Here are a few examples:
|
|||
|
||||
In addition to simple operations like @scheme[append], Scheme includes
|
||||
procedures that iterate over the elements of a list. These iteration
|
||||
procedures play the same role as, say, @tt{for} in Java. The body of
|
||||
an iteration is packaged into a procedure to be applied to each
|
||||
element, so the @scheme[lambda] form becomes particularly handy in
|
||||
combination with iteration procedures.
|
||||
procedures play much the same role as @tt{for} in Java and other
|
||||
languages. The body of a Scheme iteration is packaged into a procedure
|
||||
to be applied to each element, so the @scheme[lambda] form becomes
|
||||
particularly handy in combination with iteration procedures.
|
||||
|
||||
The @scheme[for-each] procedure acts the most like a @tt{for} loop:
|
||||
|
||||
|
@ -58,12 +58,14 @@ The @scheme[for-each] procedure acts the most like a @tt{for} loop:
|
|||
(list "pie" "stew" "carrots and pizza, and pineapple, too"))
|
||||
]
|
||||
|
||||
Scheme includes many other list-iteration procedures, because there
|
||||
are multiple ways to combine the results from each iteration. The
|
||||
@scheme[for-each] procedure completely ignores the per-element result,
|
||||
so it is used with a loop body that has some side-effect (such as
|
||||
printing output). The @scheme[map] procedure, in contrast, uses the
|
||||
per-element results to create a new list:
|
||||
The @scheme[for-each] procedure completely ignores the per-element
|
||||
result of the iteration body, so it is used with loop bodies that have
|
||||
a side-effect (such as printing output). Keeping in mind that Scheme
|
||||
programmers avoid side-effects, they also avoid @scheme[for-each].
|
||||
|
||||
Other list-iteration procedures use the per-element results, but in
|
||||
different ways. The @scheme[map] procedure uses the per-element
|
||||
results to create a new list:
|
||||
|
||||
@interaction[
|
||||
(map sqrt (list 1 4 9 16))
|
||||
|
@ -81,10 +83,18 @@ by @scheme[and]ing or @scheme[or]ing:
|
|||
(ormap number? (list "a" "b" 6))
|
||||
]
|
||||
|
||||
The @scheme[for-each], @scheme[map], @scheme[andmap], and
|
||||
@scheme[ormap] procedures can all handle multiple lists, instead of
|
||||
just a single list. The lists must all have the same length, and the
|
||||
given procedure must accept one argument for each list:
|
||||
The @scheme[filter] procedure keeps elements for which the body result
|
||||
is true, and discards elements for which it is @scheme[#f]:
|
||||
|
||||
@interaction[
|
||||
(filter string? (list "a" "b" 6))
|
||||
(filter positive? (list 1 -2 6 7 0))
|
||||
]
|
||||
|
||||
The @scheme[for-each], @scheme[map], @scheme[andmap], @scheme[ormap],
|
||||
and @scheme[filter] procedures can all handle multiple lists, instead
|
||||
of just a single list. The lists must all have the same length, and
|
||||
the given procedure must accept one argument for each list:
|
||||
|
||||
@interaction[
|
||||
(map (lambda (s n) (substring s 0 n))
|
||||
|
@ -95,7 +105,7 @@ given procedure must accept one argument for each list:
|
|||
The @scheme[foldl] procedure generalizes some iteration procedures. It
|
||||
uses the per-element procedure to both process an element and combine
|
||||
it with the ``current'' value, so the per-element procedure takes an
|
||||
extra first argument. Also, a starting ``current ' value must be
|
||||
extra first argument. Also, a starting ``current'' value must be
|
||||
provided before the lists:
|
||||
|
||||
@interaction[
|
||||
|
@ -106,9 +116,9 @@ provided before the lists:
|
|||
]
|
||||
|
||||
Despite its generality, @scheme[foldl] is not as popular as the other
|
||||
procedures. The main reason is that @scheme[for-each], @scheme[map],
|
||||
@scheme[ormap], and @scheme[andmap] cover the most common kinds of
|
||||
loops.
|
||||
procedures. One reason is that @scheme[map], @scheme[ormap],
|
||||
@scheme[andmap], and @scheme[filter] cover the most common kinds of
|
||||
list loops.
|
||||
|
||||
@;------------------------------------------------------------------------
|
||||
@section{Iterative Folds and Comprehensions: @scheme[fold-for] and @scheme[list-for]}
|
||||
|
@ -151,7 +161,7 @@ and implicitly accumulates each result into a list:
|
|||
]
|
||||
|
||||
The @scheme[list-for] form is a @defterm{list compherension} form, as
|
||||
in Haskell, Ruby, Python, and other languages. Its advantage over
|
||||
in Haskell, Ruby, Python, and other languages. One advantage over
|
||||
@scheme[map] is that it can iterate over more things than just lists.
|
||||
For example, @scheme[list-for] can iterate over a range of numbers:
|
||||
|
||||
|
@ -191,15 +201,15 @@ simpler (just a procedure call).
|
|||
|
||||
We have ignored several other variants of the interation
|
||||
form---including plain @scheme[for], which is use when the iteration
|
||||
body is to be run only for its effect. We explain the full set in
|
||||
@secref["iterations+comprehensions"].
|
||||
body is to be run only for its effect. For more complete information,
|
||||
see @secref["iterations+comprehensions"].
|
||||
|
||||
@;------------------------------------------------------------------------
|
||||
@section{List Iteration from Scratch}
|
||||
|
||||
Although @scheme[map] and @scheme[list-for] are predefined, they are
|
||||
not primitive in any interesting sense. You can write equivalent
|
||||
iterations using just a handful of list primitives.
|
||||
iterations using a handful of list primitives.
|
||||
|
||||
Since a Scheme list is a linked list, the two core operations on a
|
||||
non-empty list are
|
||||
|
@ -231,8 +241,7 @@ empty
|
|||
To process a list, you need to be able to distinguish empty lists from
|
||||
non-empty lists, because @scheme[first] and @scheme[rest] work only on
|
||||
non-empty lists. The @scheme[empty?] procedure detects empty lists,
|
||||
and @scheme[cons?] detects non-empty lists (which pair an element with
|
||||
another list):
|
||||
and @scheme[cons?] detects non-empty lists:
|
||||
|
||||
@interaction[
|
||||
(empty? empty)
|
||||
|
@ -261,14 +270,13 @@ With these pieces, you can write your own versions of the
|
|||
(my-map string-upcase (list "ready" "set" "go"))
|
||||
]
|
||||
|
||||
If the definitions are mysterious to you, consider reading @|HtDP|. If
|
||||
you are merely suspicious of the use of recursive calls instead of a
|
||||
looping construct, then read on.
|
||||
If the derivation of the above definitions is mysterious to you,
|
||||
consider reading @|HtDP|. But if you are merely suspicious of the use
|
||||
of recursive calls instead of a looping construct, then read on.
|
||||
|
||||
Both the @scheme[my-length] and @scheme[my-map] procedures run in
|
||||
@math{O(n)} time for a list of length @math{n}. This is easy to see by
|
||||
imagining how @scheme[(my-length (list "a" "b" "c"))] must evaluate
|
||||
sub-expression:
|
||||
imagining how @scheme[(my-length (list "a" "b" "c"))] must evaluate:
|
||||
|
||||
@schemeblock[
|
||||
(my-length (list "a" "b" "c"))
|
||||
|
@ -283,8 +291,13 @@ sub-expression:
|
|||
|
||||
For a list with @math{n} elements, evalution will stack up @math{n}
|
||||
@scheme[(+ 1 ...)] additions, and then finally add them up when the
|
||||
list is exhausted. You can avoid piling up additions by adding along
|
||||
the way, accumulating the length in a variable @scheme[len].
|
||||
list is exhausted.
|
||||
|
||||
You can avoid piling up additions by adding along the way. To
|
||||
accumulate a length this way, we need a procedure that takes both a
|
||||
list and the length of the list seem so far; the code below uses a
|
||||
local procedure @scheme[iter] that accumulates the length in an
|
||||
argument @scheme[len]:
|
||||
|
||||
@schemeblock[
|
||||
(define (my-length lst)
|
||||
|
@ -310,16 +323,18 @@ Now evaluation looks like this:
|
|||
|
||||
The revised @scheme[my-length] runs in constant space, just as the
|
||||
evaluation steps above suggest. That is, when the result of a
|
||||
procedure call is the result of some other procedure call, then the
|
||||
original procedure doesn't have to wait around for the result, taking
|
||||
up space for no good reason. This evaluation behavior is sometimes
|
||||
called @idefterm{tail-call optimization}, but it's not merely an
|
||||
``optimization'' in Scheme; it's a guarantee about the way the code
|
||||
will run.
|
||||
procedure call, like @scheme[(iter (list "b" "c") 1)], is exactly the
|
||||
result of some other procedure call, like @scheme[(iter (list "c")
|
||||
2)], then the first one doesn't have to wait around for the second
|
||||
one, because that takes up space for no good reason.
|
||||
|
||||
This evaluation behavior is sometimes called @idefterm{tail-call
|
||||
optimization}, but it's not merely an ``optimization'' in Scheme; it's
|
||||
a guarantee about the way the code will run.
|
||||
|
||||
In the case of @scheme[my-map], @math{O(n)} space compelxity is
|
||||
reasonable, since it has to generate an @math{O(n)}
|
||||
result. Nevertheless, you can reduce the constant factor by
|
||||
reasonable, since it has to generate a result of size
|
||||
@math{O(n)}. Nevertheless, you can reduce the constant factor by
|
||||
accumulating the result list. The only catch is that the accumulated
|
||||
list will be backwards, so you'll have to reverse it at the very end:
|
||||
|
||||
|
@ -350,11 +365,11 @@ use. The difference is merely syntactic convenience.
|
|||
@section{Recursion versus Iteration}
|
||||
|
||||
The @scheme[my-length] and @scheme[my-map] examples demonstrate that
|
||||
iteration is just a special case of recursion. In many languages, it
|
||||
is important to try to fit as many computations as possible into
|
||||
iteration form, otherwise performance will be bad and moderately large
|
||||
inputs can lead to stack overflow. Similarly, in Scheme, it is often
|
||||
important to make sure that tail recursion is used to avoid
|
||||
iteration is just a special case of recursion. In many languages, it's
|
||||
important to try to fit as many computations as possible into
|
||||
iteration form. Otherwise, performance will be bad, and moderately
|
||||
large inputs can lead to stack overflow. Similarly, in Scheme, it is
|
||||
often important to make sure that tail recursion is used to avoid
|
||||
@math{O(n)} space consumption when the computation is easily performed
|
||||
in constant space.
|
||||
|
||||
|
@ -368,9 +383,9 @@ tail-recursive programs automatically run the same as a loop, lead
|
|||
Scheme programmers to embrace recursive forms rather than avoid them.
|
||||
|
||||
Suppose, for example, that you want to remove consecutive duplicates
|
||||
from a list. While that can be written as a loop that remembers the
|
||||
previous element for each iteration, a Scheme programmer would more
|
||||
likely just write the following:
|
||||
from a list. While that procedure can be written as a loop that
|
||||
remembers the previous element for each iteration, a Scheme programmer
|
||||
would more likely just write the following:
|
||||
|
||||
@def+int[
|
||||
(define (remove-dups l)
|
||||
|
@ -405,22 +420,22 @@ kicks in:
|
|||
]
|
||||
|
||||
Tail-call behavior becomes even more important when dealing with
|
||||
non-list data and when using an object-oriented style. In the latter
|
||||
case, an object must frequently dispatch to another object; if the
|
||||
non-list data or when using an object-oriented style. In the latter
|
||||
case, an object must sometimes dispatch to another object; if the
|
||||
other object's result is the complete answer, there's no reason for
|
||||
the first object to wait around. We defer this extended discussion
|
||||
until @secref["datatypes"], at which point we'll have more forms of
|
||||
the first object to wait around. We defer futher discussion of this
|
||||
point until @secref["datatypes"], after which we'll have more forms of
|
||||
data to consider.
|
||||
|
||||
@;------------------------------------------------------------------------
|
||||
@section{Named @scheme[let]}
|
||||
|
||||
As you start reading Scheme code, you'll discover one more form that
|
||||
is commonly used to implement recursive functions: @idefterm{named @scheme[let]}.
|
||||
A named @scheme[let] uses the same syntactic keyword as a simple
|
||||
sequence of local bindings, but an @nonterm{identifier} after the
|
||||
@scheme[let] (instead of an immediate open parenthesis) triggers a
|
||||
different parsing. In general,
|
||||
is commonly used to implement iterations and recursive functions:
|
||||
@idefterm{named @scheme[let]}. A named @scheme[let] uses the same
|
||||
syntactic keyword as a simple sequence of local bindings, but an
|
||||
@nonterm{identifier} after the @scheme[let] (instead of an immediate
|
||||
open parenthesis) triggers a different parsing. In general,
|
||||
|
||||
@schemeblock[
|
||||
#, @BNF-seq[@litchar{(} @litchar{let} @nonterm{proc-identifier} @litchar{(}
|
||||
|
@ -442,9 +457,10 @@ context.
|
|||
|
||||
That is, a named @scheme[let] binds a procedure identifier that is
|
||||
visible only in the procedure's body, and it implicitly calls the
|
||||
procedure with the values of some initial expressions. It looks
|
||||
similar to the start of @scheme[fold-for], but the recursive calls in
|
||||
the body are explicit, and they are not constrained to tail position.
|
||||
procedure with the values of some initial expressions. A named
|
||||
@scheme[let] looks similar to the start of @scheme[fold-for], but the
|
||||
recursive calls in the body are explicit, and they are not constrained
|
||||
to tail position.
|
||||
|
||||
As an example, here is @scheme[my-map] once again, using a named let
|
||||
to bind the local @scheme[iter] procedure:
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
@require[(lib "bnf.ss" "scribble")]
|
||||
@require["guide-utils.ss"]
|
||||
|
||||
@title[#:tag "syntax-overview"]{Just Enough Scheme Syntax}
|
||||
@title[#:tag "syntax-overview"]{Basic Scheme Syntax}
|
||||
|
||||
The syntax of a Scheme program is specified in an unusual way compared
|
||||
to most programming languages. In particular, importing a module can
|
||||
|
@ -92,9 +92,10 @@ binds @nonterm{identifier} to the result of @nonterm{expression}, while
|
|||
@schemeblock[#, @fun-defn-stx]
|
||||
|
||||
binds the first @nonterm{identifier} to a procedure that takes
|
||||
arguments as named by the remaining @nonterm{identifier}s. The
|
||||
@nonterm{expression}s are the body of the procedure. When called, the
|
||||
procedure returns the result of the last @nonterm{expression}.
|
||||
arguments as named by the remaining @nonterm{identifier}s. In the
|
||||
procedure case, the @nonterm{expression}s are the body of the
|
||||
procedure. When the procedure is called, it returns the result of the
|
||||
last @nonterm{expression}.
|
||||
|
||||
@defexamples[
|
||||
(code:line (define five 5) (code:comment #, @t{defines @scheme[five] to be @scheme[5]}))
|
||||
|
@ -105,7 +106,7 @@ five
|
|||
]
|
||||
|
||||
Under the hood, a procedure definition is really the same as a
|
||||
non-procedure definition. Consequently, a procedure name does not have to be
|
||||
non-procedure definition, and a procedure name does not have to be
|
||||
used in a procedure call. A procedure is just another kind of value,
|
||||
though the printed form is necessarily less complete than the printed
|
||||
form of a number or string.
|
||||
|
@ -139,10 +140,12 @@ evaluated only for some side-effect, such as printing.
|
|||
(greet "universe")
|
||||
]
|
||||
|
||||
Although you should generally avoid side-effects, it's important to
|
||||
understand that multiple expressions are allowed in a definition
|
||||
body. It explains why the following @scheme[nogreet] procedure simply
|
||||
returns its argument:
|
||||
You should generally avoid side-effects in Scheme; printing is a
|
||||
reasonable effect to use in some programs, but it's no substitute for
|
||||
simply returning a value. In any case, you should understand that
|
||||
multiple expressions are allowed in a definition body, because it
|
||||
explains why the following @scheme[nogreet] procedure simply returns
|
||||
its argument:
|
||||
|
||||
@def+int[
|
||||
(define (nogreet name)
|
||||
|
@ -150,12 +153,12 @@ returns its argument:
|
|||
(nogreet "world")
|
||||
]
|
||||
|
||||
There are no parentheses around @scheme[string-append "hello " name],
|
||||
so they are three separate expressions instead of one procedure-call
|
||||
expression. The expressions @scheme[string-append] and
|
||||
@scheme["hello "] are evaluated, but the results are never
|
||||
used. Instead, the result of the procedure is just the result of
|
||||
the expression @scheme[name].
|
||||
Withing @scheme[nogreet], there are no parentheses around
|
||||
@scheme[string-append "hello " name], so they are three separate
|
||||
expressions instead of one procedure-call expression. The expressions
|
||||
@scheme[string-append] and @scheme["hello "] are evaluated, but the
|
||||
results are never used. Instead, the result of the procedure is just
|
||||
the result of the expression @scheme[name].
|
||||
|
||||
@;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
@section{Identifiers}
|
||||
|
@ -251,7 +254,7 @@ string-append
|
|||
|
||||
We have already seen many procedure calls---or @defterm{procedure
|
||||
applications} in Scheme termonology. The syntax of a procedure
|
||||
call is
|
||||
application is
|
||||
|
||||
@schemeblock[
|
||||
#, app-expr-stx
|
||||
|
@ -289,8 +292,7 @@ click on an identifier to get full details about its use.
|
|||
@;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
@section{Conditionals with @scheme[if], @scheme[and], @scheme[or], and @scheme[cond]}
|
||||
|
||||
After identifiers and constants, the next simplest kind of expression
|
||||
is an @scheme[if] conditional:
|
||||
The next simplest kind of expression is an @scheme[if] conditional:
|
||||
|
||||
@schemeblock[
|
||||
#, if-expr-stx
|
||||
|
@ -301,10 +303,7 @@ non-@scheme[#f] value, then the second @nonterm{expression} is
|
|||
evaluted for the result of the whole @scheme[if] expression, otherwise
|
||||
the third @nonterm{expression} is evaluated for the result.
|
||||
|
||||
The @scheme[if] form is often used with procedures whose names end in
|
||||
@schemeid[?]:
|
||||
|
||||
@interaction[
|
||||
@examples[
|
||||
(if (> 2 3)
|
||||
"bigger"
|
||||
"smaller")
|
||||
|
@ -319,7 +318,7 @@ The @scheme[if] form is often used with procedures whose names end in
|
|||
(reply "\u03BBx:(\u03BC\u03B1.\u03B1\u2192\u03B1).xx")
|
||||
]
|
||||
|
||||
More complex conditionals can be formed by nesting @scheme[if]
|
||||
Complex conditionals can be formed by nesting @scheme[if]
|
||||
expressions. For example, you could make the @scheme[reply] procedure
|
||||
work when given non-strings:
|
||||
|
||||
|
@ -345,7 +344,7 @@ better written as
|
|||
]
|
||||
|
||||
but these kinds of nested @scheme[if]s are difficult to read. Scheme
|
||||
provides a more readable shortcut through the @scheme[and] and
|
||||
provides more readable shortcuts through the @scheme[and] and
|
||||
@scheme[or] forms, which work with any number of expressions:
|
||||
|
||||
@schemeblock[
|
||||
|
@ -396,8 +395,8 @@ expression. If it produces true, then the clause's second
|
|||
expression, and the rest of the clauses are ignored. If the test
|
||||
@nonterm{expression} produces @scheme[#f], then the clause's second
|
||||
@nonterm{expression} is ignored, and evaluation continues with the
|
||||
next clause. The last clause can use @scheme[else] as a sononym for
|
||||
@scheme[#t] in place of a test expression.
|
||||
next clause. The last clause can use @scheme[else] as a synonym for
|
||||
a @scheme[#t] test expression.
|
||||
|
||||
Using @scheme[cond], the @scheme[reply-more] procedure can be more
|
||||
clearly written as follows:
|
||||
|
@ -458,13 +457,6 @@ When you accidentally omit a procedure name or when you use
|
|||
parentheses around an expression, you'll most often get an ``expected
|
||||
a procedure'' error like this one.
|
||||
|
||||
Technically, @scheme[(if #t 1 2)] can be parsed as a procedure
|
||||
application as well as a conditional in our pretend grammar of Scheme,
|
||||
since @schemeid[if] is an identifier. For now, we say that the
|
||||
application form has a weaker precedence than the other forms, and
|
||||
we'll leave a full explanation to our discussion of
|
||||
@secref["scheme-forms"].
|
||||
|
||||
@;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
@section{Anonymous Procedures with @scheme[lambda]}
|
||||
|
||||
|
@ -659,12 +651,8 @@ too simple even for this chapter. Here's the grammar that we have now:
|
|||
@BNF-etc)]
|
||||
|
||||
For an expanded grammar, it's still a pretty small language! This
|
||||
language is plenty, however, to write lots of interesting programs.
|
||||
language is enough, however, to write lots of interesting programs.
|
||||
|
||||
Depending on your programming background, you may be struck by the
|
||||
apparent absence of an iteration form. But the above is enough to
|
||||
write any kind of loop, as we see in the next chapter. Moreover, an
|
||||
extra built-in datatype (to go along numbers, strings, etc.) gives us
|
||||
more interesting data to process with loops. The new datatype is also
|
||||
the key to understanding the true syntax of Scheme, which we get back
|
||||
to in @secref["scheme-read"] and @secref["scheme-forms"].
|
||||
apparent absence of an iteration form. We'll add one in the next
|
||||
chapter, but also explain why it isn't really necessary.
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
|
||||
The @scheme[cons] procedure actually accepts any two values, not just
|
||||
a list for the second argument. When the second argument is not
|
||||
@scheme[empty] or itself produced by @scheme[cons], the result prints
|
||||
@scheme[empty] and not itself produced by @scheme[cons], the result prints
|
||||
in a special way. The two values joined with @scheme[cons] are printed
|
||||
between parentheses, but with a dot (i.e., a period surrounded by
|
||||
whitespace) in between:
|
||||
|
@ -66,7 +66,7 @@ becomes @schemeresult[(0 1 . 2)], and
|
|||
@schemeresultfont{(1 . (2 . (3 . ())))} becomes @schemeresult[(1 2 3)].
|
||||
|
||||
@;------------------------------------------------------------------------
|
||||
@section{Quoting Lists and Symbols with @scheme[quote]}
|
||||
@section{Quoting Pairs and Symbols with @scheme[quote]}
|
||||
|
||||
After you see
|
||||
|
||||
|
@ -145,9 +145,9 @@ identifiers, it creates a list of symbols:
|
|||
@;------------------------------------------------------------------------
|
||||
@section{Abbreviating @scheme[quote] with @schemevalfont{'}}
|
||||
|
||||
If @scheme[(#, @scheme[quote] (1 2 3))] is still too much typing, you
|
||||
can abbreviate by just putting @litchar{'} in front of @scheme[(1 2
|
||||
3)]:
|
||||
If @scheme[(#, @scheme[quote] (1 2 3))] still seems like too much
|
||||
typing, you can abbreviate by just putting @litchar{'} in front of
|
||||
@scheme[(1 2 3)]:
|
||||
|
||||
@interaction[
|
||||
'(1 2 3)
|
||||
|
@ -173,8 +173,8 @@ quote:
|
|||
]
|
||||
|
||||
Beware, however, that the REPL's printer recognizes the symbol
|
||||
@schemeidfont{quote} hwne printing output, and it uses @schemeidfont{'}
|
||||
in the output:
|
||||
@schemeidfont{quote} when printing output, and then it uses
|
||||
@schemeidfont{'} in the output:
|
||||
|
||||
@interaction[
|
||||
'road
|
||||
|
@ -182,7 +182,7 @@ in the output:
|
|||
(eval:alts '(#, @schemevalfont{quote} #, @schemevalfont{road}) ''road)
|
||||
]
|
||||
|
||||
There is a method to this madness. It has to do with the true nature
|
||||
There is a method to this madness; it has to do with the true nature
|
||||
of Scheme syntax (which we discuss in the next section) and the
|
||||
traditional Lisp approach to meta-programming (which we discuss in the
|
||||
@seclink["quote-eval"]{section afterward}).
|
||||
|
@ -207,11 +207,11 @@ streams. Instead, the syntax is determined by two layers:
|
|||
|
||||
}
|
||||
|
||||
The rules for printing and the read layer go together. For example, a
|
||||
list is printed with parentheses, and reading a pair of parentheses
|
||||
produces a list. Similarly, a non-list pair is printed with the dot
|
||||
notation, and a dot on input effectively runs the dot-notation rules
|
||||
in reverse to obtain a pair.
|
||||
The rules for printing and reading go together. For example, a list is
|
||||
printed with parentheses, and reading a pair of parentheses produces a
|
||||
list. Similarly, a non-list pair is printed with the dot notation, and
|
||||
a dot on input effectively runs the dot-notation rules in reverse to
|
||||
obtain a pair.
|
||||
|
||||
One consequence of the read layer for expressions is that you can use
|
||||
the dot notation in expressions that are not quoted forms:
|
||||
|
@ -221,8 +221,9 @@ the dot notation in expressions that are not quoted forms:
|
|||
]
|
||||
|
||||
This works because @scheme[(+ 1 . #, @scheme[(2)])] is just another
|
||||
way of writing @scheme[(+ 1 2)]. Of course, it is practically never a
|
||||
good idea to write application expressions using this dot notation.
|
||||
way of writing @scheme[(+ 1 2)]. It is practically never a good idea
|
||||
to write application expressions using this dot notation; it's just a
|
||||
consequence of the way Scheme's syntax is defined.
|
||||
|
||||
The rule for converting @litchar{'} to a use of @scheme[quote] is also
|
||||
defined at the read level. If you (accidentally) use
|
||||
|
@ -244,8 +245,8 @@ when you understand the reader's conversion:
|
|||
|
||||
The second example fails because @scheme['#, @schemeidfont{shakey}] is
|
||||
really @scheme[(#, @schemeidfont{quote} #, @schemeidfont{shakey})],
|
||||
which means the application of the @scheme[shakey] procedure's
|
||||
argument (which turns out to be a string, not a procedure).
|
||||
which means the application of @scheme[shakey]'s argument (which turns
|
||||
out to be a string, not a procedure).
|
||||
|
||||
A few other character combinations trigger @litchar{'}-like
|
||||
conversions, including @litchar{`}, @litchar{,}, @litchar["@,"], and
|
||||
|
@ -257,9 +258,9 @@ Normally, @litchar{.} is allowed by the reader only with a
|
|||
parenthesized sequence, and only before the last element of the
|
||||
sequence. However, a pair of @litchar{.}s can also appear around a
|
||||
single element in a parenthesized sequence, as long as the element is
|
||||
not first or last. Such a pair triggers a reader conversion that
|
||||
moves the element between @litchar{.}s to the front of the list, which
|
||||
enables a kind of general infix notation:
|
||||
not first or last. Such a pair triggers a reader conversion that moves
|
||||
the element between @litchar{.}s to the front of the list. The
|
||||
conversion enables a kind of general infix notation:
|
||||
|
||||
@interaction[
|
||||
(1 . < . 2)
|
||||
|
|
|
@ -39,15 +39,10 @@ command-line @exec{mzscheme} interpreter and your favorite text
|
|||
editor. The rest of this guide presents the language mostly
|
||||
independent of the tool that you use.
|
||||
|
||||
If you read @Quick and you're still using DrScheme, you already know
|
||||
about interactions and definitions. You can safely skip to
|
||||
@secref["indentation"], with the caveat that we call the interactions
|
||||
window the @defterm{REPL} in this guide.
|
||||
|
||||
Otherwise, if you're using DrScheme, you'll need to set it in the
|
||||
right mode, because DrScheme is less biased to a particular Scheme
|
||||
variant than @exec{mzscheme}. Assuming that you've never used DrScheme
|
||||
before, start it up, type the line
|
||||
If you're using DrScheme, you'll need to set it in the right mode,
|
||||
because DrScheme is less biased to a particular Scheme variant than
|
||||
@exec{mzscheme}. Assuming that you've never used DrScheme before,
|
||||
start it up, type the line
|
||||
|
||||
@schememod[big]
|
||||
|
||||
|
@ -167,7 +162,7 @@ bad performance, and awkward scripting to combine and run
|
|||
programs. The problems are not in @exec{mzscheme}'s implementation;
|
||||
they're fundamental limitations of the traditional top-level
|
||||
environment, which Scheme and Lisp implementations have historically
|
||||
combated through ad hoc command-line flags, compiler directives, and
|
||||
fought with ad hoc command-line flags, compiler directives, and
|
||||
build tools. The module system is to designed to avoid the problems,
|
||||
so start with @schemefont{#module}, and you'll be happier with Scheme
|
||||
in the long run.
|
||||
|
|
|
@ -227,7 +227,7 @@ anonymous procedure:
|
|||
|
||||
@mr-interaction[(series (lambda (size) (checkerboard (square size))))]
|
||||
|
||||
The parenthesized name(s) after a @scheme[lambda] are the argument to
|
||||
The parenthesized names after a @scheme[lambda] are the arguments to
|
||||
the procedure, and the expression after the argument names is the
|
||||
procedure body. Using the word ``lambda'' instead of ``function'' or
|
||||
``procedure'' is part of Scheme's history and culture.
|
||||
|
@ -243,10 +243,7 @@ A procedure-form @scheme[define] is really a shorthand for a simple
|
|||
]
|
||||
|
||||
Most Schemers prefer to use the shorthand procedure form with
|
||||
@scheme[define] instead of expanding to @scheme[lambda], but
|
||||
@scheme[lambda] shows up often with @scheme[letrec] to define mutually
|
||||
recursive procedures; see @link["elsewhere"]{elsewhere} for
|
||||
examples.
|
||||
@scheme[define] instead of expanding to @scheme[lambda].
|
||||
|
||||
@; ----------------------------------------------------------------------
|
||||
@section{Lexical Scope}
|
||||
|
@ -258,8 +255,8 @@ binding. This rule applies to identifiers in a @scheme[lambda] body as
|
|||
well as anywhere else.
|
||||
|
||||
For example, in the following @scheme[color-series] procedure the uses
|
||||
of @scheme[mk] in each @scheme[lambda] form refer to the argument of
|
||||
@scheme[color-series], since that's the binding that textually in
|
||||
of @scheme[mk] in each @scheme[lambda] form to refer to the argument of
|
||||
@scheme[color-series], since that's the binding that is textually in
|
||||
scope:
|
||||
|
||||
@mr-def+int[
|
||||
|
@ -300,7 +297,7 @@ The @scheme[list] procedure takes any number of arguments and returns
|
|||
a list containing the given values:
|
||||
|
||||
@mr-interaction[(list "red" "green" "blue")
|
||||
(list (circle 10) (square 10))]
|
||||
(list (circle 10) (square 10))]
|
||||
|
||||
As you can see, a list prints as a pair of parentheses wrapped around
|
||||
the printed form of the list elements. There's room for confusion
|
||||
|
@ -308,12 +305,14 @@ here, because parentheses are used for both expressions, such as
|
|||
@scheme[(circle 10)], and printed results, such as
|
||||
@schemeresult[("red" "green" "blue")]. This connection between
|
||||
expressions and printed results is no coincidence, but we save that
|
||||
bit of culture for @link["elsewhere"]{discussion elsewhere}.
|
||||
bit of culture for @link["elsewhere"]{discussion elsewhere}. In the
|
||||
documentation and in DrScheme, result parentheses are printed in blue,
|
||||
unlike expression parentheses.
|
||||
|
||||
If you have a list, then you'll eventually want to do something with
|
||||
each of the elements. The @scheme[map] procedure takes a list and a
|
||||
procedure to apply to each element of the list; it returns a new list
|
||||
to report the procedure's results:
|
||||
to combine the procedure's results:
|
||||
|
||||
@mr-def+int[
|
||||
(define (rainbow p)
|
||||
|
@ -444,7 +443,7 @@ that @schememodname[little] provides @scheme[require] and the
|
|||
procedure-calling syntax. Libraries are not restricted to exporting
|
||||
values, such as procedures; they can also define new syntax. In this
|
||||
sense, Scheme isn't exactly language at all; it's more of an idea for
|
||||
how to structure a language to that you can extend it or create
|
||||
how to structure a language so that you can extend it or create
|
||||
entirely new languages.
|
||||
|
||||
One way to introduce a new syntactic form is through
|
||||
|
|
Loading…
Reference in New Issue
Block a user