This is a proposal for adding custom I/O ports to R7RS small Scheme. I am publishing this document to invite wide comment. There is nothing official about it. I retain sole responsibility for it, including all errors.
Custom ports in R6RS are like those in most systems: basically a set of procedures which are invoked when standard port operations are executed. For example, if you create a custom character input port, you may then call read on it, and the normal read algorithm will be invoked, but it will read characters not from a file or a string, but rather from one of the procedures set up when the port was created, the one corresponding to read-char. However, the R6RS interface to creating custom ports, like all others I have seen, is highly inflexible. The set of procedures varies depending on whether the port is input or output, binary or character-based. If you get the order of procedures wrong, you lose. And if new basic procedures or port types are added by an implementation, the existing port constructors will require supplementation with new constructors. Therefore, I am proposing a pattern whereby a custom port is not a record of procedures, but a special case of what Common Lisp calls a disembodied property list: a map from symbols to procedures. (This does not imply, of course, that a custom port must be implemented using a list.) When such a port is created, it has a variety of default behaviors corresponding to the standard port operations. The resulting port isn't good for anything much. To make the port useful, you replace its behaviors: for example, you can redefine read-char with an implementation-dependent procedure that reads from a network port. You can replace not only the lowest-level ones but higher-level ones: for example, you can redefine read to do non-Scheme parsing if you want. Removing a behavior causes it to revert to the default. Some symbols and their associated behaviors are input-related, some are output-related, some are neither. You can also change non-standardized behaviors which your Scheme implementation provides. 5 identifiers are bound to procedures by this proposal: (port? object) answers true if its argument is a port. This is made necessary by the fact that custom ports can be input ports, output ports, both, or neither. A custom port returns #t to input-port? if it has a non-default behavior for any input-related symbol. Likewise, it returns #t to output-port? if it has a non-default behavior for any output-related symbol. (make-custom-port) returns a custom port with default behaviors. (custom-port-get custom-port symbol) returns the behavior of the custom-port associated with the symbol. The standard symbols are the names of standard procedures, and the procedures returned take the same number of arguments with the same semantics as those standard procedures. (custom-port-set! custom-port symbol procedure) changes the behavior associated with symbol in custom-port to procedure. (custom-port-remove! custom-port symbol) reverts the behavior associated with symbol in custom-port to the default. Here are the 6 standard input-related symbols and their default behaviors. read Performs the normal read algorithm read-char Returns an eof-object peek-char Returns an eof-object read-line Performs the normal read-line algorithm read-u8 Returns an eof-object peek-u8 Returns an eof-object Here are the 5 standard output-related symbols and their default behaviors. write Performs the normal write algorithm display Performs the normal display algorithm newline Performs the normal newline algorithm write-char Does nothing write-u8 Does nothing Here are the remaining 2 standard symbols and their default behaviors. port-u8-position Does nothing set-port-u8-position! Does nothing -- John Cowan <[email protected]> http://www.ccil.org/~cowan Charles li reis, nostre emperesdre magnes, Set anz totz pleinz ad ested in Espagnes. _______________________________________________ r6rs-discuss mailing list [email protected] http://lists.r6rs.org/cgi-bin/mailman/listinfo/r6rs-discuss
