NuScheme

From SchemePunks

Jump to: navigation, search

Contents

[edit] What is nuScheme?

Despite my interest in a more theoretical, research-like Scheme Standard, a good point was made to me that a conservative approach might be better. As a result, I am taking the initiative to develop such a standard, as the discussion of radical alternatives is developed. This standard aims to do the following:

  • Fix some errors in R5RS.
  • Introduce a "non-obtrusive Module System"

While more radical approaches are great, Scheme as we have it is already great, and it really does satisfy the ideals of Scheme. However, there are some things that should be cleaned up. In addition, the one big problem with it is portability. This is probably the only one big issue that needs work. Given that there is already a lot of good thought on these things, a new standard could come out relatively efficiently, be non-disruptive, and would just work.

In order to accomplish this objective, I will start with the R5RS text, adjust what isn't working, add the module system, and adjust the standard for organization and content.

  1. nuScheme Standard
  2. nuScheme Formal Standard

[edit] Issues to fix in R5RS

  • Deal with Multiple Values and Continuations
  • Clarify Strings and Characters
  • Fix Formal Specifications

[edit] Module System

The following details Taylor Campbell's alternative proposal for R6RS's module system.

[edit] Syntax

Here is a pseudo-BNF grammar describing the syntax of the language I am proposing as an alternative to the current language in SRFI 83:

<system> ---> <component definition> ...
<component definition> --->
  <interface definition> | <module definition>

<interface definition> ---> (DEFINE-INTERFACE <name> <interface>)
<interface> --->
    <name>
  | (EXPORT <export> ...)
  | (MODIFY-INTERFACE <interface> <modifier command> ...)
  | (COMPOUND-INTERFACE <interface> ...)
  | (INVERT-INTERFACE <interface> <modifier command> ...)
  ; INVERT-INTERFACE is used for rename-on-export: it is equivalent to
  ; the supplied interface, except that names are taken from the
  ; implementation module and translated per the modifier commands to
  ; the actual interface's names
<export> ---> <name> | (<name> <export type>)
  ; possibly also (<name> [<export type>] <documentation>)
<export type> ---> VARIABLE | SYNTAX
  ; Syntactic exports *must* be specified as such.  VARIABLE is the
  ; default.

<module definition> --->
    (DEFINE-MODULE <name> <interface>
      <module clause>    ; at least one clause needed
      <module clause>
      ...)
  | (DEFINE-MODULE <name> <module>)
<module clause> --->
    (IMPORTS <module> ...)
  | (FILES <pathname specifier> ...)
  | (CODE <command or definition> ...)
  | (FOR-SYNTAX <module clause> ...)
  ; possible extensions like (OPTIMIZE <compiler optimizer specifier>)
  ; to request compiler optimizations, (READER <reader specifier>) to
  ; supply an entirely different reader like JAR's SGOL, &c.
<module> --->
  <name> | (MODIFY <module> <modifier command> ...)
  ; anonymous modules could be added here, for use within parametric
  ; modules, for example

<modifier command> --->
    (ONLY <identifier> ...)
  | (HIDE <identifier> ...)
  | (PREFIX <prefix>)
  | (RENAME (<from> <to>) ...)
  | (ALIAS (<from> <to>) ...)
  ; &c., with whatever names are deemed best

<Name> is left unspecified: it might be a simple Scheme symbol, or, if the authors insist, a URI, or a list of symbols, or a dotted list of symbols, or anything like that. (Clearly a list of symbols would lead to some ambiguity, but the language could be modified to work around it.)

[edit] Examples

This section contains examples of the module system, corresponding with the examples presented in the current SRFI document:

;;;; Interfaces

(define-interface stack-interface
  (export make      ; (MAKE) - construct a new stack
          push!     ; (PUSH! stack item) - push item onto stack
          pop!      ; (POP! stack) - pop stack, returning top item
          empty!    ; (EMPTY! stack) - empty out all of stack
          ))

(define-interface balloons-interface
  (export make push pop))

(define-interface party-interface
  (export make-party pop!
          pop-again!   ; Not sure where this is meant to be defined.
          make push    ; balloon operations
          pop!         ; stack operation
          ))

;;;; Implementation Modules

