-----

CS 151 (Artificial Intelligence)
Scheme48 Extensions and Missing Features

-----

The CS 151 class binary contains a variety of features not described in the R5RS Scheme Report, and a few R5RS features appear not to work (or work well, or work in obvious ways).

Missing features

Some of the complex number functions appear not to work in scheme48 and I don't know why. (I've tried loading the modules that seem relevant.)

Hash tables

(MAKE-TABLE) => <table>
(MAKE-STRING-TABLE) => <string-table>
(MAKE-INTEGER-TABLE) => <integer-table>
(MAKE-SYMBOL-TABLE) => <symbol-table>

Make a new, empty table. MAKE-TABLE returns a table that uses EQ? for comparing keys and an ad-hoc hash function. The other three functions return tables that are correctly tuned for storing strings, integers, and symbols.

(MAKE-TABLE-MAKER <comparison-procedure> <hash-procedure>) => <procedure>

Returns a procedure of no arguments that makes tables that use the given comparison and hash procedures. (<comparison-procedure> <key1> <key2>) => <boolean> (<hash-procedure> <key>) => <non-negative-integer> See the definitions of functions such as make-integer-table (in big/general-table.scm) for examples of its use.

(TABLE? <x>) => <boolean>

True if <x> is a table.

(TABLE-REF <table> <key>) => <x>

Return the value for <key> in <table>, or #F if there is none. <key> should be of a type appropriate for <table>.

(TABLE-SET! <table> <key> <value>) => <undefined>

Make <value> be the value of <key> in <table>. <key> should be of a type appropriate for <table>.

(TABLE-WALK <procedure> <table>) => <undefined>

Apply <procedure>, which must accept two arguments, to every associated key and value in <table>.

Multiple values

Scheme provides some basic functions that allow a function to return multiple values: values and call-with-values (see the R5RS Report, p. 34). However, call-with-values is awkward to use. Here are some functions that are easier to use.

(MULTIPLE-SET! <list-of-identifiers> <expression>)

Evaluates <expression> and binds its return values to the identifiers in the list. <expression> should return as many values as there are identifiers in the list. Example:
    (define (baz x y) (values x y (+ x y)))
    (multiple-set! (a b c) (baz 2 3))  

(MULTIPLE-DEFINE <list-of-identifiers> <expression>)

MULTIPLE-DEFINE is to MULTIPLE-SET! as DEFINE is to SET!.

(RECEIVE <list-of-identifiers> <expression> <body> ...)

Bind <identifiers> to the values returned by <exp>, and evaluate <body> in the resulting environment. Similar to LET for regular return values. <expression> should return as many values as there are identifiers in the list.

Output

(FORMAT <port-spec> <format-string> . <arguments>) => <string> or <undefined>

Prints the arguments to the port as directed by the string. <port-spec> should be either:

An output port.
The output is written directly to the port. The result of the call to FORMAT is undefined.
#T.
The output is written to the current output port. The result of the call to FORMAT is undefined.
#F.
The output is written to a string, which is then the value returned from the call to FORMAT.

Characters in <format-string> which are not preceded by a ~ are written directly to the output. Characters preceded by a ~ have the following meaning (case is irrelevant; ~a and ~A have the same meaning):

