[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Procedures are created by evaluating lambda
expressions
(see section 2.1 Lambda Expressions); the lambda
may either be explicit
or may be implicit as in a "procedure define
"
(see section 2.4 Definitions). Also there are special built-in procedures,
called primitive procedures, such as car
; these procedures
are not written in Scheme but in the language used to implement the
Scheme system. MIT Scheme also provides application hooks, which
support the construction of data structures that act like procedures.
In MIT Scheme, the written representation of a procedure tells you the type of the procedure (compiled, interpreted, or primitive):
pp => #[compiled-procedure 56 ("pp" #x2) #x10 #x307578] (lambda (x) x) => #[compound-procedure 57] (define (foo x) x) foo => #[compound-procedure 58 foo] car => #[primitive-procedure car] (call-with-current-continuation (lambda (x) x)) => #[continuation 59] |
Note that interpreted procedures are called "compound" procedures (strictly speaking, compiled procedures are also compound procedures). The written representation makes this distinction for historical reasons, and may eventually change.
12.1 Procedure Operations 12.2 Primitive Procedures 12.3 Continuations 12.4 Application Hooks
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
(cons* object object ...) |
The initial objects may be any objects, but the last object (there must be at least one object) must be a list.
(apply + (list 3 4 5 6)) => 18 (apply + 3 4 '(5 6)) => 18 (define compose (lambda (f g) (lambda args (f (apply g args))))) ((compose sqrt *) 12 75) => 30 |
#t
if object is a procedure; otherwise returns
#f
. If #t
is returned, exactly one of the following
predicates is satisfied by object: compiled-procedure?
,
compound-procedure?
, or primitive-procedure?
.
#t
if object is a compiled procedure; otherwise
returns #f
.
#t
if object is a compound (i.e. interpreted)
procedure; otherwise returns #f
.
#t
if object is a primitive procedure; otherwise
returns #f
.
The following two procedures test the arity of a procedure, that
is, the number of arguments that the procedure accepts. The results of
the test may be less restrictive than the effect of calling the
procedure. In other words, these procedures may indicate that the
procedure will accept a given number of arguments, but if you call the
procedure it may signal a
condition-type:wrong-number-of-arguments
error. This is because
these procedures examine the apparent arity of a procedure. For
example, here is a procedure that appears to accept any number of
arguments, but when called will signal an error if the number of
arguments is not one:
(lambda arguments (apply car arguments)) |
#t
if procedure accepts k arguments;
otherwise returns #f
.
#f
meaning
that the procedure has no maximum number of arguments.
(procedure-arity (lambda () 3)) => (0 . 0) (procedure-arity (lambda (x) x)) => (1 . 1) (procedure-arity car) => (1 . 1) (procedure-arity (lambda x x)) => (0 . #f) (procedure-arity (lambda (x . y) x)) => (1 . #f) (procedure-arity (lambda (x #!optional y) x)) => (1 . 2) |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
-1
, #f
, or #t
; if not supplied it defaults
to #f
. Returns the primitive procedure called name. May
perform further actions depending on arity:
#f
#t
#f
.
-1
means it
accepts any number of arguments.
(primitive-procedure-name car) => car |
#t
if primitive-procedure is implemented; otherwise
returns #f
. Useful because the code that implements a particular
primitive procedure is not necessarily linked into the executable Scheme
program.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
call-with-current-continuation
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 uses of this procedure.
If all real programs 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 |
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 quite useful for implementing a
wide variety of advanced control structures.
Whenever a Scheme expression is evaluated a continuation exists that
wants 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, the continuation will 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
don't think much about them. On the rare occasions that you may need to
deal explicitly with continuations,
call-with-current-continuation
lets you do so by creating a
procedure that acts just like the current continuation.
#t
if object is a continuation; otherwise returns
#f
.
within-continuation
invokes continuation on the result of
invoking thunk, but thunk is executed in the dynamic context
of continuation. In other words, the "current" continuation is
abandoned before thunk is invoked.
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:
call-with-current-continuation
) during 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) |
The following two procedures support multiple values.
values
procedure. Then procedure is called with the
multiple values as its arguments. The result yielded by procedure
is returned as the result of call-with-values
.
call-with-values
. Furthermore it must accept as many values as
there are objects.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Application hooks are objects that can be applied like procedures. Each application hook has two parts: a procedure that specifies what to do when the application hook is applied, and an arbitrary object, called extra. Often the procedure uses the extra object to determine what to do.
There are two kinds of application hooks, which differ in what arguments are passed to the procedure. When an apply hook is applied, the procedure is passed exactly the same arguments that were passed to the apply hook. When an entity is applied, the entity itself is passed as the first argument, followed by the other arguments that were passed to the entity.
Both apply hooks and entities satisfy the predicate procedure?
.
Each satisfies either compiled-procedure?
,
compound-procedure?
, or primitive-procedure?
, depending on
its procedure component. An apply hook is considered to accept the same
number of arguments as its procedure, while an entity is considered to
accept one less argument than its procedure.
#t
if object is an apply hook; otherwise returns
#f
.
#t
if object is an entity; otherwise returns
#f
.
[ << ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |