racket/collects/scribblings/guide/begin.scrbl
Asumu Takikawa 2b173612e6 Fix guide description of when
Closes PR 12445

Merge to v5.3
2012-07-23 16:00:29 -04:00

137 lines
4.1 KiB
Racket

#lang scribble/doc
@(require scribble/manual scribble/eval "guide-utils.rkt")
@title[#:tag "begin"]{Sequencing}
Racket programmers prefer to write programs with as few side-effects
as possible, since purely functional code is more easily tested and
composed into larger programs. Interaction with the external
environment, however, requires sequencing, such as when writing to a
display, opening a graphical window, or manipulating a file on disk.
@;------------------------------------------------------------------------
@section{Effects Before: @racket[begin]}
@refalso["begin"]{@racket[begin]}
A @racket[begin] expression sequences expressions:
@specform[(begin expr ...+)]{}
The @racket[_expr]s are evaluated in order, and the result of all but
the last @racket[_expr] is ignored. The result from the last
@racket[_expr] is the result of the @racket[begin] form, and it is in
tail position with respect to the @racket[begin] form.
@defexamples[
(define (print-triangle height)
(if (zero? height)
(void)
(begin
(display (make-string height #\*))
(newline)
(print-triangle (sub1 height)))))
(print-triangle 4)
]
Many forms, such as @racket[lambda] or @racket[cond] support a
sequence of expressions even without a @racket[begin]. Such positions are
sometimes said to have an @defterm{implicit begin}.
@defexamples[
(define (print-triangle height)
(cond
[(positive? height)
(display (make-string height #\*))
(newline)
(print-triangle (sub1 height))]))
(print-triangle 4)
]
The @racket[begin] form is special at the top level, at module level,
or as a @racket[body] after only internal definitions. In those
positions, instead of forming an expression, the content of
@racket[begin] is spliced into the surrounding context.
@defexamples[
(let ([curly 0])
(begin
(define moe (+ 1 curly))
(define larry (+ 1 moe)))
(list larry curly moe))
]
This splicing behavior is mainly useful for macros, as we discuss
later in @secref["macros"].
@;------------------------------------------------------------------------
@section{Effects After: @racket[begin0]}
@refalso["begin"]{@racket[begin0]}
A @racket[begin0] expression has the same syntax as a @racket[begin]
expression:
@specform[(begin0 expr ...+)]{}
The difference is that @racket[begin0] returns the result of the first
@racket[expr], instead of the result of the last @racket[expr]. The
@racket[begin0] form is useful for implementing side-effects that
happen after a computation, especially in the case where the
computation produces an unknown number of results.
@defexamples[
(define (log-times thunk)
(printf "Start: ~s\n" (current-inexact-milliseconds))
(begin0
(thunk)
(printf "End..: ~s\n" (current-inexact-milliseconds))))
(log-times (lambda () (sleep 0.1) 0))
(log-times (lambda () (values 1 2)))
]
@;------------------------------------------------------------------------
@section[#:tag "when+unless"]{Effects If...: @racket[when] and @racket[unless]}
@refalso["when+unless"]{@racket[when] and @racket[unless]}
The @racket[when] form combines an @racket[if]-style conditional with
sequencing for the ``then'' clause and no ``else'' clause:
@specform[(when test-expr then-expr ...)]
If @racket[_test-expr] produces a true value, then all of the
@racket[_then-expr]s are evaluated. The result of the last
@racket[_then-expr] is the result of the @racket[when] form.
Otherwise, no @racket[_then-expr]s are evaluated and the
result is @|void-const|.
The @racket[unless] form is similar:
@specform[(unless test-expr then-expr ...)]
The difference is that the @racket[_test-expr] result is inverted: the
@racket[_then-expr]s are evaluated only if the @racket[_test-expr]
result is @racket[#f].
@defexamples[
(define (enumerate lst)
(if (null? (cdr lst))
(printf "~a.\n" (car lst))
(begin
(printf "~a, " (car lst))
(when (null? (cdr (cdr lst)))
(printf "and "))
(enumerate (cdr lst)))))
(enumerate '("Larry" "Curly" "Moe"))
]
@def+int[
(define (print-triangle height)
(unless (zero? height)
(display (make-string height #\*))
(newline)
(print-triangle (sub1 height))))
(print-triangle 4)
]