============================================== EXTENSIONS NOT PRESENT IN THE REVISED^3 REPORT ============================================== Scheme Version 1.2 19-March-1988 The following summarizes features included in the system which are not defined by the "Revised^3 Report on the Algorithmic Language Scheme". ================================================================================ ========================= SPECIAL FORM MANIPULATION ========================= -------------------------------------------------------------------------------- add-syntax! PRIMITIVE PROCEDURE (add-syntax! symbol function) A symbol is associated with the special form whose evaluation function is given by "function". This function will be passed the special form expression (in its entirety) and the current environment whenever the special form is encountered by the evaluator. The result of evaluating the special form is the result returned by the function. IN: symbol: symbol function: two argument function OUT: #u EXAMPLE: :=> (add-syntax! 'rqlist (lambda (exp env) (reverse (cdr exp)))) #u :=> (rqlist a b c) (c b a) -------------------------------------------------------------------------------- delete-syntax! PRIMITIVE PROCEDURE (delete-syntax! symbol) The special form associated with the given symbol is removed from the system. IN: symbol:symbol OUT: #u EXAMPLE: :=> (delete-syntax! 'define) #u :=> (define x 1) *** ERROR: unbound-variable define -------------------------------------------------------------------------------- get-syntax-definitions PRIMITIVE PROCEDURE (get-syntax-definitions) A copy of the system's special forms association list is returned. The builtin special forms' evaluation functions show up as #[enigma!] objects -- they are not actual procedures, but instead they are pointers to code. IN: --- OUT: association list: ((symbol . code) ...) ================================================================================ ======================= CONSTANTS AND VARIABLES ======================= -------------------------------------------------------------------------------- #u CONSTANT "The Unit" is the only member of the Unit domain, just as #t and #f are the two members of the Boolean domain. It is returned from functions which would otherwise have no meaningful return value, typically those functions which cause side-effects. -------------------------------------------------------------------------------- command-name VARIABLE This symbol is set during system initialization. Its value is the name of the executable file invoked to start the Scheme system. In C parlance, it is the value of argv[0]. If the program is invoked from the Workbench, command-name has the value "". EXAMPLE: From CLI: 1> Scheme x y z In Scheme: :=> command-name "Scheme" -------------------------------------------------------------------------------- command-line VARIABLE This symbol is set during system initialization. Its value is the arguments supplied on the command line when the Scheme system was started. If the program is invoked from the Workbench, command-line has the value "". EXAMPLE: From CLI: 1> Scheme x y z In Scheme: :=> command-line "x y z\ " ; note that newline character is included -------------------------------------------------------------------------------- startup-file VARIABLE This symbol is set during system initialization. Its value is the name of the startup file loaded into Scheme as the last step of system initialization. If the startup file was not found, startup-file has the value "". Currently, only one filename is attempted, "S:Scheme-init.scm". ================================================================================ ==================== HEAP SIZE MANAGEMENT ==================== -------------------------------------------------------------------------------- change-size PRIMITIVE PROCEDURE (change-size new-size) The heap memory blocks' sizes are changed to new-size bytes. IN: new-size: exact integer OUT: () if failed because request was too small #f if failed because memory not available #t if successful -------------------------------------------------------------------------------- extend-size PRIMITIVE PROCEDURE (extend-size amount-to-expand) The heap memory blocks' sizes are increased by amount-to-expand bytes. IN: amount-to-expand: exact integer OUT: () if failed because resulting size was too small #f if failed because memory not available #t if successful -------------------------------------------------------------------------------- shrink-size PRIMITIVE PROCEDURE (shrink-size amount-to-shrink) The heap memory blocks' sizes are decreased by amount-to-shrink bytes. IN: amount-to-shrink: exact integer OUT: () if failed because resulting size was too small #f if failed because memory not available #t if successful -------------------------------------------------------------------------------- minimize-size PRIMITIVE PROCEDURE (minimize-size) The heap memory blocks' sizes are decreased to a minimum size. IN: --- OUT: #f if failed because memory not available #t if successful -------------------------------------------------------------------------------- current-size PRIMITIVE PROCEDURE (current-size) The current size in bytes of each of the heap memory blocks is returned. IN: --- OUT: size: exact integer -------------------------------------------------------------------------------- collect-garbage PRIMITIVE PROCEDURE (collect-garbage) A garbage-collection is performed. IN: --- OUT: #u ================================================================================ ================== INTERRUPT-HANDLING ================== Unless otherwise noted in what follows, "interrupt" refers to an event within the Scheme system, and not a hardware event in the Amiga system, though Amiga interrupts may ultimately produce Scheme interrupts. The Scheme system responds to interrupts by generating an error at the point in the process where they are first detected. The reason passed to the error handler is the symbol INTERRUPT, and the cause is the interrupt flags value as an exact integer. Currently, two types of interrupts are recognized by the system: breaks and hard breaks. Breaks are caused by CTRL-C, CTRL-D and CTRL-E. Hard breaks are caused by CTRL-F. Amiga interrupts are handled by an exception handler associated with the Scheme task. When the handler executes, it sets a bit associated with the event in the Scheme system's interrupt flags. The interpreter will acts on these flags later. In conjunction with the interrupt flags, the system maintains an interrupt mask. This integer's bits indicate which of the interrupt flags are currently allowed to cause an interrupt. Interrupts posted to a flag whose mask bit is 0 will be ignored until the mask bit becomes 1. Breaks set interrupt bit 0. Hard breaks set interrupt bit 1. Interrupt bits 0-7 are reserved for the system, and bits 8-15 are intended for the user. There are currently only 16 interrupt bits. -------------------------------------------------------------------------------- current-interrupt-flags PRIMITIVE PROCEDURE (current-interrupt-flags) The current state of the pending interrupt flags is returned. IN: --- OUT: flags: exact integer -------------------------------------------------------------------------------- set-interrupt-flags! PRIMITIVE PROCEDURE (set-interrupt-flags! flags-mask affect-mask) The current state of the pending interrupt flags is modified. Only the flags indicated in affect-mask are affected; their values are set as indicated by flags mask. This function can be used to simulate a break. IN: flags-mask: exact positive integer affect-mask: exact positive integer OUT: #u EXAMPLE: (set-interrupt-flags! 1 1) ; simulate CTRL-C -------------------------------------------------------------------------------- current-interrupt-mask PRIMITIVE PROCEDURE (current-interrupt-mask) The current state of the interrupt mask is returned. IN: --- OUT: mask: exact integer -------------------------------------------------------------------------------- with-interrupt-mask PRIMITIVE PROCEDURE (with-interrupt-mask mask-mask affect-mask thunk) This function provides a controlled method of setting the value of the interrupt mask. The bits indicated by affect-mask in the current interrupt mask are set according to the corresponding bits in mask-mask, then the thunk's body is executed. When finished, the original mask is restored. The mask's value is "dynamically-wound". Any entry or exit (even if nonlocal through a continuation) will cause the mask to be set to the appropriate value. See dynamic-wind. IN: mask-mask: exact integer affect-mask: exact integer thunk: 0-argument procedure object OUT: return value from thunk EXAMPLE: (with-interrupt-mask #b0000000000000010 #b1111111111111111 (lambda () ) ; allow only hard breaks This function could be defined as follows, given a mythical interrupt-mask- setting function: (define (with-interrupt-mask mask affect-mask thunk) (let ((old-mask (current-interrupt-mask)) (new-mask (logical-or (logical-and affect-mask mask) (logical-and (logical-not affect-mask) (current-interrupt-mask))) )) (dynamic-wind (lambda () (SET-INTERRUPT-MASK! new-mask)) thunk (lambda () (SET-INTERRUPT-MASK! old-mask)) ))) ================================================================================ ============== ERROR HANDLING ============== The system maintains a continuation which is called each time an error occurs. Currently, the continuation is thrown a packet (a list) of three things: the reason, the cause and a continuation of the faulted process. The format of this packet may change in the future. For example, (let ((n 1) (d 0)) (if (= 0 d) (error 'bad-value d) (/ n d))) will cause the error handler continuation to be invoked with the packet (bad-value 1 ) where is a newly-made continuation of the process near the point of the error. The continuations passed into the error handler are sometimes from a point prior to the actual error. Errors occurring inside primitive procedures return to the continuation of the erroring primitive. WARNING ------- Continuations passed into the error handler whose reason is special-form-syntax-error are currently unstable. I think all the others are OK, but if you see one from a special-form-syntax-error, DON'T USE IT. These continuations will most likely cause a system crash if applied. I will be working on this problem, but for now, error handlers (and/or debuggers) should not use special-form-syntax-error continuations. -------------------------------------------------------------------------------- current-error-continuation PRIMITIVE PROCEDURE (current-error-continuation) The current error continuation is returned. IN: --- OUT: err-cont: continuation -------------------------------------------------------------------------------- error-context PRIMITIVE PROCEDURE (error-context error-handler-continuaton body-thunk) This function provides a controlled method of installing a new error continuation. The body-thunk is executed with this new handler in place. When finished, the original handler is restored. The error handler continuation is "dynamically-wound". Any entry or exit (even if nonlocal through another continuation) will cause the handler to be set appropriately. See dynamic-wind. IN: error-handler-continuation: continuation thunk: 0-argument procedure object OUT: return value from thunk EXAMPLE: :=> (define ec (call/cc (lambda (return) (display (call/cc (lambda (later) (return later)))) (newline)))) returns --> ec :=> (error-context ec (lambda () (let ((n 1) (d 0)) (if (= 0 d) (error 'bad-value d) (/ n d))))) prints --> (bad-value 0 #[closure]) returns --> ec :=> ec returns --> #u This function could be defined as follows, given a mythical error-handler- setting function: (define (error-context error-handler-continuation body-thunk) (let ((old-handler (current-error-continuation))) (dynamic-wind (lambda () (SET-ERROR-HANDLER! error-handler-continuation)) body-thunk (lambda () (SET-ERROR-HANDLER! old-handler)) ))) -------------------------------------------------------------------------------- error PRIMITIVE PROCEDURE (error reason cause) Generate an error. The current error handler will be thrown the reason and cause along with a continuation of the current process. ================================================================================ ============================== MISCELLANEOUS SYSTEM FUNCTIONS ============================== -------------------------------------------------------------------------------- abort-system PRIMITIVE PROCEDURE (abort-system) (abort-system exitval) The Scheme system is aborted. If exitval is supplied, it is the return value returned to AmigaDOS. Otherwise, 0 is returned. IN: exitval: exact integer (optional) OUT: nothing! -------------------------------------------------------------------------------- file-exists? PRIMITIVE PROCEDURE (file-exists? filename) This function returns whether or not a file could be Lock()'ed. The file is not left in a locked state, however. IN: filename: string OUT: boolean -------------------------------------------------------------------------------- sleep PRIMITIVE PROCEDURE (sleep nticks) The system sleeps for roughly nticks/50 seconds. IN: nticks: exact integer OUT: #u -------------------------------------------------------------------------------- call-system PRIMITIVE PROCEDURE (call-system command) The command is issued via an AmigaDOS Execute() call. IN: command: string OUT: boolean ================================================================================ === I/O === -------------------------------------------------------------------------------- read-raw-bytes PRIMITIVE PROCEDURE (read-raw-bytes size) (read-raw-bytes size port) An attempt is made to read the number of bytes specified by "size", and a string is returned formed by those which were read. The length of the returned string is the number of bytes actually read. If the port argument is not supplied, the current input port is used. The number of bytes read will be less than "size" if an end-of-file is encountered. If the file is at end-of-file when read-raw-bytes is called, an empty string will be returned. Interactive files sometimes return fewer bytes as the result of a newline. IN: size: exact integer port: port (optional) OUT: string -------------------------------------------------------------------------------- write-raw-bytes PRIMITIVE PROCEDURE (write-raw-bytes string) (write-raw-bytes string port) The text of the given string is written in raw format to "port", or to the current output port if no port argument is supplied. IN: string: string port: port (optional) OUT: #u ================================================================================ =================== LOW-LEVEL ACCESSORS =================== These functions allow access to the low-level representations of objects. Some are dangerous, and can cause system crashes if used improperly. These have names prefixed with "!". In the descriptions below, "rep" values are of the form (tags . value). Both tags and value are exact integers. -------------------------------------------------------------------------------- obj->rep PRIMITIVE PROCEDURE (obj->rep obj) The representation of obj is returned. IN: obj: any Scheme object OUT: (tags . value) EXAMPLE: :=> (obj->rep '()) (130 . 1) -------------------------------------------------------------------------------- !rep->obj PRIMITIVE PROCEDURE (!rep->obj rep) An object is returned, assuming that the tags and value describe a valid object. This can cause a crash if you introduce bad stuff into the system. IN: (tags . value) OUT: an object EXAMPLE: :=> (!rep->obj '(130 . 1)) () -------------------------------------------------------------------------------- !storage-ref PRIMITIVE PROCEDURE (!storage-ref obj offset) Given that the rep of obj is (tags . value), the object stored at memory location (+ value (* 4 offset)) is returned. IN: obj: any object offset: exact integer OUT: an object EXAMPLE: :=> (!storage-ref '(a b) 0) (b) :=> (!storage-ref '(a b) 1) a -------------------------------------------------------------------------------- !storage-set! PRIMITIVE PROCEDURE (!storage-set! obj offset obj-to-store) Given that the rep of obj is (tags . value), obj-to-store is stored at memory location (+ value (* 4 offset)). IN: obj: any object offset: exact integer obj-to-store: any object OUT: #u EXAMPLE: :=> (define obj '(a b)) obj :=> (!storage-set! obj 0 'c) #u :=> obj (a . c) -------------------------------------------------------------------------------- !storage-rep-ref PRIMITIVE PROCEDURE (!storage-rep-ref obj offset) Given that the rep of obj is (tags . value), the rep of the object stored at memory location (+ value (* 4 offset)) is returned. This function is slightly safer than !storage-ref!...you will not pollute the system with non-objects. IN: obj: any object offset: exact integer OUT: (tags . value) for referenced object EXAMPLE: :=> (!storage-rep-ref '(() . b) 1) (130 . 1) -------------------------------------------------------------------------------- !storage-rep-set! PRIMITIVE PROCEDURE (!storage-rep-set! obj offset rep-to-store) Given that the rep of obj is (tags . value), obj-to-store is stored at memory location (+ value (* 4 offset)). IN: obj: any object offset: exact integer rep-to-store: (tags . value) OUT: #u EXAMPLE: :=> (define obj '(a b)) obj :=> (!storage-rep-set! obj 0 '(130 . 1)) #u :=> obj (a) -------------------------------------------------------------------------------- !byte-ref PRIMITIVE PROCEDURE (!byte-ref obj offset) Given that the rep of obj is (tags . value), the byte stored at memory location (+ value offset) is returned. IN: obj: any object offset: exact integer OUT: byte: exact integer EXAMPLE: :=> (!byte-ref '(a . ()) 0) 130 -------------------------------------------------------------------------------- !byte-set! PRIMITIVE PROCEDURE (!byte-set! obj offset byte) Given that the rep of obj is (tags . value), byte is stored at memory location (+ value offset). IN: obj: any object offset: exact integer byte: any object OUT: #u EXAMPLE: :=> (define obj (a . 0)) obj :=> (!byte-set! obj 3 7) #u :=> obj (a . 7) ================================================================================ =========================== PROCEDURE OBJECT TYPE TESTS =========================== The following tests further subdivide the class of objects for which procedure? returns #t. -------------------------------------------------------------------------------- primitive? PRIMITIVE PROCEDURE (primitive? obj) IN: obj: any object OUT: #t if obj is a primitive procedure #f otherwise -------------------------------------------------------------------------------- compound-procedure? PRIMITIVE PROCEDURE (compound-procedure? obj) IN: obj: any object OUT: #t if obj is a compound procedure (produced by lambda) #f otherwise -------------------------------------------------------------------------------- compiled? PRIMITIVE PROCEDURE (compiled? obj) Currently, no system functions produce compiled procedure objects. IN: obj: any object OUT: #t if obj is a compiled procedure #f otherwise -------------------------------------------------------------------------------- thunk? PRIMITIVE PROCEDURE (thunk? obj) Currently, no external system functions produce thunk objects. The system's thunk type is not merely a procedure of 0 arguments, but a special 0-argument procedure type used internally. IN: obj: any object OUT: #t if obj is a procedure #f otherwise -------------------------------------------------------------------------------- promise? PRIMITIVE PROCEDURE (promise? obj) IN: obj: any object OUT: #t if obj is a promise (0-argument procedure returned by delay) #f otherwise -------------------------------------------------------------------------------- continuation? PRIMITIVE PROCEDURE (continuation? obj) IN: obj: any object OUT: #t if obj is a continuation #f otherwise ================================================================================ ============= MISCELLANEOUS ============= -------------------------------------------------------------------------------- eval PRIMITIVE PROCEDURE (eval exp env) The expression is evaluated in the given environment, and the result returned. IN: exp: a Scheme expression env: an environment object OUT: the result of evaluating exp in env EXAMPLE: :=> (eval '(+ 2 3) (the-environment)) 5 -------------------------------------------------------------------------------- dynamic-wind PRIMITIVE PROCEDURE (dynamic-wind entry-thunk body-thunk exit-thunk) This function provides a controlled method of ensuring the dynamic state of a process. The entry-thunk's code is executed, then the body-thunk's code and finally the exit-thunk's code. The result is that which was returned by body-thunk. Any exit, local or nonlocal, causes the exit-thunk to be applied. Any entry, local or nonlocal, causes the entry-thunk to be applied. The entry and exit thunks are applied with the interrupt mask set to accept hard breaks only. It will probably cause problems if an entry or exit thunk is interrupted. IN: entry-thunk: 0-argument procedure object body-thunk: 0-argument procedure object exit-thunk: 0-argument procedure object OUT: return value from body-thunk EXAMPLE: :=> (define dwind-test (dynamic-wind (lambda () (display "ENTRY") (newline)) (lambda () (call/cc (lambda (cont) cont))) (lambda () (display "EXIT") (newline)))) prints --> ENTRY prints --> EXIT returns --> dwind-test :=> (define wound-cont dwind-test) ; 'cause dwind-test gets clobbered wound-cont :=> (wound-cont 'hello) prints --> ENTRY prints --> EXIT returns --> dwind-test :=> dwind-test returns --> hello :=> (wound-cont 'aloha) prints --> ENTRY prints --> EXIT returns --> dwind-test :=> dwind-test returns --> aloha -------------------------------------------------------------------------------- char->string PRIMITIVE PROCEDURE (char->string char) A string representing the given character is returned. The string is such that the reader operating on it would return the given character. IN: char: character OUT: string: a string formed by prepending #\ to a character specifier: (char->integer char) character specifier -------------------- ------------------- #x00 nul #x01 soh #x02 stx #x03 etx #x04 eot #x05 enq #x06 ack #x07 bel #x08 bs #x09 ht #x0A lf #x0B vt #x0C ff #x0D cr #x0E so #x0F si #x10 dle #x11 dc1 #x12 dc2 #x13 dc3 #x14 dc4 #x15 nak #x16 syn #x17 etb #x18 can #x19 em #x1A sub #x1B esc #x1C fs #x1D gs #x1E rs #x1F us #x20 space #x21 through #x7E the character #x7F rub #x80 through #xFF the character EXAMPLE: :=> (char->string #\space) "#\\space" ; \ is escaped -------------------------------------------------------------------------------- string->char PRIMITIVE PROCEDURE (string->char string) A string representation of a character (such as char->string would return) is converted to its corresponding character. Character case is ignored. In addition, the following strings are recognized: "#\\null" --> #\nul "#\\bell" --> #\bel "#\\tab" --> #\ht "#\\newline" --> #\lf Unrecognized strings cause #u to be returned. IN: string: string OUT: char: character if successful #u if unsuccessful -------------------------------------------------------------------------------- call-with-quotient&remainder PRIMITIVE PROCEDURE (call-with-quotient&remainder number1 number2 proc) This function lets you get both the quotient and the remainder with one call. IN: number1: number number2: number proc: 2-argument procedure OUT: return value from proc EXAMPLE: :=> (call-with-quotient&remainder 229 11 (lambda (q r) (display (cons q r)))) (20 . 9)#u -------------------------------------------------------------------------------- fluid-let SPECIAL FORM (fluid-let (binding1 ...) exp1 ...) (fluid-let () exp1 ...) This special form is just like the "let" special form, except that the bindings are dynamic instead of static. It is unlike MIT Scheme's fluid-let in that the bindings are in a separate environment, and must be accessed with the special form "fluid". EXAMPLE: :=> (define (p x) (cons x (fluid x))) p :=> (fluid-let ((x 'fluid-var)) (p 'lexical-var)) (lexical-var . fluid-var) -------------------------------------------------------------------------------- fluid SPECIAL FORM (fluid symbol) This special form provides access to variables in the fluid environment. ================================================================================ ======= STREAMS ======= -------------------------------------------------------------------------------- the-empty-stream VARIABLE This is a distinguished object representing the empty stream. (stream? the-empty-stream) returns #t. -------------------------------------------------------------------------------- stream? PRIMITIVE PROCEDURE (stream? obj) IN: obj: any object OUT: #t if obj is a stream object #f otherwise -------------------------------------------------------------------------------- empty-stream? PRIMITIVE PROCEDURE (empty-stream? obj) IN: obj: any object OUT: #t if obj is the-empty-stream #f otherwise -------------------------------------------------------------------------------- cons-stream SPECIAL FORM (cons-stream obj1 obj2) A stream object is returned whose "head" is obj1 and "tail" is obj2. Obj1 is evaluated prior to building the stream object, obj2 is not evaluated until a "tail" is performed on the stream object. Even so, obj2 will be evaluated but once; it is memoized. IN: obj1: any object obj2: any object OUT: stream object -------------------------------------------------------------------------------- head PRIMITIVE PROCEDURE (head stream) IN: stream: stream OUT: an object EXAMPLE: :=> (define s (cons-stream (begin (display "HEAD") (newline)) (begin (display "TAIL") (newline)))) prints --> "HEAD" returns --> s :=> (head s) returns --> #u -------------------------------------------------------------------------------- tail PRIMITIVE PROCEDURE (tail stream) IN: stream: stream OUT: an object EXAMPLE: :=> (define s (cons-stream (begin (display "HEAD") (newline)) (begin (display "TAIL") (newline)))) prints --> "HEAD" returns --> s :=> (tail s) prints --> "TAIL" returns --> #u :=> (tail s) returns --> #u ; note memoization ================================================================================ ============ ENVIRONMENTS ============ -------------------------------------------------------------------------------- the-environment SPECIAL FORM (the-environment) This special form returns the current environment from the point where it is evaluated. EXAMPLE: :=> (let ((a 'first)) (let ((env (the-environment))) (let ((a 'second)) (cons a (eval 'a env))))) (second . first) -------------------------------------------------------------------------------- environment? PRIMITIVE PROCEDURE (environment? obj) IN: obj: any object OUT: #t if obj is an environment object #f otherwise -------------------------------------------------------------------------------- make-environment SPECIAL FORM (make-environment exp1 ...) The given expressions are evaluated in order in a separate environment enclosed by the current environment, and the resulting environment is returned. (make-environment exp1 ...) is equivalent to (let () exp1 ... (the-environment)) IN: exps: Scheme expressions OUT: resulting environment object -------------------------------------------------------------------------------- access SPECIAL FORM (access symbol1 env) (access symbol1 symbol2 ... env) Symbol1 is looked up in the environment bound to symbol2 which is looked up in the enviroment bound to ... which is looked up in the enviroment bound to env. At least one symbol must be specified as in (access 'a (the-environment)). IN: symbols: symbol env: environment object OUT: the value bound to symbol1 EXAMPLE: :=> (define package (make-environment (define a 'one) (define inner-package (make-environment (define a 'two) (define inner-inner-package (make-environment (define a 'three) )) )) )) package :=> (vector (access a package) (access a inner-package package) (access a inner-inner-package inner-package package)) #(one two three)