Go to the first, previous, next, last section, table of contents.


General Utility Functions

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.

Equality

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.

Scheme Procedure: eq? x y
Return #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?.

Scheme Procedure: eqv? x y
The 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.

Scheme Procedure: equal? x y
Return #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.

Object Properties

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

Scheme Procedure: make-object-property
Create and return an object property. An object property is a procedure-with-setter that can be called in two ways. (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.

Low Level Property Implementation.

Scheme Procedure: primitive-make-property not_found_proc
C Function: scm_primitive_make_property (not_found_proc)
Create a property token that can be used with primitive-property-ref and primitive-property-set!. See primitive-property-ref for the significance of not_found_proc.

Scheme Procedure: primitive-property-ref prop obj
C Function: scm_primitive_property_ref (prop, obj)
Return the property prop of obj. When no value has yet been associated with prop and obj, call not-found-proc instead (see 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.

Scheme Procedure: primitive-property-set! prop obj val
C Function: scm_primitive_property_set_x (prop, obj, val)
Associate code with prop and obj.

Scheme Procedure: primitive-property-del! prop obj
C Function: scm_primitive_property_del_x (prop, obj)
Remove any value associated with prop and obj.

An Older Approach to Properties

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

Scheme Procedure: object-properties obj
C Function: scm_object_properties (obj)
Return obj's property list.

Scheme Procedure: set-object-properties! obj alist
C Function: scm_set_object_properties_x (obj, alist)
Set obj's property list to alist.

Scheme Procedure: object-property obj key
C Function: scm_object_property (obj, key)
Return the property of obj with name key.

Scheme Procedure: set-object-property! obj key value
C Function: scm_set_object_property_x (obj, key, value)
In obj's property list, set the property named key to value.

Sorting

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.

Scheme Procedure: merge alist blist less
C Function: scm_merge (alist, blist, less)
Merge two already sorted lists into one. Given two lists alist and blist, such that (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.

Scheme Procedure: merge! alist blist less
C Function: scm_merge_x (alist, blist, less)
Takes two lists alist and blist such that (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.

Scheme Procedure: sorted? items less
C Function: scm_sorted_p (items, less)
Return #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

Scheme Procedure: sort items less
C Function: scm_sort (items, less)
Sort the sequence items, which may be a list or a vector. less is used for comparing the sequence elements. This is not a stable sort.

Scheme Procedure: sort! items less
C Function: scm_sort_x (items, less)
Sort the sequence items, which may be a list or a vector. less is used for comparing the sequence elements. The sorting is destructive, that means that the input sequence is modified to produce the sorted result. This is not a stable sort.

Scheme Procedure: stable-sort items less
C Function: scm_stable_sort (items, less)
Sort the sequence items, which may be a list or a vector. less is used for comparing the sequence elements. This is a stable sort.

Scheme Procedure: stable-sort! items less
C Function: scm_stable_sort_x (items, less)
Sort the sequence items, which may be a list or a vector. less is used for comparing the sequence elements. The sorting is destructive, that means that the input sequence is modified to produce the sorted result. This is a stable sort.

The procedures in the last group only accept lists or vectors as input, as their names indicate.

Scheme Procedure: sort-list items less
C Function: scm_sort_list (items, less)
Sort the list items, using less for comparing the list elements. This is a stable sort.

Scheme Procedure: sort-list! items less
C Function: scm_sort_list_x (items, less)
Sort the list items, using less for comparing the list elements. The sorting is destructive, that means that the input list is modified to produce the sorted result. This is a stable sort.

Scheme Procedure: restricted-vector-sort! vec less startpos endpos
C Function: scm_restricted_vector_sort_x (vec, less, startpos, endpos)
Sort the vector vec, using less for comparing the vector elements. startpos and endpos delimit the range of the vector which gets sorted. The return value is not specified.

Copying Deep Structures

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.

Scheme Procedure: copy-tree obj
C Function: scm_copy_tree (obj)
Recursively copy the data tree that is bound to obj, and return a pointer to the new data structure. 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.

General String Conversion

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.

Scheme Procedure: object->string obj [printer]
C Function: scm_object_to_string (obj, printer)
Return a Scheme string obtained by printing obj. Printing function can be specified by the optional second argument printer (default: write).

Hooks

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 by Example

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

Hook Reference

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.

Scheme Procedure: make-hook [n_args]
C Function: scm_make_hook (n_args)
Create a hook for storing procedure of arity n_args. n_args defaults to zero. The returned value is a hook object to be used with the other hook procedures.

Scheme Procedure: hook? x
C Function: scm_hook_p (x)
Return #t if x is a hook, #f otherwise.

Scheme Procedure: hook-empty? hook
C Function: scm_hook_empty_p (hook)
Return #t if hook is an empty hook, #f otherwise.

Scheme Procedure: add-hook! hook proc [append_p]
C Function: scm_add_hook_x (hook, proc, append_p)
Add the procedure proc to the hook hook. The procedure is added to the end if append_p is true, otherwise it is added to the front. The return value of this procedure is not specified.

Scheme Procedure: remove-hook! hook proc
C Function: scm_remove_hook_x (hook, proc)
Remove the procedure proc from the hook hook. The return value of this procedure is not specified.

Scheme Procedure: reset-hook! hook
C Function: scm_reset_hook_x (hook)
Remove all procedures from the hook hook. The return value of this procedure is not specified.

Scheme Procedure: hook->list hook
C Function: scm_hook_to_list (hook)
Convert the procedure list of hook to a list.

Scheme Procedure: run-hook hook . args
C Function: scm_run_hook (hook, args)
Apply all procedures from the hook hook to the arguments args. The order of the procedure application is first to last. The return value of this procedure is not specified.

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.

C Function: void scm_c_run_hook (SCM hook, SCM args)
The same as 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.

Hooks For C Code.

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.

C Type: scm_t_c_hook
Data type for a C hook. The internals of this type should be treated as opaque.

C Enum: scm_t_c_hook_type
Enumeration of possible hook types, which are:
SCM_C_HOOK_NORMAL
Type of hook for which all the registered functions will always be called.
SCM_C_HOOK_OR
Type of hook for which the sequence of registered functions will be called only until one of them returns C true (a non-NULL pointer).
SCM_C_HOOK_AND
Type of hook for which the sequence of registered functions will be called only until one of them returns C false (a NULL pointer).

C Function: void scm_c_hook_init (scm_t_c_hook *hook, void *hook_data, scm_t_c_hook_type type)
Initialize the C hook at memory pointed to by hook. type should be one of the values of the 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:

hook_data
The hook closure data that was specified at the time the hook was initialized by scm_c_hook_init.
func_data
The function closure data that was specified at the time that that function was registered with the hook by scm_c_hook_add.
data
The call closure data specified by the scm_c_hook_run call that runs the hook.

C Type: scm_t_c_hook_function
Function type for a C hook function: takes three void * parameters and returns a void * result.

C Function: void scm_c_hook_add (scm_t_c_hook *hook, scm_t_c_hook_function func, void *func_data, int appendp)
Add function func, with function closure data func_data, to the C hook hook. The new function is appended to the hook's list of functions if appendp is non-zero, otherwise prepended.

C Function: void scm_c_hook_remove (scm_t_c_hook *hook, scm_t_c_hook_function func, void *func_data)
Remove function func, with function closure data func_data, from the C hook hook. 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:

C Function: void * scm_c_hook_run (scm_t_c_hook *hook, void *data)
Run the C hook hook will call closure data data. Subject to the variations for hook types 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.

Hooks Provided by Guile

Hooks for Garbage Collection

Whenever Guile performs a garbage collection, it calls the following hooks in the order shown.

C Hook: scm_before_gc_c_hook
C hook called at the very start of a garbage collection, after setting 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.

C Hook: scm_before_mark_c_hook
C hook called before beginning the mark phase of garbage collection, after the GC thread has entered a critical section.

C Hook: scm_before_sweep_c_hook
C hook called before beginning the sweep phase of garbage collection. This is the same as at the end of the mark phase, since nothing else happens between marking and sweeping.

C Hook: scm_after_sweep_c_hook
C hook called after the end of the sweep phase of garbage collection, but while the GC thread is still inside its critical section.

C Hook: scm_after_gc_c_hook
C hook called at the very end of a garbage collection, after the GC thread has left its critical section.

Scheme Hook: after-gc-hook
Scheme hook with arity 0. This hook is run asynchronously (see section Asyncs) soon after the GC has completed and any other events that were deferred during garbage collection have been processed. (Also accessible from C with the name 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.

Hooks into the Guile REPL


Go to the first, previous, next, last section, table of contents.