You are looking at historical revision 31196 of this page. It may differ significantly from its current revision.

Rationale

Scheme lists are mutable and untyped. The list types produced with the only exported symbol of this module, a giant macro, are typed and immutable.

Concerning mutability, Scheme's authors, G. J. Sussman and G. L. Steele jr. in their paper "The First Report on Scheme Revisited", Higher-Order and Symbolic Computation, 11, 399-404 (1998) argued:

"We also now believe that Carl Hewitt was right: we would have been better off to have introduced cells as a separate, primitive kind of object, rather than allowing assignment to any and every lambda-bound variable"

Well, cells -- or boxes, if you prefer -- exist as modules, so restricted mutability can be provided by accepting cells -- or boxes -- as item types.

Typing of list arguments on the other hand improves security of the implemented functions on the one side, but are cumbersome to use on the other: After all, we don't want to write the same routines for lists of numbers, lists of strings, lists of symbols, ... over and over again. Macros come to the rescue, you guess it! Hence this module exports only one macro, define-list-type, which implements two types, typed lists and typed sets (the latter being implemented as equivalence classes of the former), as well as a long list of functions, which are all prefixed with the prefix of the list type.

Moreover, a documentation procedure is generated, whose name can be supplied as a keyword parameter to define-list-type, it defaults to the plural form of the list type name. Called as a thunk, this procedure shows the list of generated functions, called with one of those functions' name, it shows its signature.

Two obligatory keyword parameters must be supplied, the item-predicate and the item-equality procedures.

Note, that these typed lists don't pass the list? predicate. They are different creatures, created with define-datatype and accessed with cases from the datatype module.

Programming interface

define-list-type

[syntax] (define-list-type name [documentation: docu] item-predicate: ok? item-equality: equ?)