(define-module list-stacks stacks-interface
  (import scheme)
  (code          ; or stick this in a file, and use FILES
    (define (make) (list '()))
    (define (push! s v) (set-car! s (cons v (car s))))
    (define (pop! s)
      (let ((v (caar s)))
        (set-car! s (cdar s))
        v))
    (define (empty! s) (set-car! s '()))
    ))

;;; Stacks could also be implemented with the same interface, for
;;; instance, in a VECTOR-STACKS module, which would use a vector
;;; buffer for the stack.

(define-module balloons balloons-interface
  (import scheme)
  (code
    (define (make w h) (cons w h))
    (define (push b amt) (cons (- (car b) amt) (+ (cdr b) amt)))
    (define (pop b)
      (display "Boom! ")
      (display (* (car b) (cdr b)))
      (newline))
    ))

(define-module parties (invert-interface party-interface
                         (rename (balloon:make make)
                                 (balloon:push push)
                                 (party-pop! pop!)))
  (import scheme
          (modify list-stacks (only make push! pop!))
          ;; could also be (MODIFY LIST-STACKS (HIDE EMPTY!))
          (prefix balloon: balloons))
  (code
    (define (make-party)
      (let ((s (make)))    ; MAKE is from STACKS
        (push! s (balloon:make 10 10))  ; PUSH! is from STACKS, too
        (push! s (balloon:make 12 9))
        s))
    (define (party-pop! p)
      (balloon:pop (pop! p)))
    ))

[edit] Syntactic Tower Examples

And examples of the syntactic tower, assuming a syntactic-closure-based macro system:

;;;; Interfaces

(define-interface syntax-checking-interface
  (export ... valid-lambda-bvl? ...))

;;;; Implementation Modules

(define-module syntax-checking syntax-checking-interface
  (import scheme ...)
  (code
    (define (valid-lambda-bvl? obj env)
      (or (identifier? obj)
          (and (pair? obj)
               (let loop ((bvl obj) (seen '()))
                 (or (and (identifier? bvl)
                          (not (seen? bvl seen env)))
                     (and (pair? bvl)
                          (not (seen? (car bvl) seen env))
                          (loop (cdr bvl)
                                (cons (car bvl) seen))))))))

    (define (seen? id list env)
      (or (null? list)
          (and (not (identifier=? env id env (car list)))
               (seen? id (cdr list) env))))
    ))

;;; (I use the standard and traditional name here, not LET-VALUES.)

(define-module receiving (export (receive syntax))
  (import scheme)
  (for-syntax (import scheme syntax-checking))
  (code
    (define-syntax receive
      (syntactic-closure-rules usage-env transformer-env
        ((RECEIVE ,bvl ,producer ,body ...)
         (valid-lambda-bvl? bvl usage-env)
         (let ((c (lambda (x) (close-syntax x transformer-env))))
           (make-syntactic-closure usage-env '()
             `(,(c 'CALL-WITH-VALUES) (,(c 'LAMBDA) () ,producer)
                (,(c 'LAMBDA) ,bvl ,@body)))))
        ;; Actually, the SRFI document's example is buggy because it
        ;; does not list the indirect exports CALL-WITH-VALUES and
        ;; LAMBDA.  (This is the list of indirect exports/auxiliary
        ;; names.)  Such omission usually wouldn't be a problem, but
        ;; it could consequently be the source of obscure bugs later
        ;; on where least expected.
        (CALL-WITH-VALUES LAMBDA)))
    ))

(define-module let-division (export (let-division syntax))
  (import scheme receiving)
  (code

    (define (quotient&remainder n d)
      (values (quotient n d) (remainder n d)))

    ;;; There is, in fact, no need to specify the indirect export of
    ;;; QUOTIENT&REMAINDER here, because the information is readily
    ;;; available to a SYNTAX-RULES compiler, which can generate the
    ;;; indirect exports reliably on its own in all cases.

    (define-syntax let-division
      (syntax-rules ()
        ((LET-DIVISION n d (q r) body0 body1 ...)
         (RECEIVE (q r) (QUOTIENT&REMAINDER n d)
           body0
           body1
           ...))))
    ))

[edit] Minor Quibbles

  • What name to use? Module, library, package, structure, unit, component, ...? Personally, I'd actually prefer to use the name 'implementation' for what I called modules above. I used the term 'module' simply because it is probably the most widely recognized general term for the notion of module systems. I don't like the name 'library' because it implies that, well...libraries are intended to be libraries, not just any bodies of code that might be used for any purpose, like being the entry point to an application.
  • The term 'interface inversion' is a bit weird and due to my hasty concoction of it. A better term is in order. (I briefly considered ydifom, too, but concluded it too cryptic.) The concept was hastily designed as well, and I am not yet entirely sure of it. Rename-on- export is still useful, though, and the only other way I could think to accomplish it was through an intermediate module:
(define-interface foo-interface ...)
(define-module %foo (modify-interface foo-interface
               (rename (frob grovel) ...))
  ...)
(define-module foo (modify %foo (rename (grovel frob) ...)))
  • I am presently ambivalent about how modules and interfaces should be named. At times I prefer simple symbol naming schemes, whereas at other times I am partial to lists of symbols. I think using URIs for the purpose is rather silly. However, I don't have a very strong opinion either way on the matter.
Personal tools