diff options
Diffstat (limited to 'slib.info-4')
-rw-r--r-- | slib.info-4 | 1248 |
1 files changed, 1248 insertions, 0 deletions
diff --git a/slib.info-4 b/slib.info-4 new file mode 100644 index 0000000..3d3da19 --- /dev/null +++ b/slib.info-4 @@ -0,0 +1,1248 @@ +This is Info file slib.info, produced by Makeinfo-1.64 from the input +file slib.texi. + + This file documents SLIB, the portable Scheme library. + + Copyright (C) 1993 Todd R. Eigenschink Copyright (C) 1993, 1994, 1995 +Aubrey Jaffer + + Permission is granted to make and distribute verbatim copies of this +manual provided the copyright notice and this permission notice are +preserved on all copies. + + Permission is granted to copy and distribute modified versions of this +manual under the conditions for verbatim copying, provided that the +entire resulting derived work is distributed under the terms of a +permission notice identical to this one. + + Permission is granted to copy and distribute translations of this +manual into another language, under the above conditions for modified +versions, except that this permission notice may be stated in a +translation approved by the author. + + +File: slib.info, Node: Syntactic Closures, Next: Syntax-Case Macros, Prev: Macros That Work, Up: Macros + +Syntactic Closures +================== + + `(require 'syntactic-closures)' + + - Function: macro:expand EXPRESSION + - Function: synclo:expand EXPRESSION + Returns scheme code with the macros and derived expression types of + EXPRESSION expanded to primitive expression types. + + - Function: macro:eval EXPRESSION + - Function: synclo:eval EXPRESSION + `macro:eval' returns the value of EXPRESSION in the current top + level environment. EXPRESSION can contain macro definitions. + Side effects of EXPRESSION will affect the top level environment. + + - Procedure: macro:load FILENAME + - Procedure: synclo:load FILENAME + FILENAME should be a string. If filename names an existing file, + the `macro:load' procedure reads Scheme source code expressions and + definitions from the file and evaluates them sequentially. These + source code expressions and definitions may contain macro + definitions. The `macro:load' procedure does not affect the + values returned by `current-input-port' and `current-output-port'. + +Syntactic Closure Macro Facility +-------------------------------- + + A Syntactic Closures Macro Facility + + by Chris Hanson + + 9 November 1991 + + This document describes "syntactic closures", a low-level macro +facility for the Scheme programming language. The facility is an +alternative to the low-level macro facility described in the `Revised^4 +Report on Scheme.' This document is an addendum to that report. + + The syntactic closures facility extends the BNF rule for TRANSFORMER +SPEC to allow a new keyword that introduces a low-level macro +transformer: + TRANSFORMER SPEC := (transformer EXPRESSION) + + Additionally, the following procedures are added: + make-syntactic-closure + capture-syntactic-environment + identifier? + identifier=? + + The description of the facility is divided into three parts. The +first part defines basic terminology. The second part describes how +macro transformers are defined. The third part describes the use of +"identifiers", which extend the syntactic closure mechanism to be +compatible with `syntax-rules'. + +Terminology +........... + + This section defines the concepts and data types used by the syntactic +closures facility. + + "Forms" are the syntactic entities out of which programs are + recursively constructed. A form is any expression, any + definition, any syntactic keyword, or any syntactic closure. The + variable name that appears in a `set!' special form is also a + form. Examples of forms: + 17 + #t + car + (+ x 4) + (lambda (x) x) + (define pi 3.14159) + if + define + + An "alias" is an alternate name for a given symbol. It can appear + anywhere in a form that the symbol could be used, and when quoted + it is replaced by the symbol; however, it does not satisfy the + predicate `symbol?'. Macro transformers rarely distinguish + symbols from aliases, referring to both as identifiers. + + A "syntactic" environment maps identifiers to their meanings. + More precisely, it determines whether an identifier is a syntactic + keyword or a variable. If it is a keyword, the meaning is an + interpretation for the form in which that keyword appears. If it + is a variable, the meaning identifies which binding of that + variable is referenced. In short, syntactic environments contain + all of the contextual information necessary for interpreting the + meaning of a particular form. + + A "syntactic closure" consists of a form, a syntactic environment, + and a list of identifiers. All identifiers in the form take their + meaning from the syntactic environment, except those in the given + list. The identifiers in the list are to have their meanings + determined later. A syntactic closure may be used in any context + in which its form could have been used. Since a syntactic closure + is also a form, it may not be used in contexts where a form would + be illegal. For example, a form may not appear as a clause in the + cond special form. A syntactic closure appearing in a quoted + structure is replaced by its form. + +Transformer Definition +...................... + + This section describes the `transformer' special form and the +procedures `make-syntactic-closure' and `capture-syntactic-environment'. + + - Syntax: transformer EXPRESSION + Syntax: It is an error if this syntax occurs except as a + TRANSFORMER SPEC. + + Semantics: The EXPRESSION is evaluated in the standard transformer + environment to yield a macro transformer as described below. This + macro transformer is bound to a macro keyword by the special form + in which the `transformer' expression appears (for example, + `let-syntax'). + + A "macro transformer" is a procedure that takes two arguments, a + form and a syntactic environment, and returns a new form. The + first argument, the "input form", is the form in which the macro + keyword occurred. The second argument, the "usage environment", + is the syntactic environment in which the input form occurred. + The result of the transformer, the "output form", is automatically + closed in the "transformer environment", which is the syntactic + environment in which the `transformer' expression occurred. + + For example, here is a definition of a push macro using + `syntax-rules': + (define-syntax push + (syntax-rules () + ((push item list) + (set! list (cons item list))))) + + Here is an equivalent definition using `transformer': + (define-syntax push + (transformer + (lambda (exp env) + (let ((item + (make-syntactic-closure env '() (cadr exp))) + (list + (make-syntactic-closure env '() (caddr exp)))) + `(set! ,list (cons ,item ,list)))))) + + In this example, the identifiers `set!' and `cons' are closed in + the transformer environment, and thus will not be affected by the + meanings of those identifiers in the usage environment `env'. + + Some macros may be non-hygienic by design. For example, the + following defines a loop macro that implicitly binds `exit' to an + escape procedure. The binding of `exit' is intended to capture + free references to `exit' in the body of the loop, so `exit' must + be left free when the body is closed: + (define-syntax loop + (transformer + (lambda (exp env) + (let ((body (cdr exp))) + `(call-with-current-continuation + (lambda (exit) + (let f () + ,@(map (lambda (exp) + (make-syntactic-closure env '(exit) + exp)) + body) + (f)))))))) + + To assign meanings to the identifiers in a form, use + `make-syntactic-closure' to close the form in a syntactic + environment. + + - Function: make-syntactic-closure ENVIRONMENT FREE-NAMES FORM + ENVIRONMENT must be a syntactic environment, FREE-NAMES must be a + list of identifiers, and FORM must be a form. + `make-syntactic-closure' constructs and returns a syntactic closure + of FORM in ENVIRONMENT, which can be used anywhere that FORM could + have been used. All the identifiers used in FORM, except those + explicitly excepted by FREE-NAMES, obtain their meanings from + ENVIRONMENT. + + Here is an example where FREE-NAMES is something other than the + empty list. It is instructive to compare the use of FREE-NAMES in + this example with its use in the `loop' example above: the examples + are similar except for the source of the identifier being left + free. + (define-syntax let1 + (transformer + (lambda (exp env) + (let ((id (cadr exp)) + (init (caddr exp)) + (exp (cadddr exp))) + `((lambda (,id) + ,(make-syntactic-closure env (list id) exp)) + ,(make-syntactic-closure env '() init)))))) + + `let1' is a simplified version of `let' that only binds a single + identifier, and whose body consists of a single expression. When + the body expression is syntactically closed in its original + syntactic environment, the identifier that is to be bound by + `let1' must be left free, so that it can be properly captured by + the `lambda' in the output form. + + To obtain a syntactic environment other than the usage + environment, use `capture-syntactic-environment'. + + - Function: capture-syntactic-environment PROCEDURE + `capture-syntactic-environment' returns a form that will, when + transformed, call PROCEDURE on the current syntactic environment. + PROCEDURE should compute and return a new form to be transformed, + in that same syntactic environment, in place of the form. + + An example will make this clear. Suppose we wanted to define a + simple `loop-until' keyword equivalent to + (define-syntax loop-until + (syntax-rules () + ((loop-until id init test return step) + (letrec ((loop + (lambda (id) + (if test return (loop step))))) + (loop init))))) + + The following attempt at defining `loop-until' has a subtle bug: + (define-syntax loop-until + (transformer + (lambda (exp env) + (let ((id (cadr exp)) + (init (caddr exp)) + (test (cadddr exp)) + (return (cadddr (cdr exp))) + (step (cadddr (cddr exp))) + (close + (lambda (exp free) + (make-syntactic-closure env free exp)))) + `(letrec ((loop + (lambda (,id) + (if ,(close test (list id)) + ,(close return (list id)) + (loop ,(close step (list id))))))) + (loop ,(close init '()))))))) + + This definition appears to take all of the proper precautions to + prevent unintended captures. It carefully closes the + subexpressions in their original syntactic environment and it + leaves the `id' identifier free in the `test', `return', and + `step' expressions, so that it will be captured by the binding + introduced by the `lambda' expression. Unfortunately it uses the + identifiers `if' and `loop' within that `lambda' expression, so if + the user of `loop-until' just happens to use, say, `if' for the + identifier, it will be inadvertently captured. + + The syntactic environment that `if' and `loop' want to be exposed + to is the one just outside the `lambda' expression: before the + user's identifier is added to the syntactic environment, but after + the identifier loop has been added. + `capture-syntactic-environment' captures exactly that environment + as follows: + (define-syntax loop-until + (transformer + (lambda (exp env) + (let ((id (cadr exp)) + (init (caddr exp)) + (test (cadddr exp)) + (return (cadddr (cdr exp))) + (step (cadddr (cddr exp))) + (close + (lambda (exp free) + (make-syntactic-closure env free exp)))) + `(letrec ((loop + ,(capture-syntactic-environment + (lambda (env) + `(lambda (,id) + (,(make-syntactic-closure env '() `if) + ,(close test (list id)) + ,(close return (list id)) + (,(make-syntactic-closure env '() + `loop) + ,(close step (list id))))))))) + (loop ,(close init '()))))))) + + In this case, having captured the desired syntactic environment, + it is convenient to construct syntactic closures of the + identifiers `if' and the `loop' and use them in the body of the + `lambda'. + + A common use of `capture-syntactic-environment' is to get the + transformer environment of a macro transformer: + (transformer + (lambda (exp env) + (capture-syntactic-environment + (lambda (transformer-env) + ...)))) + +Identifiers +........... + + This section describes the procedures that create and manipulate +identifiers. Previous syntactic closure proposals did not have an +identifier data type - they just used symbols. The identifier data +type extends the syntactic closures facility to be compatible with the +high-level `syntax-rules' facility. + + As discussed earlier, an identifier is either a symbol or an "alias". +An alias is implemented as a syntactic closure whose "form" is an +identifier: + (make-syntactic-closure env '() 'a) + => an "alias" + + Aliases are implemented as syntactic closures because they behave just +like syntactic closures most of the time. The difference is that an +alias may be bound to a new value (for example by `lambda' or +`let-syntax'); other syntactic closures may not be used this way. If +an alias is bound, then within the scope of that binding it is looked +up in the syntactic environment just like any other identifier. + + Aliases are used in the implementation of the high-level facility +`syntax-rules'. A macro transformer created by `syntax-rules' uses a +template to generate its output form, substituting subforms of the +input form into the template. In a syntactic closures implementation, +all of the symbols in the template are replaced by aliases closed in +the transformer environment, while the output form itself is closed in +the usage environment. This guarantees that the macro transformation +is hygienic, without requiring the transformer to know the syntactic +roles of the substituted input subforms. + + - Function: identifier? OBJECT + Returns `#t' if OBJECT is an identifier, otherwise returns `#f'. + Examples: + (identifier? 'a) + => #t + (identifier? (make-syntactic-closure env '() 'a)) + => #t + (identifier? "a") + => #f + (identifier? #\a) + => #f + (identifier? 97) + => #f + (identifier? #f) + => #f + (identifier? '(a)) + => #f + (identifier? '#(a)) + => #f + + The predicate `eq?' is used to determine if two identifers are + "the same". Thus `eq?' can be used to compare identifiers exactly + as it would be used to compare symbols. Often, though, it is + useful to know whether two identifiers "mean the same thing". For + example, the `cond' macro uses the symbol `else' to identify the + final clause in the conditional. A macro transformer for `cond' + cannot just look for the symbol `else', because the `cond' form + might be the output of another macro transformer that replaced the + symbol `else' with an alias. Instead the transformer must look + for an identifier that "means the same thing" in the usage + environment as the symbol `else' means in the transformer + environment. + + - Function: identifier=? ENVIRONMENT1 IDENTIFIER1 ENVIRONMENT2 + IDENTIFIER2 + ENVIRONMENT1 and ENVIRONMENT2 must be syntactic environments, and + IDENTIFIER1 and IDENTIFIER2 must be identifiers. `identifier=?' + returns `#t' if the meaning of IDENTIFIER1 in ENVIRONMENT1 is the + same as that of IDENTIFIER2 in ENVIRONMENT2, otherwise it returns + `#f'. Examples: + + (let-syntax + ((foo + (transformer + (lambda (form env) + (capture-syntactic-environment + (lambda (transformer-env) + (identifier=? transformer-env 'x env 'x))))))) + (list (foo) + (let ((x 3)) + (foo)))) + => (#t #f) + + (let-syntax ((bar foo)) + (let-syntax + ((foo + (transformer + (lambda (form env) + (capture-syntactic-environment + (lambda (transformer-env) + (identifier=? transformer-env 'foo + env (cadr form)))))))) + (list (foo foo) + (foobar)))) + => (#f #t) + +Acknowledgements +................ + + The syntactic closures facility was invented by Alan Bawden and +Jonathan Rees. The use of aliases to implement `syntax-rules' was +invented by Alan Bawden (who prefers to call them "synthetic names"). +Much of this proposal is derived from an earlier proposal by Alan +Bawden. + + +File: slib.info, Node: Syntax-Case Macros, Next: Fluid-Let, Prev: Syntactic Closures, Up: Macros + +Syntax-Case Macros +================== + + `(require 'syntax-case)' + + - Function: macro:expand EXPRESSION + - Function: syncase:expand EXPRESSION + Returns scheme code with the macros and derived expression types of + EXPRESSION expanded to primitive expression types. + + - Function: macro:eval EXPRESSION + - Function: syncase:eval EXPRESSION + `macro:eval' returns the value of EXPRESSION in the current top + level environment. EXPRESSION can contain macro definitions. + Side effects of EXPRESSION will affect the top level environment. + + - Procedure: macro:load FILENAME + - Procedure: syncase:load FILENAME + FILENAME should be a string. If filename names an existing file, + the `macro:load' procedure reads Scheme source code expressions and + definitions from the file and evaluates them sequentially. These + source code expressions and definitions may contain macro + definitions. The `macro:load' procedure does not affect the + values returned by `current-input-port' and `current-output-port'. + + This is version 2.1 of `syntax-case', the low-level macro facility +proposed and implemented by Robert Hieb and R. Kent Dybvig. + + This version is further adapted by Harald Hanche-Olsen +<hanche@imf.unit.no> to make it compatible with, and easily usable +with, SLIB. Mainly, these adaptations consisted of: + + * Removing white space from `expand.pp' to save space in the + distribution. This file is not meant for human readers anyway... + + * Removed a couple of Chez scheme dependencies. + + * Renamed global variables used to minimize the possibility of name + conflicts. + + * Adding an SLIB-specific initialization file. + + * Removing a couple extra files, most notably the documentation (but + see below). + + If you wish, you can see exactly what changes were done by reading the +shell script in the file `syncase.sh'. + + The two PostScript files were omitted in order to not burden the SLIB +distribution with them. If you do intend to use `syntax-case', +however, you should get these files and print them out on a PostScript +printer. They are available with the original `syntax-case' +distribution by anonymous FTP in +`cs.indiana.edu:/pub/scheme/syntax-case'. + + In order to use syntax-case from an interactive top level, execute: + (require 'syntax-case) + (require 'repl) + (repl:top-level macro:eval) + See the section Repl (*Note Repl::) for more information. + + To check operation of syntax-case get +`cs.indiana.edu:/pub/scheme/syntax-case', and type + (require 'syntax-case) + (syncase:sanity-check) + + Beware that `syntax-case' takes a long time to load - about 20s on a +SPARCstation SLC (with SCM) and about 90s on a Macintosh SE/30 (with +Gambit). + +Notes +----- + + All R4RS syntactic forms are defined, including `delay'. Along with +`delay' are simple definitions for `make-promise' (into which `delay' +expressions expand) and `force'. + + `syntax-rules' and `with-syntax' (described in `TR356') are defined. + + `syntax-case' is actually defined as a macro that expands into calls +to the procedure `syntax-dispatch' and the core form `syntax-lambda'; +do not redefine these names. + + Several other top-level bindings not documented in TR356 are created: + the "hooks" in `hooks.ss' + + the `build-' procedures in `output.ss' + + `expand-syntax' (the expander) + + The syntax of define has been extended to allow `(define ID)', which +assigns ID to some unspecified value. + + We have attempted to maintain R4RS compatibility where possible. The +incompatibilities should be confined to `hooks.ss'. Please let us know +if there is some incompatibility that is not flagged as such. + + Send bug reports, comments, suggestions, and questions to Kent Dybvig +(dyb@iuvax.cs.indiana.edu). + +Note from maintainer +-------------------- + + Included with the `syntax-case' files was `structure.scm' which +defines a macro `define-structure'. There is no documentation for this +macro and it is not used by any code in SLIB. + + +File: slib.info, Node: Fluid-Let, Next: Yasos, Prev: Syntax-Case Macros, Up: Macros + +Fluid-Let +========= + + `(require 'fluid-let)' + + - Syntax: fluid-let `(BINDINGS ...)' FORMS... + + (fluid-let ((VARIABLE INIT) ...) + EXPRESSION EXPRESSION ...) + + The INITs are evaluated in the current environment (in some +unspecified order), the current values of the VARIABLEs are saved, the +results are assigned to the VARIABLEs, the EXPRESSIONs are evaluated +sequentially in the current environment, the VARIABLEs are restored to +their original values, and the value of the last EXPRESSION is returned. + + The syntax of this special form is similar to that of `let', but +`fluid-let' temporarily rebinds existing VARIABLEs. Unlike `let', +`fluid-let' creates no new bindings; instead it *assigns* the values of +each INIT to the binding (determined by the rules of lexical scoping) +of its corresponding VARIABLE. + + +File: slib.info, Node: Yasos, Prev: Fluid-Let, Up: Macros + +Yasos +===== + + `(require 'oop)' or `(require 'yasos)' + + `Yet Another Scheme Object System' is a simple object system for +Scheme based on the paper by Norman Adams and Jonathan Rees: `Object +Oriented Programming in Scheme', Proceedings of the 1988 ACM Conference +on LISP and Functional Programming, July 1988 [ACM #552880]. + + Another reference is: + + Ken Dickey. Scheming with Objects `AI Expert' Volume 7, Number 10 +(October 1992), pp. 24-33. + +* Menu: + +* Yasos terms:: Definitions and disclaimer. +* Yasos interface:: The Yasos macros and procedures. +* Setters:: Dylan-like setters in Yasos. +* Yasos examples:: Usage of Yasos and setters. + + +File: slib.info, Node: Yasos terms, Next: Yasos interface, Prev: Yasos, Up: Yasos + +Terms +----- + +"Object" + Any Scheme data object. + +"Instance" + An instance of the OO system; an "object". + +"Operation" + A METHOD. + +*Notes:* + The object system supports multiple inheritance. An instance can + inherit from 0 or more ancestors. In the case of multiple + inherited operations with the same identity, the operation used is + that from the first ancestor which contains it (in the ancestor + `let'). An operation may be applied to any Scheme data + object--not just instances. As code which creates instances is + just code, there are no "classes" and no meta-ANYTHING. Method + dispatch is by a procedure call a la CLOS rather than by `send' + syntax a la Smalltalk. + +*Disclaimer:* + There are a number of optimizations which can be made. This + implementation is expository (although performance should be quite + reasonable). See the L&FP paper for some suggestions. + + +File: slib.info, Node: Yasos interface, Next: Setters, Prev: Yasos terms, Up: Yasos + +Interface +--------- + + - Syntax: define-operation `('OPNAME SELF ARG ...`)' DEFAULT-BODY + Defines a default behavior for data objects which don't handle the + operation OPNAME. The default default behavior (for an empty + DEFAULT-BODY) is to generate an error. + + - Syntax: define-predicate OPNAME? + Defines a predicate OPNAME?, usually used for determining the + "type" of an object, such that `(OPNAME? OBJECT)' returns `#t' if + OBJECT has an operation OPNAME? and `#f' otherwise. + + - Syntax: object `((NAME SELF ARG ...) BODY)' ... + Returns an object (an instance of the object system) with + operations. Invoking `(NAME OBJECT ARG ...' executes the BODY of + the OBJECT with SELF bound to OBJECT and with argument(s) ARG.... + + - Syntax: object-with-ancestors `(('ANCESTOR1 INIT1`)' ...`)' + OPERATION ... + A `let'-like form of `object' for multiple inheritance. It + returns an object inheriting the behaviour of ANCESTOR1 etc. An + operation will be invoked in an ancestor if the object itself does + not provide such a method. In the case of multiple inherited + operations with the same identity, the operation used is the one + found in the first ancestor in the ancestor list. + + - Syntax: operate-as COMPONENT OPERATION SELF ARG ... + Used in an operation definition (of SELF) to invoke the OPERATION + in an ancestor COMPONENT but maintain the object's identity. Also + known as "send-to-super". + + - Procedure: print OBJ PORT + A default `print' operation is provided which is just `(format + PORT OBJ)' (*Note Format::) for non-instances and prints OBJ + preceded by `#<INSTANCE>' for instances. + + - Function: size OBJ + The default method returns the number of elements in OBJ if it is + a vector, string or list, `2' for a pair, `1' for a character and + by default id an error otherwise. Objects such as collections + (*Note Collections::) may override the default in an obvious way. + + +File: slib.info, Node: Setters, Next: Yasos examples, Prev: Yasos interface, Up: Yasos + +Setters +------- + + "Setters" implement "generalized locations" for objects associated +with some sort of mutable state. A "getter" operation retrieves a +value from a generalized location and the corresponding setter +operation stores a value into the location. Only the getter is named - +the setter is specified by a procedure call as below. (Dylan uses +special syntax.) Typically, but not necessarily, getters are access +operations to extract values from Yasos objects (*Note Yasos::). +Several setters are predefined, corresponding to getters `car', `cdr', +`string-ref' and `vector-ref' e.g., `(setter car)' is equivalent to +`set-car!'. + + This implementation of setters is similar to that in Dylan(TM) +(`Dylan: An object-oriented dynamic language', Apple Computer Eastern +Research and Technology). Common LISP provides similar facilities +through `setf'. + + - Function: setter GETTER + Returns the setter for the procedure GETTER. E.g., since + `string-ref' is the getter corresponding to a setter which is + actually `string-set!': + (define foo "foo") + ((setter string-ref) foo 0 #\F) ; set element 0 of foo + foo => "Foo" + + - Syntax: set PLACE NEW-VALUE + If PLACE is a variable name, `set' is equivalent to `set!'. + Otherwise, PLACE must have the form of a procedure call, where the + procedure name refers to a getter and the call indicates an + accessible generalized location, i.e., the call would return a + value. The return value of `set' is usually unspecified unless + used with a setter whose definition guarantees to return a useful + value. + (set (string-ref foo 2) #\O) ; generalized location with getter + foo => "FoO" + (set foo "foo") ; like set! + foo => "foo" + + - Procedure: add-setter GETTER SETTER + Add procedures GETTER and SETTER to the (inaccessible) list of + valid setter/getter pairs. SETTER implements the store operation + corresponding to the GETTER access operation for the relevant + state. The return value is unspecified. + + - Procedure: remove-setter-for GETTER + Removes the setter corresponding to the specified GETTER from the + list of valid setters. The return value is unspecified. + + - Syntax: define-access-operation GETTER-NAME + Shorthand for a Yasos `define-operation' defining an operation + GETTER-NAME that objects may support to return the value of some + mutable state. The default operation is to signal an error. The + return value is unspecified. + + +File: slib.info, Node: Yasos examples, Prev: Setters, Up: Yasos + +Examples +-------- + + (define-operation (print obj port) + (format port + (if (instance? obj) "#<instance>" "~s") + obj)) + + (define-operation (SIZE obj) + (cond + ((vector? obj) (vector-length obj)) + ((list? obj) (length obj)) + ((pair? obj) 2) + ((string? obj) (string-length obj)) + ((char? obj) 1) + (else + (error "Operation not supported: size" obj)))) + + (define-predicate cell?) + (define-operation (fetch obj)) + (define-operation (store! obj newValue)) + + (define (make-cell value) + (object + ((cell? self) #t) + ((fetch self) value) + ((store! self newValue) + (set! value newValue) + newValue) + ((size self) 1) + ((print self port) + (format port "#<Cell: ~s>" (fetch self))))) + + (define-operation (discard obj value) + (format #t "Discarding ~s~%" value)) + + (define (make-filtered-cell value filter) + (object-with-ancestors ((cell (make-cell value))) + ((store! self newValue) + (if (filter newValue) + (store! cell newValue) + (discard self newValue))))) + + (define-predicate array?) + (define-operation (array-ref array index)) + (define-operation (array-set! array index value)) + + (define (make-array num-slots) + (let ((anArray (make-vector num-slots))) + (object + ((array? self) #t) + ((size self) num-slots) + ((array-ref self index) (vector-ref anArray index)) + ((array-set! self index newValue) (vector-set! anArray index newValue)) + ((print self port) (format port "#<Array ~s>" (size self)))))) + + (define-operation (position obj)) + (define-operation (discarded-value obj)) + + (define (make-cell-with-history value filter size) + (let ((pos 0) (most-recent-discard #f)) + (object-with-ancestors + ((cell (make-filtered-call value filter)) + (sequence (make-array size))) + ((array? self) #f) + ((position self) pos) + ((store! self newValue) + (operate-as cell store! self newValue) + (array-set! self pos newValue) + (set! pos (+ pos 1))) + ((discard self value) + (set! most-recent-discard value)) + ((discarded-value self) most-recent-discard) + ((print self port) + (format port "#<Cell-with-history ~s>" (fetch self)))))) + + (define-access-operation fetch) + (add-setter fetch store!) + (define foo (make-cell 1)) + (print foo #f) + => "#<Cell: 1>" + (set (fetch foo) 2) + => + (print foo #f) + => "#<Cell: 2>" + (fetch foo) + => 2 + + +File: slib.info, Node: Numerics, Next: Procedures, Prev: Macros, Up: Top + +Numerics +******** + +* Menu: + +* Bit-Twiddling:: 'logical +* Modular Arithmetic:: 'modular +* Prime Testing and Generation:: 'primes +* Prime Factorization:: 'factor +* Random Numbers:: 'random +* Cyclic Checksum:: 'make-crc +* Plotting:: 'charplot +* Root Finding:: + + +File: slib.info, Node: Bit-Twiddling, Next: Modular Arithmetic, Prev: Numerics, Up: Numerics + +Bit-Twiddling +============= + + `(require 'logical)' + + The bit-twiddling functions are made available through the use of the +`logical' package. `logical' is loaded by inserting `(require +'logical)' before the code that uses these functions. + + - Function: logand N1 N1 + Returns the integer which is the bit-wise AND of the two integer + arguments. + + Example: + (number->string (logand #b1100 #b1010) 2) + => "1000" + + - Function: logior N1 N2 + Returns the integer which is the bit-wise OR of the two integer + arguments. + + Example: + (number->string (logior #b1100 #b1010) 2) + => "1110" + + - Function: logxor N1 N2 + Returns the integer which is the bit-wise XOR of the two integer + arguments. + + Example: + (number->string (logxor #b1100 #b1010) 2) + => "110" + + - Function: lognot N + Returns the integer which is the 2s-complement of the integer + argument. + + Example: + (number->string (lognot #b10000000) 2) + => "-10000001" + (number->string (lognot #b0) 2) + => "-1" + + - Function: logtest J K + (logtest j k) == (not (zero? (logand j k))) + + (logtest #b0100 #b1011) => #f + (logtest #b0100 #b0111) => #t + + - Function: logbit? INDEX J + (logbit? index j) == (logtest (integer-expt 2 index) j) + + (logbit? 0 #b1101) => #t + (logbit? 1 #b1101) => #f + (logbit? 2 #b1101) => #t + (logbit? 3 #b1101) => #t + (logbit? 4 #b1101) => #f + + - Function: ash INT COUNT + Returns an integer equivalent to `(inexact->exact (floor (* INT + (expt 2 COUNT))))'. + + Example: + (number->string (ash #b1 3) 2) + => "1000" + (number->string (ash #b1010 -1) 2) + => "101" + + - Function: logcount N + Returns the number of bits in integer N. If integer is positive, + the 1-bits in its binary representation are counted. If negative, + the 0-bits in its two's-complement binary representation are + counted. If 0, 0 is returned. + + Example: + (logcount #b10101010) + => 4 + (logcount 0) + => 0 + (logcount -2) + => 1 + + - Function: integer-length N + Returns the number of bits neccessary to represent N. + + Example: + (integer-length #b10101010) + => 8 + (integer-length 0) + => 0 + (integer-length #b1111) + => 4 + + - Function: integer-expt N K + Returns N raised to the non-negative integer exponent K. + + Example: + (integer-expt 2 5) + => 32 + (integer-expt -3 3) + => -27 + + - Function: bit-extract N START END + Returns the integer composed of the START (inclusive) through END + (exclusive) bits of N. The STARTth bit becomes the 0-th bit in + the result. + + Example: + (number->string (bit-extract #b1101101010 0 4) 2) + => "1010" + (number->string (bit-extract #b1101101010 4 9) 2) + => "10110" + + +File: slib.info, Node: Modular Arithmetic, Next: Prime Testing and Generation, Prev: Bit-Twiddling, Up: Numerics + +Modular Arithmetic +================== + + `(require 'modular)' + + - Function: extended-euclid N1 N2 + Returns a list of 3 integers `(d x y)' such that d = gcd(N1, N2) = + N1 * x + N2 * y. + + - Function: symmetric:modulus N + Returns `(quotient (+ -1 n) -2)' for positive odd integer N. + + - Function: modulus->integer MODULUS + Returns the non-negative integer characteristic of the ring formed + when MODULUS is used with `modular:' procedures. + + - Function: modular:normalize MODULUS N + Returns the integer `(modulo N (modulus->integer MODULUS))' in the + representation specified by MODULUS. + +The rest of these functions assume normalized arguments; That is, the +arguments are constrained by the following table: + +For all of these functions, if the first argument (MODULUS) is: +`positive?' + Work as before. The result is between 0 and MODULUS. + +`zero?' + The arguments are treated as integers. An integer is returned. + +`negative?' + The arguments and result are treated as members of the integers + modulo `(+ 1 (* -2 MODULUS))', but with "symmetric" + representation; i.e. `(<= (- MODULUS) N MODULUS)'. + +If all the arguments are fixnums the computation will use only fixnums. + + - Function: modular:invertable? MODULUS K + Returns `#t' if there exists an integer n such that K * n == 1 mod + MODULUS, and `#f' otherwise. + + - Function: modular:invert MODULUS K2 + Returns an integer n such that 1 = (n * K2) mod MODULUS. If K2 + has no inverse mod MODULUS an error is signaled. + + - Function: modular:negate MODULUS K2 + Returns (-K2) mod MODULUS. + + - Function: modular:+ MODULUS K2 K3 + Returns (K2 + K3) mod MODULUS. + + - Function: modular:- MODULUS K2 K3 + Returns (K2 - K3) mod MODULUS. + + - Function: modular:* MODULUS K2 K3 + Returns (K2 * K3) mod MODULUS. + + The Scheme code for `modular:*' with negative MODULUS is not + completed for fixnum-only implementations. + + - Function: modular:expt MODULUS K2 K3 + Returns (K2 ^ K3) mod MODULUS. + + +File: slib.info, Node: Prime Testing and Generation, Next: Prime Factorization, Prev: Modular Arithmetic, Up: Numerics + +Prime Testing and Generation +============================ + + `(require 'primes)' + + This package tests and generates prime numbers. The strategy used is +as follows: + + First, use trial division by small primes (primes less than 1000) + to quickly weed out composites with small factors. As a side + benefit, this makes the test precise for numbers up to one million. + + Second, apply the Miller-Rabin primality test to detect (with high + probability) any remaining composites. + + The Miller-Rabin test is a Monte-Carlo test--in other words, it's fast +and it gets the right answer with high probability. For a candidate +that *is* prime, the Miller-Rabin test is certain to report "prime"; it +will never report "composite". However, for a candidate that is +composite, there is a (small) probability that the Miller-Rabin test +will erroneously report "prime". This probability can be made +arbitarily small by adjusting the number of iterations of the +Miller-Rabin test. + + - Function: probably-prime? CANDIDATE + - Function: probably-prime? CANDIDATE ITER + Returns `#t' if `candidate' is probably prime. The optional + parameter `iter' controls the number of iterations of the + Miller-Rabin test. The probability of a composite candidate being + mistaken for a prime is at most `(1/4)^iter'. The default value of + `iter' is 15, which makes the probability less than 1 in 10^9. + + + - Function: primes< START COUNT + - Function: primes< START COUNT ITER + - Function: primes> START COUNT + - Function: primes> START COUNT ITER + Returns a list of the first `count' odd probable primes less (more) + than or equal to `start'. The optional parameter `iter' controls + the number of iterations of the Miller-Rabin test for each + candidate. The probability of a composite candidate being + mistaken for a prime is at most `(1/4)^iter'. The default value + of `iter' is 15, which makes the probability less than 1 in 10^9. + + +* Menu: + +* The Miller-Rabin Test:: How the Miller-Rabin test works + + +File: slib.info, Node: The Miller-Rabin Test, Prev: Prime Testing and Generation, Up: Prime Testing and Generation + +Theory +------ + + Rabin and Miller's result can be summarized as follows. Let `p' (the +candidate prime) be any odd integer greater than 2. Let `b' (the +"base") be an integer in the range `2 ... p-1'. There is a fairly +simple Boolean function--call it `C', for "Composite"--with the +following properties: + If `p' is prime, `C(p, b)' is false for all `b' in the range `2 + ... p-1'. + + If `p' is composite, `C(p, b)' is false for at most 1/4 of all `b' + in the range ` 2 ... p-1'. (If the test fails for base `b', `p' + is called a *strong pseudo-prime to base `b'*.) + + For details of `C', and why it fails for at most 1/4 of the potential +bases, please consult a book on number theory or cryptography such as +"A Course in Number Theory and Cryptography" by Neal Koblitz, published +by Springer-Verlag 1994. + + There is nothing probablistic about this result. It's true for all +`p'. If we had time to test `(1/4)p + 1' different bases, we could +definitively determine the primality of `p'. For large candidates, +that would take much too long--much longer than the simple approach of +dividing by all numbers up to `sqrt(p)'. This is where probability +enters the picture. + + Suppose we have some candidate prime `p'. Pick a random integer `b' +in the range `2 ... p-1'. Compute `C(p,b)'. If `p' is prime, the +result will certainly be false. If `p' is composite, the probability +is at most 1/4 that the result will be false (demonstrating that `p' is +a strong pseudoprime to base `b'). The test can be repeated with other +random bases. If `p' is prime, each test is certain to return false. +If `p' is composite, the probability of `C(p,b)' returning false is at +most 1/4 for each test. Since the `b' are chosen at random, the tests +outcomes are independent. So if `p' is composite and the test is +repeated, say, 15 times, the probability of it returning false all +fifteen times is at most (1/4)^15, or about 10^-9. If the test is +repeated 30 times, the probability of failure drops to at most 8.3e-25. + + Rabin and Miller's result holds for *all* candidates `p'. However, +if the candidate `p' is picked at random, the probability of the +Miller-Rabin test failing is much less than the computed bound. This +is because, for *most* composite numbers, the fraction of bases that +cause the test to fail is much less than 1/4. For example, if you pick +a random odd number less than 1000 and apply the Miller-Rabin test with +only 3 random bases, the computed failure bound is (1/4)^3, or about +1.6e-2. However, the actual probability of failure is much less--about +7.2e-5. If you accidentally pick 703 to test for primality, the +probability of failure is (161/703)^3, or about 1.2e-2, which is almost +as high as the computed bound. This is because 703 is a strong +pseudoprime to 161 bases. But if you pick at random there is only a +small chance of picking 703, and no other number less than 1000 has +that high a percentage of pseudoprime bases. + + The Miller-Rabin test is sometimes used in a slightly different +fashion, where it can, at least in principle, cause problems. The +weaker version uses small prime bases instead of random bases. If you +are picking candidates at random and testing for primality, this works +well since very few composites are strong pseudo-primes to small prime +bases. (For example, there is only one composite less than 2.5e10 that +is a strong pseudo-prime to the bases 2, 3, 5, and 7.) The problem +with this approach is that once a candidate has been picked, the test is +deterministic. This distinction is subtle, but real. With the +randomized test, for *any* candidate you pick--even if your +candidate-picking procedure is strongly biased towards troublesome +numbers, the test will work with high probability. With the +deterministic version, for any particular candidate, the test will +either work (with probability 1), or fail (with probability 1). It +won't fail for very many candidates, but that won't be much consolation +if your candidate-picking procedure is somehow biased toward troublesome +numbers. + + +File: slib.info, Node: Prime Factorization, Next: Random Numbers, Prev: Prime Testing and Generation, Up: Numerics + +Prime Factorization +=================== + + `(require 'factor)' + + - Function: factor K + Returns a list of the prime factors of K. The order of the + factors is unspecified. In order to obtain a sorted list do + `(sort! (factor k) <)'. + + *Note:* The rest of these procedures implement the Solovay-Strassen +primality test. This test has been superseeded by the faster *Note +probably-prime?: Prime Testing and Generation. However these are left +here as they take up little space and may be of use to an +implementation without bignums. + + See Robert Solovay and Volker Strassen, `A Fast Monte-Carlo Test for +Primality', SIAM Journal on Computing, 1977, pp 84-85. + + - Function: jacobi-symbol P Q + Returns the value (+1, -1, or 0) of the Jacobi-Symbol of exact + non-negative integer P and exact positive odd integer Q. + + - Function: prime? P + Returns `#f' if P is composite; `#t' if P is prime. There is a + slight chance `(expt 2 (- prime:trials))' that a composite will + return `#t'. + + - Function: prime:trials + Is the maxinum number of iterations of Solovay-Strassen that will + be done to test a number for primality. + + +File: slib.info, Node: Random Numbers, Next: Cyclic Checksum, Prev: Prime Factorization, Up: Numerics + +Random Numbers +============== + + `(require 'random)' + + - Procedure: random N + - Procedure: random N STATE + Accepts a positive integer or real N and returns a number of the + same type between zero (inclusive) and N (exclusive). The values + returned have a uniform distribution. + + The optional argument STATE must be of the type produced by + `(make-random-state)'. It defaults to the value of the variable + `*random-state*'. This object is used to maintain the state of the + pseudo-random-number generator and is altered as a side effect of + the `random' operation. + + - Variable: *random-state* + Holds a data structure that encodes the internal state of the + random-number generator that `random' uses by default. The nature + of this data structure is implementation-dependent. It may be + printed out and successfully read back in, but may or may not + function correctly as a random-number state object in another + implementation. + + - Procedure: make-random-state + - Procedure: make-random-state STATE + Returns a new object of type suitable for use as the value of the + variable `*random-state*' and as a second argument to `random'. + If argument STATE is given, a copy of it is returned. Otherwise a + copy of `*random-state*' is returned. + + If inexact numbers are support by the Scheme implementation, +`randinex.scm' will be loaded as well. `randinex.scm' contains +procedures for generating inexact distributions. + + - Procedure: random:uniform STATE + Returns an uniformly distributed inexact real random number in the + range between 0 and 1. + + - Procedure: random:solid-sphere! VECT + - Procedure: random:solid-sphere! VECT STATE + Fills VECT with inexact real random numbers the sum of whose + squares is less than 1.0. Thinking of VECT as coordinates in + space of dimension N = `(vector-length VECT)', the coordinates are + uniformly distributed within the unit N-shere. The sum of the + squares of the numbers is returned. + + - Procedure: random:hollow-sphere! VECT + - Procedure: random:hollow-sphere! VECT STATE + Fills VECT with inexact real random numbers the sum of whose + squares is equal to 1.0. Thinking of VECT as coordinates in space + of dimension n = `(vector-length VECT)', the coordinates are + uniformly distributed over the surface of the unit n-shere. + + - Procedure: random:normal + - Procedure: random:normal STATE + Returns an inexact real in a normal distribution with mean 0 and + standard deviation 1. For a normal distribution with mean M and + standard deviation D use `(+ M (* D (random:normal)))'. + + - Procedure: random:normal-vector! VECT + - Procedure: random:normal-vector! VECT STATE + Fills VECT with inexact real random numbers which are independent + and standard normally distributed (i.e., with mean 0 and variance + 1). + + - Procedure: random:exp + - Procedure: random:exp STATE + Returns an inexact real in an exponential distribution with mean + 1. For an exponential distribution with mean U use (* U + (random:exp)). + |