~~
prints a single ~
~A
prints the next argument using DISPLAY
~D
prints the next argument as a decimal number
~S
prints the next argument using WRITE
~%
prints a newline character
~&
prints a NEWLINE character if the previous printed character was not one (this is implemented using FRESH-LINE)
~?
performs a recursive call to FORMAT using the next two arguments as the string and the list of arguments
Example: (format #t "The output of foo is ~s~.%" (foo 2 7 9))

(FORCE-OUTPUT <port>)

Force buffered output to actually appear right now. Example: (force-output (current-output-port)).

(P <thing>)
(P <thing> <output-port>)

Pretty-print <thing>. The current output port is used if no port is specified.
  Example:

    (p '(do ((foo 1)) (> x foo) (begin (+ foo 1) (* foo 2))))

  prints 

    (do ((foo 1))
        (> x foo)
      (begin (+ foo 1) (* foo 2)))

Records

"Record" is lisp-speak for "struct."

(DEFINE-RECORD-TYPE <tag> <type-name> (<constructor-name> <field-tag>*) <predicate-name> (<field-tag> <accessor-name> [<modifier-name>])*)

Defines a new type of record. Sets up a function (the constructor) for making objects of this type, a function (the predicate) to test whether an object is of this type, and functions to set and access the fields of the record (accessors and modifiers).

Example:

      (define-record-type pare :pare
        (kons x y)
	pare?
	(x kar set-kar!)
	(y kdr))
This defines KONS to be a constructor, KAR and KDR to be accessors, SET-KAR! to be a modifier, and PARE? to be a predicate for a new type of object. The type itself is named :PARE. PARE is a tag used in printing the new objects. The field tags X and Y are used in the inspector and to match constructor arguments with fields.

(DEFINE-RECORD-DISCLOSER <type> <print-function>)

By default, an object of record type :pare prints as #{Pare}. The print method can be modified using DEFINE-RECORD-DISCLOSER.
Example:
      (define-record-discloser :pare
        (lambda (p) `(pare ,(kar p) ,(kdr p))))

Sorting lists

(INSERT <item> <list> <comparison-function>)

<list> is presumably sorted, using <comparison-function>. Inserts <item> into <list> in correct position.

(SORT-LIST <list> <a<b-procedure>) => <list>
(SORT-LIST! <list> <a<b-procedure>) => <list>

Returns a sorted copy of <list>. The sorting algorithm is stable. (SORT-LIST '(6 5 1 3 2 4) <) => '(1 2 3 4 5 6). SORT-LIST! trashes its input. SORT-LIST leaves it input intact.

List utilities

(MEMQ? <element> <list>) => <boolean>

Returns true if <element> is in <list>, false otherwise.

(ANY? <predicate> <list>) => <boolean>

Returns true if <predicate> is true for any element of <list>.

(EVERY? <predicate> <list>) => <boolean>

Returns true if <predicate> is true for every element of <list>.

(ANY <predicate> <list>)
(FIRST <predicate> <list>)

ANY returns some element of <list> for which <predicate> is true, or #F if there are none. FIRST does the same except that it returns the first element for which is true.

(FILTER <predicate> <list>)
(FILTER! <predicate> <list>)

Returns a list containing all of the elements of <list> for which is true. The order of the elements is preserved. FILTER! may reuse the storage of <list>.

(FILTER-MAP <list>)

The same as FILTER except the returned list contains the results of applying <procedure> instead of elements of <list>. (FILTER-MAP p l) is the same as (FILTER IDENTITY (MAP p l)).

(PARTITION-LIST <predicate> <list>) => <list>
(PARTITION-LIST! <predicate> <list>) => <list> <list>

The first return value contains those elements for which <predicate> is true, the second contains the remaining elements. The order of the elements is preserved. PARTITION-LIST! may resuse the storage of the <list>.

(REMOVE-DUPLICATES <list>) => <list>

Returns its argument with all duplicate elements removed. The first instance of each element is preserved.

(DELQ <element> <list>) => <list>
(DELQ! <element> <list>) => <list>
(DELETE <predicate> <list>) => <list>

All three of these return <list> with some elements removed. DELQ removes all elements EQ? to <element>. DELQ! does the same and may reuse the storage of the list argument. DELETE removes all elements for which <predicate> is true.

(REVERSE! <list>) => <list>

Destructively reverses <list>.

(POSITION <item> <list>)
(POSV <item> <list>)
(POSQ <item> <list>)

Returns the position of <item> in <list>. POSITION identifies the element using equal?, POSV with eqv?, and POSQ with eq?.

(LAST <list>)

Returns the last element in the list.

(SUBLIST <list> <start> <end>)

Returns the subsection of the list from <start> to <end>, including the item at position <start> but not that at position <end>.

(REDUCE <operator> <identity-value> <list>)

Uses operator to combine all the elements in the list. The identity value is returned when the list is empty. For example, (reduce + 0 list) adds together all the elements in the list (a list, presumably, of numbers).

Miscellany

(ERROR <format-string> . format-args)

Triggers an error, printing the string.
  example:
      (error "this is my error message")
      (define symbol 'something)
      (error "this is error ~s" symbol)

(MAKE-RANDOM <seed>)

Random number generator. Unfortunately, there's no feature for providing it with a random seed.
Example:
        (define random (make-random <seed>))
	(random)  =>  a pseudo-random number between 0 and 2^28

(IDENTITY <any>) => <any>
(NO-OP <any>) => <any>

These both just return their argument. NO-OP is guaranteed not to be compiled in-line, IDENTITY may be.

(CONCATENATE-SYMBOL . <components>)

Returns the symbol whose name is produced by concatenating the DISPLAYed representations of <components>. (CONCATENATE-SYMBOL 'abc "-" 4) => 'abc-4

Multi-dimensional Arrays

(MAKE-ARRAY <initial-value> <bound1> ..<boundk>)

Create a k-dimensional array, in which the ith dimension goes from zero to <boundi>.

(ARRAY-SHAPE <array>)

Return the list of bounds for the array.

(ARRAY-REF <array> <index1> ...)
(ARRAY-SET! <array> <value> <index1> ...)

Set and retrieve values from an array location.

(MAKE-SHARED-ARRAY <array> <linear-map> <bound1> ...)

The <linear-map> argument to MAKE-SHARED-ARRAY is a linear function that maps indices into the shared array into a list of indices into the original array. The array returned by MAKE-SHARED-ARRAY shares storage with the original array.
Example: (array-ref (make-shared-array a f i1 i2 ... iN) j1 j2 ... jM)
         does the same thing as
         (apply array-ref a (f j1 j2 ... jM))

(COPY-ARRAY <array>)

Copy the array.

(ARRAY->VECTOR <array>)

ARRAY->VECTOR returns a vector containing the elements of an array in row-major order.

(ARRAY <bounds> . <elements>)

Create an array whose bounds are given by the list <bounds> and whose values are given by <elements>.
Example:
   (define yy (array '(2 3) 0 1 2 10 11 12))
   makes the 2 by 3 array
       0  1   2 
       10 11 12

This page is maintained by Margaret Fleck.