This chapter contains information about procedures which are not cleanly tied to a specific data type. Because of their wide range of applications, they are collected in a utility chapter.
Three different kinds of sameness are defined in Scheme.
The differentiation between these three kinds is important, because determining whether two values are the same objects is very efficient, while determining structural equivalence can be quite expensive (consider comparing two very long lists). Therefore, three different procedures for testing for equality are provided, which correspond to the three kinds of sameness defined above.
#t iff x references the same object as y.
eq? is similar to eqv? except that in some cases it is
capable of discerning distinctions finer than those detectable by
eqv?.
eqv? procedure defines a useful equivalence relation on objects.
Briefly, it returns #t if x and y should normally be
regarded as the same object. This relation is left slightly open to
interpretation, but works for comparing immediate integers, characters,
and inexact numbers.
#t iff x and y are recursively eqv? equivalent.
equal? recursively compares the contents of pairs,
vectors, and strings, applying eqv? on other objects such as
numbers and symbols. A rule of thumb is that objects are generally
equal? if they print the same. equal? may fail to
terminate if its arguments are circular data structures.
It's often useful to associate a piece of additional information with a Scheme object even though that object does not have a dedicated slot available in which the additional information could be stored. Object properties allow you to do just that.
An object property is most commonly used to associate one kind of
additional information with each instance of a class of similar Scheme
objects. For example, all procedures have a `name' property, which
stores the name of the variable in which the procedure was stored by a
define expression, or #f if the procedure wasn't created
by that kind of expression.
Guile's representation of an object property is a procedure-with-setter
(see section Procedures with Setters) that can be used with the generalized
form of set! (REFFIXME) to set and retrieve that property for any
Scheme object. So, setting a property looks like this:
(set! (my-property obj1) value-for-obj1) (set! (my-property obj2) value-for-obj2)
And retrieving values of the same property looks like this:
(my-property obj1) => value-for-obj1 (my-property obj2) => value-for-obj2
To create an object property in the first place, use the
make-object-property procedure:
(define my-property (make-object-property))
(set!
(property obj) val) sets obj's property
to val. (property obj) returns the current
setting of obj's property.
A single object property created by make-object-property can
associate distinct property values with all Scheme values that are
distinguishable by eq? (including, for example, integers).
Internally, object properties are implemented using a weak key hash table. This means that, as long as a Scheme value with property values is protected from garbage collection, its property values are also protected. When the Scheme value is collected, its entry in the property table is removed and so the (ex-) property values are no longer protected by the table.
primitive-property-ref and primitive-property-set!.
See primitive-property-ref for the significance of
not_found_proc.
primitive-make-property)
and use its return value. That value is also associated with
obj via primitive-property-set!. When
not-found-proc is #f, use #f as the
default value of prop.
Traditionally, Lisp systems provide a different object property
interface to that provided by make-object-property, in which the
object property that is being set or retrieved is indicated by a symbol.
Guile includes this older kind of interface as well, but it may well be
removed in a future release, as it is less powerful than
make-object-property and so increases the size of the Guile
library for no benefit. (And it is trivial to write a compatibility
layer in Scheme.)
Sorting is very important in computer programs. Therefore, Guile comes
with several sorting procedures built-in. As always, procedures with
names ending in ! are side-effecting, that means that they may
modify their parameters in order to produce their results.
The first group of procedures can be used to merge two lists (which must be already sorted on their own) and produce sorted lists containing all elements of the input lists.
(sorted? alist less?) and (sorted? blist less?),
return a new list in which the elements of alist and
blist have been stably interleaved so that
(sorted? (merge alist blist less?) less?).
Note: this does _not_ accept vectors.
(sorted? alist less?) and (sorted? blist less?) and
returns a new list in which the elements of alist and
blist have been stably interleaved so that
(sorted? (merge alist blist less?) less?).
This is the destructive variant of merge
Note: this does _not_ accept vectors.
The following procedures can operate on sequences which are either
vectors or list. According to the given arguments, they return sorted
vectors or lists, respectively. The first of the following procedures
determines whether a sequence is already sorted, the other sort a given
sequence. The variants with names starting with stable- are
special in that they maintain a special property of the input sequences:
If two or more elements are the same according to the comparison
predicate, they are left in the same order as they appeared in the
input.
#t iff items is a list or a vector such that
for all 1 <= i <= m, the predicate less returns true when
applied to all elements i - 1 and i
The procedures in the last group only accept lists or vectors as input, as their names indicate.
The procedures for copying lists (see section Lists) only produce a flat
copy of the input list, and currently Guile does not even contain
procedures for copying vectors. copy-tree can be used for these
application, as it does not only copy the spine of a list, but also
copies any pairs in the cars of the input lists.
copy-tree recurses down the
contents of both pairs and vectors (since both cons cells and vector
cells may point to arbitrary objects), and stops recursing when it hits
any other object.
When debugging Scheme programs, but also for providing a human-friendly interface, a procedure for converting any Scheme object into string format is very useful. Conversion from/to strings can of course be done with specialized procedures when the data type of the object to convert is known, but with this procedure, it is often more comfortable.
object->string converts an object by using a print procedure for
writing to a string port, and then returning the resulting string.
Converting an object back from the string is only possible if the object
type has a read syntax and the read syntax is preserved by the printing
procedure.
write).
A hook is a list of procedures to be called at well defined points in time. Typically, an application provides a hook h and promises its users that it will call all of the procedures in h at a defined point in the application's processing. By adding its own procedure to h, an application user can tap into or even influence the progress of the application.
Guile itself provides several such hooks for debugging and customization purposes: these are listed in a subsection below.
When an application first creates a hook, it needs to know how many arguments will be passed to the hook's procedures when the hook is run. The chosen number of arguments (which may be none) is declared when the hook is created, and all the procedures that are added to that hook must be capable of accepting that number of arguments.
A hook is created using make-hook. A procedure can be added to
or removed from a hook using add-hook! or remove-hook!,
and all of a hook's procedures can be removed together using
reset-hook!. When an application wants to run a hook, it does so
using run-hook.
Hook usage is shown by some examples in this section. First, we will define a hook of arity 2 -- that is, the procedures stored in the hook will have to accept two arguments.
(define hook (make-hook 2)) hook => #<hook 2 40286c90>
Now we are ready to add some procedures to the newly created hook with
add-hook!. In the following example, two procedures are added,
which print different messages and do different things with their
arguments.
(add-hook! hook (lambda (x y)
(display "Foo: ")
(display (+ x y))
(newline)))
(add-hook! hook (lambda (x y)
(display "Bar: ")
(display (* x y))
(newline)))
Once the procedures have been added, we can invoke the hook using
run-hook.
(run-hook hook 3 4) -| Bar: 12 -| Foo: 7
Note that the procedures are called in the reverse of the order with
which they were added. This is because the default behaviour of
add-hook! is to add its procedure to the front of the
hook's procedure list. You can force add-hook! to add its
procedure to the end of the list instead by providing a third
#t argument on the second call to add-hook!.
(add-hook! hook (lambda (x y)
(display "Foo: ")
(display (+ x y))
(newline)))
(add-hook! hook (lambda (x y)
(display "Bar: ")
(display (* x y))
(newline))
#t) ; <- Change here!
(run-hook hook 3 4)
-| Foo: 7
-| Bar: 12
When you create a hook with make-hook, you must specify the arity
of the procedures which can be added to the hook. If the arity is not
given explicitly as an argument to make-hook, it defaults to
zero. All procedures of a given hook must have the same arity, and when
the procedures are invoked using run-hook, the number of
arguments passed must match the arity specified at hook creation time.
The order in which procedures are added to a hook matters. If the third
parameter to add-hook! is omitted or is equal to #f, the
procedure is added in front of the procedures which might already be on
that hook, otherwise the procedure is added at the end. The procedures
are always called from the front to the end of the list when they are
invoked via run-hook.
The ordering of the list of procedures returned by hook->list
matches the order in which those procedures would be called if the hook
was run using run-hook.
#t if x is a hook, #f otherwise.
#t if hook is an empty hook, #f
otherwise.
If, in C code, you are certain that you have a hook object and well
formed argument list for that hook, you can also use
scm_c_run_hook, which is identical to scm_run_hook but
does no type checking.
scm_run_hook but without any type checking to confirm
that hook is actually a hook object and that args is a
well-formed list matching the arity of the hook.
The hooks already described are intended to be populated by Scheme-level procedures. In addition to this, the Guile library provides an independent set of interfaces for the creation and manipulation of hooks that are designed to be populated by functions implemented in C.
The original motivation here was to provide a kind of hook that could safely be invoked at various points during garbage collection. Scheme-level hooks are unsuitable for this purpose as running them could itself require memory allocation, which would then invoke garbage collection recursively ... However, it is also the case that these hooks are easier to work with than the Scheme-level ones if you only want to register C functions with them. So if that is mainly what your code needs to do, you may prefer to use this interface.
To create a C hook, you should allocate storage for a structure of type
scm_t_c_hook and then initialize it using scm_c_hook_init.
SCM_C_HOOK_NORMAL
SCM_C_HOOK_OR
SCM_C_HOOK_AND
scm_t_c_hook_type enumeration,
and controls how the hook functions will be called. hook_data is
a closure parameter that will be passed to all registered hook functions
when they are called.
To add or remove a C function from a C hook, use scm_c_hook_add
or scm_c_hook_remove. A hook function must expect three
void * parameters which are, respectively:
scm_c_hook_init.
scm_c_hook_add.
scm_c_hook_run call that
runs the hook.
void *
parameters and returns a void * result.
scm_c_hook_remove checks both
func and func_data so as to allow for the same func
being registered multiple times with different closure data.
Finally, to invoke a C hook, call the scm_c_hook_run function
specifying the hook and the call closure data for this run:
SCM_C_HOOK_OR and
SCM_C_HOOK_AND, scm_c_hook_run calls hook's
registered functions in turn, passing them the hook's closure data, each
function's closure data, and the call closure data.
scm_c_hook_run's return value is the return value of the last
function to be called.
Whenever Guile performs a garbage collection, it calls the following hooks in the order shown.
scm_gc_running_p to 1, but before entering the GC critical
section.
If garbage collection is blocked because scm_block_gc is
non-zero, GC exits early soon after calling this hook, and no further
hooks will be called.
scm_after_gc_hook.)
All the C hooks listed here have type SCM_C_HOOK_NORMAL, are
initialized with hook closure data NULL, are are invoked by
scm_c_hook_run with call closure data NULL.
The Scheme hook after-gc-hook is particularly useful in
conjunction with guardians (see section Guardians). Typically, if you are
using a guardian, you want to call the guardian after garbage collection
to see if any of the objects added to the guardian have been collected.
By adding a thunk that performs this call to after-gc-hook, you
can ensure that your guardian is tested after every garbage collection
cycle.
Go to the first, previous, next, last section, table of contents.