defines a new list type, name, usually a combination of a prefix and the symbol list, whose items must pass the ok? predicate and are compared by equ?, and a documentation procedure, docu, which defaults to the plural of name. Exports two types and a long list of functions, all prefixed by the prefix of name. The list of generated functions is shown by a call to docu without arguments, the signature of such a function by the call (docu 'function).

For example, the call

(define-list-tye numlist item-predicate: number? item-equality: =)

generates the two types numlist and numset with type predicates numlist? and numset? respectively, a documentation procedure numlists and a bag of procedures all prefixed with num, most of them prefixed versions of standard list procedures, but some of them with changed order of arguments. The reason for that is consistency: The list arguments are always the last ones.

Examples


(require-library typed-lists cells)
(import typed-lists cells)

(define-list-type nlist
                  item-predicate: (lambda (x)
                                    (or (number? x)
                                        ((cell-of? number?) x)))
                  item-equality: (lambda (x y)
                                   (or (and (number? x)
                                            (number? y)
                                            (= x y))
                                       (and (cell? x)
                                            (cell? y)
                                            (= (cell-ref x)
                                               (cell-ref y)))))

(define nnil (nnull))
(nlist? nnil) ; -> #t
(nnull? nnil) ; -> #t
(null? nnil) ; -> #f
(define nls (ncons 1 nnil))
(nlist? nls) ; -> #t
(define nlst (nlist 0 1 (cell 2) 3 4))
(nlist? nlst) ; -> #t
(list? nlst) ; -> #f
(napply + 1 2 (nlist 3 4 5)) ; ->15
(nrepeat 5 0) ; -> '(0 0 0 0 0)
(nequal? (niterate-times 5 add1 0) (nlist 0 1 2 3 4)) ; -> #t
(niterate-while (lambda (x) (< x 5)) add1 0) ; -> '(0 1 2 3 4))
(niterate-until (lambda (x) (= x 5)) add1 0) ; -> '(0 1 2 3 4)
(nzip (nlist 1 2 3 4 5) (nlist 10 20 30)) ; -> '(1 10 2 20 3 30 4 5)
(ninterpose 10 (nlist 1 2 3 4 5)) ; -> '(1 10 2 10 3 10 4 10 5)
(ncdddr nlst) ; -> '(3 4)
(ncadddr nlst) ; -> 3
(nequal? (ndrop 3 nlst) (nlist 3 4)) ; -> #t
(nequal? (ndrop-while odd? (nlist 1 3 2 4 5))
         (nlist 2 4 5)) ; -> #t
(nequal? (ntake-while odd? (nlist 1 3 2 4 5))
         (nlist 1 3)) ; -> #t
(receive (head tail) (nsplit-with even? (nlist 1 3 2 4 5))
  (and (nequal? head (nlist 1 3))
       (nequal? tail (nlist 2 4 5)))) ; -> #t
(ntake 2 nlst) ; -> '(0 1)
(nlist? (nnull)) ; -> #t
(nnull? (nnull)) ; -> #t
(nnull? nls) ; -> #f
(nlist? '(1 2)) ; -> #f
(nnull? (ncdr nls)) ; -> #t
(ncar nlst) ; -> 0
(nlist? (nreverse nlst)) ; -> #t
(nreverse nlst) '(4 3 !2! 1 0)
(equal? (nlist->list nlst)
        (list 0 1 (cell 2) 3 4)) ; -> #t
(equal? (nref 2 nlst) (cell 2)) ; -> #t
(cell-set! (nref 2 nlst) 20)
(equal? (nref 2 nlst) (cell 20)) ; -> #t
(cell-ref (nref 2 nlst)) ; -> 20
(nlength nlst) ; -> 5
(nequal? (nsublist 2 4 nlst)
         (nlist (cell 20) 3)) ; -> #t
(nequal?
  (nappend (nlist 0 1 2 3)
           (nlist 4 5 6))
  (nlist 0 1 2 3 4 5 6)) ; -> #t
(nequal?
  (nappend (nlist 0)
           (nlist 1)
           (nlist 2)
           (nlist 3 4)
           (nlist 5 6 7)
           (nlist 8))
  (nlist 0 1 2 3 4 5 6 7 8)) ; -> #t
(nequal?
  (nmap add1
        (nlist 0 1 2 3))
  (nlist 1 2 3 4)) ; -> #t
(nequal?
  (nmap +
        (nlist 1 2 3)
        (nlist 10 20 30 40))
  (nlist 11 22 33)) ; -> #t
(nfold-right ncons (nnull) (nlist 0 1 2 3 4)) ; -> '(0 1 2 3 4))
(nfold-left + 0 (nlist 1 2 3) (nlist 10 20 30)) ; -> 66
(nfold-left cons '(100) (nlist 1 2 3 4)) ; -> '(((((100) . 1) . 2) . 3) . 4)
(equal?
  (call-with-values
    (lambda () (nreverse* (nlist 1 2 3) (nlist 10 20 30)))
    list)
  (list (nlist 3 2 1) (nlist 30 20 10))) ; -> #t
(nremove 0 (nlist 1 0 2 0 3 0 4)) ; -> '(1 2 3 4)
(nmerge < (nlist 2 4 5 7 8) (nlist 1 3 6 9 10))
  ; -> '(1 2 3 4 5 6 7 8 9 10))
(condition-case (nmerge < (nnull) (nlist 1 3 2))
       ((exn) #f)) ; -> #f
(nequal? (nsort <= (nlist 2 0 1 4 3))
         (nlist 0 1 2 3 4))
(not (nsorted? <= (nlist 2 0 1 4 3)))
(nsorted? <= (nlist 0 1 2 3 4))
(nevery? odd? (nlist 1 3 5)) ; -> #t
(nevery? odd? (nlist)) ; -> #t
(nsome odd? (nlist 2 3 5)) ; -> 3
(nsome odd? (nlist 2 4 6)) ; -> #f
(nnot-every? odd? (nlist 1 2 3)) ; -> #t
(nnot-any? odd? (nlist 2 4 6)) ; -> #t
(nlist->set (nlist 1 2 1 3 2 3)) ; -> '{1 2 3}
(nlist? (nlist 1 2 3)) ; -> #t
(nset? (nlist 1 2 3)) ; -> #f
(nset? (nset 1 2 2 3)) ; -> #t
(nset-in? 2 (nset 1 2 3)) ; -> #t
(nsubset? (nset 2 1 2) (nset 1 2 3 4)) ; -> #t
(nset-equal? (nset 1 2 3) (nset 2 1 3)) ; -> #t
(nsubset? (nset 1 2) (nset 1 2 3 4)) ; -> #t
(nset-add 0 (nset 1 2 3)) ; -> '{0 1 2 3}
(nset-add 2 (nset 1 2 3)) ; -> '{1 2 3}
(nset 0 1 1 0 2 3 2) ; -> '{0 1 2 3}
(nset-difference (nset 0 2 1 3) (nset 1 1)) ; -> '{0 2 3}
(nset-union (nset 1 2) (nset 2 3) (nset 3 4))
 ; -> '{1 2 3 4}
(nset-intersection (nset 1 2 3 4) (nset 2 3 5) (nset 3 4))
 ; -> '{3}
(nsubset odd? (nset 1 2 2 1 3 4)) ; -> '{1 3}

(define-list-type llist
                  item-predicate: list?
                  item-equality: equal?)
(lequal?
  (lappend (llist '(a) '(b))
           (llist '(c)))
  (llist '(a) '(b) '(c)))

Requirements

datatype

Last update

Aug 03, 2014

Author

Juergen Lorenz

License

Copyright (c) 2014, Juergen Lorenz
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:

Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.

Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
Neither the name of the author nor the names of its contributors may be
used to endorse or promote products derived from this software without
specific prior written permission. 
  
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

Version History

0.1
initial import