#lang scribble/doc
@(require scribble/manual
          scribble/eval
          "guide-utils.ss")

@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. Otherwise, no @racket[_then-expr]s
are evaluated. The result is @|void-const| in any case.

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)
]
