DOC HOME SITE MAP MAN PAGES GNU INFO SEARCH
 

(r5rs.info.gz) Control features

Info Catalog (r5rs.info.gz) Other data types (r5rs.info.gz) Standard procedures (r5rs.info.gz) Eval
 
 6.4 Control features
 ====================
 
 This chapter describes various primitive procedures which control the
 flow of program execution in special ways.  The `procedure?' predicate
 is also described here.
 
  -- procedure: procedure? obj
      Returns #t if OBJ is a procedure, otherwise returns #f.
 
      (procedure? car)                       ==>  #t
      (procedure? 'car)                      ==>  #f
      (procedure? (lambda (x) (* x x)))
                                             ==>  #t
      (procedure? '(lambda (x) (* x x)))
                                             ==>  #f
      (call-with-current-continuation procedure?)
                                             ==>  #t
 
 
  -- procedure: apply proc arg1 ... args
      PROC must be a procedure and ARGS must be a list.  Calls PROC with
      the elements of the list `(append (list ARG1 ...,) ARGS)' as the
      actual arguments.
 
      (apply + (list 3 4))                   ==>  7
 
      (define compose
        (lambda (f g)
          (lambda args
            (f (apply g args)))))
 
      ((compose sqrt *) 12 75)               ==>  30
 
 
  -- library procedure: map proc list1 list2 ...,
      The LISTs must be lists, and PROC must be a procedure taking as
      many arguments as there are lists and returning a single value.
      If more than one LIST is given, then they must all be the same
      length.  `Map' applies PROC element-wise to the elements of the
      LISTs and returns a list of the results, in order.  The dynamic
      order in which PROC is applied to the elements of the LISTs is
      unspecified.
 
      (map cadr '((a b) (d e) (g h)))
                ==>  (b e h)
 
      (map (lambda (n) (expt n n))
           '(1 2 3 4 5))
                ==>  (1 4 27 256 3125)
 
      (map + '(1 2 3) '(4 5 6))              ==>  (5 7 9)
 
      (let ((count 0))
        (map (lambda (ignored)
               (set! count (+ count 1))
               count)
             '(a b)))                        ==>  (1 2) OR (2 1)
 
 
  -- library procedure: for-each proc list1 list2 ...,
      The arguments to `for-each' are like the arguments to `map', but
      `for-each' calls PROC for its side effects rather than for its
      values.  Unlike `map', `for-each' is guaranteed to call PROC on
      the elements of the LISTs in order from the first element(s) to the
      last, and the value returned by `for-each' is unspecified.
 
      (let ((v (make-vector 5)))
        (for-each (lambda (i)
                    (vector-set! v i (* i i)))
                  '(0 1 2 3 4))
        v)                                   ==>  #(0 1 4 9 16)
 
 
  -- library procedure: force promise
      Forces the value of PROMISE (see `delay', section  Delayed
      evaluation).  If no value has been computed for the promise,
      then a value is computed and returned.  The value of the promise
      is cached (or "memoized") so that if it is forced a second time,
      the previously computed value is returned.
 
      (force (delay (+ 1 2)))                ==>  3
      (let ((p (delay (+ 1 2))))
        (list (force p) (force p)))
                                             ==>  (3 3)
 
      (define a-stream
        (letrec ((next
                  (lambda (n)
                    (cons n (delay (next (+ n 1)))))))
          (next 0)))
      (define head car)
      (define tail
        (lambda (stream) (force (cdr stream))))
 
      (head (tail (tail a-stream)))
                                             ==>  2
 
      `Force' and `delay' are mainly intended for programs written in
      functional style.  The following examples should not be considered
      to illustrate good programming style, but they illustrate the
      property that only one value is computed for a promise, no matter
      how many times it is forced.
 
      (define count 0)
      (define p
        (delay (begin (set! count (+ count 1))
                      (if (> count x)
                          count
                          (force p)))))
      (define x 5)
      p                                      ==>  a promise
      (force p)                              ==>  6
      p                                      ==>  a promise, still
      (begin (set! x 10)
             (force p))                      ==>  6
 
      Here is a possible implementation of `delay' and `force'.
      Promises are implemented here as procedures of no arguments, and
      `force' simply calls its argument:
 
      (define force
        (lambda (object)
          (object)))
 
      We define the expression
 
      (delay <expression>)
 
      to have the same meaning as the procedure call
 
      (make-promise (lambda () <expression>))
 
      as follows
 
      (define-syntax delay
        (syntax-rules ()
          ((delay expression)
           (make-promise (lambda () expression))))),
 
      where `make-promise' is defined as follows:
 
      (define make-promise
        (lambda (proc)
          (let ((result-ready? #f)
                (result #f))
            (lambda ()
              (if result-ready?
                  result
                  (let ((x (proc)))
                    (if result-ready?
                        result
                        (begin (set! result-ready? #t)
                               (set! result x)
                               result))))))))
 
           _Rationale:_ A promise may refer to its own value, as in the
           last example above.  Forcing such a promise may cause the
           promise to be forced a second time before the value of the
           first force has been computed.  This complicates the
           definition of `make-promise'.
 
      Various extensions to this semantics of `delay' and `force' are
      supported in some implementations:
 
         * Calling `force' on an object that is not a promise may simply
           return the object.
 
         * It may be the case that there is no means by which a promise
           can be operationally distinguished from its forced value.
           That is, expressions like the following may evaluate to
           either #t or to #f, depending on the implementation:
 
           (eqv? (delay 1) 1)                ==>  _unspecified_
           (pair? (delay (cons 1 2)))        ==>  _unspecified_
 
         * Some implementations may implement "implicit forcing," where
           the value of a promise is forced by primitive procedures like
           `cdr' and `+':
 
           (+ (delay (* 3 7)) 13)            ==>  34
 
 
 
  -- procedure: call-with-current-continuation proc
      PROC must be a procedure of one argument. The procedure
      `call-with-current-continuation' packages up the current
      continuation (see the rationale below) as an "escape procedure"
      and passes it as an argument to PROC.  The escape procedure is a
      Scheme procedure that, if it is later called, will abandon
      whatever continuation is in effect at that later time and will
      instead use the continuation that was in effect when the escape
      procedure was created.  Calling the escape procedure may cause the
      invocation of BEFORE and AFTER thunks installed using
      `dynamic-wind'.  
 
      The escape procedure accepts the same number of arguments as the
      continuation to the original call to
      call-with-current-continuation.  Except for continuations created
      by the `call-with-values' procedure, all continuations take
      exactly one value.  The effect of passing no value or more than
      one value to continuations that were not created by
      call-with-values is unspecified.
 
      The escape procedure that is passed to PROC has unlimited extent
      just like any other procedure in Scheme.  It may be stored in
      variables or data structures and may be called as many times as
      desired.
 
      The following examples show only the most common ways in which
      `call-with-current-continuation' is used.  If all real uses were as
      simple as these examples, there would be no need for a procedure
      with the power of `call-with-current-continuation'.
 
      (call-with-current-continuation
        (lambda (exit)
          (for-each (lambda (x)
                      (if (negative? x)
                          (exit x)))
                    '(54 0 37 -3 245 19))
          #t))                               ==>  -3
 
      (define list-length
        (lambda (obj)
          (call-with-current-continuation
            (lambda (return)
              (letrec ((r
                        (lambda (obj)
                          (cond ((null? obj) 0)
                                ((pair? obj)
                                 (+ (r (cdr obj)) 1))
                                (else (return #f))))))
                (r obj))))))
 
      (list-length '(1 2 3 4))               ==>  4
 
      (list-length '(a b . c))               ==>  #f
 
           _Rationale:_
 
           A common use of `call-with-current-continuation' is for
           structured, non-local exits from loops or procedure bodies,
           but in fact `call-with-current-continuation' is extremely
           useful for implementing a wide variety of advanced control
           structures.
 
           Whenever a Scheme expression is evaluated there is a
           "continuation" wanting the result of the expression.  The
           continuation represents an entire (default) future for the
           computation.  If the expression is evaluated at top level,
           for example, then the continuation might take the result,
           print it on the screen, prompt for the next input, evaluate
           it, and so on forever.  Most of the time the continuation
           includes actions specified by user code, as in a continuation
           that will take the result, multiply it by the value stored in
           a local variable, add seven, and give the answer to the top
           level continuation to be printed.  Normally these ubiquitous
           continuations are hidden behind the scenes and programmers do
           not think much about them.  On rare occasions, however, a
           programmer may need to deal with continuations explicitly.
           `Call-with-current-continuation' allows Scheme programmers to
           do that by creating a procedure that acts just like the
           current continuation.
 
           Most programming languages incorporate one or more
           special-purpose escape constructs with names like exit,
           `return', or even goto.  In 1965, however, Peter Landin
           [Landin65] invented a general purpose escape operator called
           the J-operator.  John Reynolds [Reynolds72] described a
           simpler but equally powerful construct in 1972.  The `catch'
           special form described by Sussman and Steele in the 1975
           report on Scheme is exactly the same as Reynolds's construct,
           though its name came from a less general construct in
           MacLisp.  Several Scheme implementors noticed that the full
           power of the `catch' construct could be provided by a
           procedure instead of by a special syntactic construct, and
           the name `call-with-current-continuation' was coined in 1982.
           This name is descriptive, but opinions differ on the merits
           of such a long name, and some people use the name `call/cc'
           instead.  
 
 
  -- procedure: values obj ...
      Delivers all of its arguments to its continuation.  Except for
      continuations created by the `call-with-values' procedure, all
      continuations take exactly one value.  Values might be defined as
      follows:
 
      (define (values . things)
        (call-with-current-continuation
          (lambda (cont) (apply cont things))))
 
 
  -- procedure: call-with-values producer consumer
      Calls its PRODUCER argument with no values and a continuation
      that, when passed some values, calls the CONSUMER procedure with
      those values as arguments.  The continuation for the call to
      CONSUMER is the continuation of the call to call-with-values.
 
      (call-with-values (lambda () (values 4 5))
                        (lambda (a b) b))
                                                         ==>  5
 
      (call-with-values * -)                             ==>  -1
 
 
  -- procedure: dynamic-wind before thunk after
      Calls THUNK without arguments, returning the result(s) of this
      call.  BEFORE and AFTER are called, also without arguments, as
      required by the following rules (note that in the absence of calls
      to continuations captured using `call-with-current-continuation'
      the three arguments are called once each, in order).  BEFORE is
      called whenever execution enters the dynamic extent of the call to
      THUNK and AFTER is called whenever it exits that dynamic extent.
      The dynamic extent of a procedure call is the period between when
      the call is initiated and when it returns.  In Scheme, because of
      `call-with-current-continuation', the dynamic extent of a call may
      not be a single, connected time period.  It is defined as follows:
 
         * The dynamic extent is entered when execution of the body of
           the called procedure begins.
 
         * The dynamic extent is also entered when execution is not
           within the dynamic extent and a continuation is invoked that
           was captured (using `call-with-current-continuation') during
           the dynamic extent.
 
         * It is exited when the called procedure returns.
 
         * It is also exited when execution is within the dynamic extent
           and a continuation is invoked that was captured while not
           within the dynamic extent.
 
 
      If a second call to `dynamic-wind' occurs within the dynamic
      extent of the call to THUNK and then a continuation is invoked in
      such a way that the AFTERs from these two invocations of
      `dynamic-wind' are both to be called, then the AFTER associated
      with the second (inner) call to `dynamic-wind' is called first.
 
      If a second call to `dynamic-wind' occurs within the dynamic
      extent of the call to THUNK and then a continuation is invoked in
      such a way that the BEFOREs from these two invocations of
      `dynamic-wind' are both to be called, then the BEFORE associated
      with the first (outer) call to `dynamic-wind' is called first.
 
      If invoking a continuation requires calling the BEFORE from one
      call to `dynamic-wind' and the AFTER from another, then the AFTER
      is called first.
 
      The effect of using a captured continuation to enter or exit the
      dynamic extent of a call to BEFORE or AFTER is undefined.
 
      (let ((path '())
            (c #f))
        (let ((add (lambda (s)
                     (set! path (cons s path)))))
          (dynamic-wind
            (lambda () (add 'connect))
            (lambda ()
              (add (call-with-current-continuation
                     (lambda (c0)
                       (set! c c0)
                       'talk1))))
            (lambda () (add 'disconnect)))
          (if (< (length path) 4)
              (c 'talk2)
              (reverse path))))
 
                ==> (connect talk1 disconnect
                     connect talk2 disconnect)
 
 
Info Catalog (r5rs.info.gz) Other data types (r5rs.info.gz) Standard procedures (r5rs.info.gz) Eval
automatically generated byinfo2html