home *** CD-ROM | disk | FTP | other *** search
/ NetNews Usenet Archive 1992 #20 / NN_1992_20.iso / spool / comp / lang / scheme / 2172 < prev    next >
Encoding:
Internet Message Format  |  1992-09-09  |  17.1 KB

  1. Path: sparky!uunet!haven.umd.edu!darwin.sura.net!sgiblab!cs.uoregon.edu!ogicse!psgrain!percy!data!kend
  2. From: kend@data.rain.com (Ken Dickey)
  3. Newsgroups: comp.lang.scheme
  4. Subject: Collection iterators for Scheme
  5. Message-ID: <710@data.rain.com>
  6. Date: 8 Sep 92 17:23:54 GMT
  7. Article-I.D.: data.710
  8. Organization: Microtek DSD, Hillsboro, OR
  9. Lines: 621
  10.  
  11. [Appologies if you see this twice--mailer problems -Ken]
  12.  
  13.  
  14. The RNRS-Author comittee which reviewed Dylan made a recommendation.
  15.  
  16. >  Scheme might benefit from adopting a subset of the collection and
  17. >  sequence operations from Dylan.  In particular, the ability to
  18. >  iterate over diverse sequences would be a valuable addition to
  19. >  Scheme, and compatible with similar generic operations on numbers
  20. >  already provided in the language.
  21.  
  22. I thought I might sketch something out.
  23.  
  24. Enjoy,
  25. -Ken
  26. ;;========================================================================
  27. ; FILE         "collect.oo"
  28. ; IMPLEMENTS    Sample collection operations
  29. ; AUTHOR        Ken Dickey
  30. ; DATE          1992 September 1
  31. ; LAST UPDATED  1992 September 2
  32. ; NOTES         Expository (optimizations & checks elided).
  33.  
  34. ;               Requires YASOS (Yet Another Scheme Object System).
  35. ;;(require 'yasos)
  36.  
  37.  
  38. ;; COLLECTION INTERFACE
  39.  
  40. ;; (collection? obj)  -- predicate
  41. ;;
  42. ;; (do-elts proc coll+) -- apply proc element-wise to collections
  43. ;; (do-keys proc coll+) -- .. return value is unspecified
  44. ;;
  45. ;; (map-elts proc coll+) -- as with do-*, but returns collection
  46. ;; (map-keys proc coll+) -- e.g. (map-keys + (list 1 2 3) (vector 1 2 3))
  47. ;;                    -> #( 2 4 6 )
  48. ;;
  49. ;; (for-each-key coll proc) -- for single collection (more efficient)
  50. ;; (for-each-elt coll proc)
  51. ;;
  52. ;; (reduce proc seed coll+) -- e.g. (reduce + 0 (vector 1 2 3))
  53. ;; (any?   predicate coll+) -- e.g. (any? > (vector 1 2 3 4) (list 2 3 4 5))
  54. ;; (every? predicate coll+) -- e.g. (every? collection? collections)
  55. ;;
  56. ;; (empty? collection)  -- I bet you can guess what these do as well...
  57. ;; (size collection)
  58. ;;
  59. ;;==============================
  60. ;; Collections must implement:
  61. ;;  collection?
  62. ;;  gen-elts
  63. ;;  gen-keys
  64. ;;  size
  65. ;;  print
  66. ;;
  67. ;; Collections should implement {typically faster}:
  68. ;;  for-each-key
  69. ;;  for-each-elt
  70. ;;==============================
  71.  
  72. (define-operation (COLLECTION? obj)
  73.  ;; default
  74.   (cond
  75.     ((or (list? obj) (vector? obj) (string obj)) #t)
  76.     (else #f)
  77. ) )
  78.  
  79. (define (EMPTY? collection) (zero? (size collection)))
  80.  
  81. (define-operation (GEN-ELTS <collection>) ;; return element generator
  82.   ;; default behavior
  83.   (cond                      ;; see utilities, below, for generators
  84.     ((vector? <collection>) (vector-gen-elts <collection>)) 
  85.     ((list?   <collection>) (list-gen-elts   <collection>))
  86.     ((string? <collection>) (string-gen-elts <collection>))
  87.     (else 
  88.       (error "Operation not supported: gen-elts " (print obj #f)))
  89. ) )
  90.  
  91. (define-operation (GEN-KEYS collection)
  92.   (if (or (vector? collection) (list? collection) (string? collection))
  93.       (let ( (max+1 (size collection)) (index 0) )
  94.      (lambda ()
  95.             (cond
  96.           ((< index max+1)
  97.            (set! index (add1 index))
  98.            (sub1 index))
  99.           (else (error "no more keys in generator"))
  100.       ) ) )
  101.       (error "Operation not handled: GEN-KEYS " collection)
  102. ) )
  103.  
  104. (define (DO-ELTS <proc> . <collections>)
  105.   (let ( (max+1 (size (car <collections>)))
  106.          (generators (map gen-elts <collections>))
  107.        )
  108.     (let loop ( (counter 0) )
  109.        (cond
  110.           ((< counter max+1)
  111.            (apply <proc> (map (lambda (g) (g)) generators))
  112.            (loop (add1 counter))
  113.           )
  114.           (else 'unspecific)  ; done
  115.     )  )
  116. ) )
  117.  
  118. (define (DO-KEYS <proc> . <collections>)
  119.   (let ( (max+1 (size (car <collections>)))
  120.          (generators (map gen-keys <collections>))
  121.        )
  122.     (let loop ( (counter 0) )
  123.        (cond
  124.           ((< counter max+1)
  125.            (apply <proc> (map (lambda (g) (g)) generators))
  126.            (loop (add1 counter))
  127.           )
  128.           (else 'unspecific)  ; done
  129.     )  )
  130. ) )
  131.  
  132. (define (MAP-ELTS <proc> . <collections>)
  133.   (let ( (max+1 (size (car <collections>)))
  134.          (generators (map gen-elts <collections>))
  135.          (vec (make-vector (size (car <collections>))))
  136.        )
  137.     (let loop ( (index 0) )
  138.        (cond
  139.           ((< index max+1)
  140.            (vector-set! vec index (apply <proc> (map (lambda (g) (g)) generators)))
  141.            (loop (add1 index))
  142.           )
  143.           (else vec)  ; done
  144.     )  )
  145. ) )
  146.  
  147. (define (MAP-KEYS <proc> . <collections>)
  148.   (let ( (max+1 (size (car <collections>)))
  149.          (generators (map gen-keys <collections>))
  150.      (vec (make-vector (size (car <collections>))))
  151.        )
  152.     (let loop ( (index 0) )
  153.        (cond
  154.           ((< index max+1)
  155.            (vector-set! vec index (apply <proc> (map (lambda (g) (g)) generators)))
  156.            (loop (add1 index))
  157.           )
  158.           (else vec)  ; done
  159.     )  )
  160. ) )
  161.  
  162. (define-operation (FOR-EACH-KEY <collection> <proc>)
  163.    ;; default
  164.    (do-keys <proc> <collection>)  ;; talk about lazy!
  165. )
  166.  
  167. (define-operation (FOR-EACH-ELT <collection> <proc>)
  168.    (do-elts <proc> <collection>)
  169. )
  170.  
  171. (define (REDUCE <proc> <seed> . <collections>)
  172.    (let ( (max+1 (size (car <collections>)))
  173.           (generators (map gen-elts <collections>))
  174.         )
  175.      (let loop ( (count 0) )
  176.        (cond
  177.           ((< count max+1)
  178.            (set! <seed> 
  179.                  (apply <proc> <seed> (map (lambda (g) (g)) generators)))
  180.            (loop (add1 count))
  181.           )
  182.           (else <seed>)
  183.      ) )
  184. )  )
  185.  
  186. ;; pred true for every elt?
  187. (define (EVERY? <pred?> . <collections>)
  188.    (let ( (max+1 (size (car <collections>)))
  189.           (generators (map gen-elts <collections>))
  190.         )
  191.      (let loop ( (count 0) )
  192.        (cond
  193.           ((< count max+1)
  194.            (if (apply <pred?> (map (lambda (g) (g)) generators))
  195.                (loop (add1 count))
  196.                #f)
  197.           )
  198.           (else #t)
  199.      ) )
  200. )  )
  201.  
  202. ;; pred true for any elt?
  203. (define (ANY? <pred?> . <collections>)
  204.    (let ( (max+1 (size (car <collections>)))
  205.           (generators (map gen-elts <collections>))
  206.         )
  207.      (let loop ( (count 0) )
  208.        (cond
  209.           ((< count max+1)
  210.            (if (apply <pred?> (map (lambda (g) (g)) generators))
  211.                #t
  212.                (loop (add1 count))
  213.           ))
  214.           (else #f)
  215.      ) )
  216. )  )
  217.  
  218.  
  219. ;; SAMPLE COLLECTION -- simple-table .. also a TABLE
  220.  
  221. (define-predicate TABLE?)
  222. (define-operation (LOOKUP table key failure-object))
  223. (define-operation (ASSOCIATE! table key value)) ;; returns key
  224. (define-operation (REMOVE! table key))          ;; returns value
  225.  
  226. (define (MAKE-SIMPLE-TABLE)
  227.   (let ( (table (list)) )
  228.     (object
  229.       ;; table behaviors
  230.       ((TABLE? self) #t)
  231.       ((SIZE self) (size table))
  232.       ((PRINT self port) (format port "#<SIMPLE-TABLE>"))
  233.       ((LOOKUP self key failure-object)
  234.        (cond 
  235.          ((assq key table) => cdr)
  236.          (else failure-object)
  237.       ))
  238.       ((ASSOCIATE! self key value)
  239.        (cond
  240.          ((assq key table) => (lambda (bucket) (set-cdr! bucket value) key))
  241.          (else 
  242.            (set! table (cons (cons key value) table))
  243.            key)
  244.       ))
  245.       ((REMOVE! self key) ;; returns old value
  246.        (cond
  247.          ((null? table) (error "TABLE:REMOVE! Key not found: " key))
  248.          ((eq? key (caar table))
  249.           (let ( (value (cdar table)) )
  250.              (set! table (cdr table))
  251.              value)
  252.          )
  253.          (else
  254.            (let loop ( (last table) (this (cdr table)) )
  255.              (cond
  256.                ((null? this) (error "TABLE:REMOVE! Key not found: " key))
  257.                ((eq? key (caar this))
  258.                 (let ( (value (cdar this)) )
  259.                   (set-cdr! last (cdr this))
  260.                  value)
  261.                )
  262.                (else
  263.                 (loop (cdr last) (cdr this)))
  264.          ) ) )
  265.       ))
  266.       ;; collection behaviors
  267.       ((COLLECTION? self) #t)
  268.       ((GEN-KEYS self) (list-gen-elts (map car table)))
  269.       ((GEN-ELTS self) (list-gen-elts (map cdr table)))
  270.       ((FOR-EACH-KEY self proc)
  271.        (for-each (lambda (bucket) (proc (car bucket))) table)
  272.       )
  273.       ((FOR-EACH-ELT self proc)
  274.        (for-each (lambda (bucket) (proc (cdr bucket))) table)
  275.       )
  276. ) ) )
  277.  
  278. ;; MISC UTILITIES
  279.  
  280. (define (ZERO? obj) (= obj 0))
  281. (define (ADD1 obj)  (+ obj 1))
  282. (define (SUB1 obj)  (- obj 1))
  283.  
  284.  
  285. ;; Let lists be regular
  286.  
  287. (define (LIST-REF <list> <index>)
  288.   (if (zero? <index>)
  289.       (car <list>)
  290.       (list-ref (cdr <list>) (sub1 <index>))
  291. ) )
  292.  
  293.  
  294. ;; Nota Bene:  list-set! is bogus for element 0
  295.  
  296. (define (LIST-SET! <list> <index> <value>)
  297.  
  298.   (define (set-loop last this idx)
  299.      (cond
  300.         ((zero? idx) 
  301.          (set-cdr! last (cons <value> (cdr this)))
  302.          <list>
  303.         )
  304.         (else (set-loop (cdr last) (cdr this) (sub1 idx)))
  305.   )  )
  306.  
  307.   ;; main
  308.   (if (zero? <index>)
  309.       (cons <value> (cdr <list>))  ;; return value
  310.       (set-loop <list> (cdr <list>) (sub1 <index>)))
  311. )
  312.  
  313. (ADD-SETTER list-ref list-set!)  ; for (setter list-ref)
  314.  
  315.  
  316. ;; generator for list elements
  317. (define (LIST-GEN-ELTS <list>)
  318.   (lambda ()
  319.      (if (null? <list>)
  320.          (error "No more list elements in generator")
  321.          (let ( (elt (car <list>)) )
  322.            (set! <list> (cdr <list>))
  323.            elt))
  324. ) )
  325.  
  326. (define (MAKE-VEC-GEN-ELTS <accessor>)
  327.   (lambda (vec)
  328.     (let ( (max+1 (size vec))
  329.            (index 0)
  330.          )
  331.       (lambda () 
  332.          (cond ((< index max+1)
  333.                 (set! index (add1 index))
  334.                 (<accessor> vec (sub1 index))
  335.                )
  336.                (else #f)
  337.       )  )
  338.   ) )
  339. )
  340.  
  341. (define VECTOR-GEN-ELTS (make-vec-gen-elts vector-ref))
  342.  
  343. (define STRING-GEN-ELTS (make-vec-gen-elts string-ref))
  344.  
  345. ;;                        --- E O F "collect.oo" ---                    ;;
  346. ;;========================================================================
  347. ;; FILE            "YASOS.scm"
  348. ;; IMPLEMENTS      YASOS: Yet Another Scheme Object System
  349. ;; AUTHOR          Kenneth Dickey
  350. ;; DATE         1992 March 1
  351. ;; LAST UPDATED 1992 September 1 -- misc optimizations
  352. ;;              1992 May 22  -- added SET and SETTER
  353.  
  354. ;; REQUIRES     R^4RS Syntax System
  355.  
  356. ;; NOTES: A simple object system for Scheme based on the paper by
  357. ;; Norman Adams and Jonathan Rees: "Object Oriented Programming in
  358. ;; Scheme", Proceedings of the 1988 ACM Conference on LISP and Functional
  359. ;; Programming, July 1988 [ACM #552880].
  360. ;
  361. ;; Setters use space for speed {extra conses for O(1) lookup}.
  362.  
  363.  
  364. ;;
  365. ;; INTERFACE:
  366. ;;
  367. ;; (DEFINE-OPERATION (opname self arg ...) default-body)
  368. ;;
  369. ;; (DEFINE-PREDICATE opname)
  370. ;;
  371. ;; (OBJECT ((name self arg ...) body) ... )
  372. ;;
  373. ;; (OBJECT-WITH-ANCESTORS ( (ancestor1 init1) ...) operation ...)
  374. ;;
  375. ;; in an operation {a.k.a. send-to-super}
  376. ;;   (OPERATE-AS component operation self arg ...)
  377. ;;
  378.  
  379. ;; (SET var new-vale) or (SET (access-proc index ...) new-value)
  380. ;;
  381. ;; (SETTER access-proc) -> setter-proc
  382. ;; (DEFINE-ACCESS-OPERATION getter-name) -> operation
  383. ;; (ADD-SETTER getter setter) ;; setter is a Scheme proc
  384. ;; (REMOVE-SETTER-FOR getter)
  385. ;;
  386.  
  387. ;;;;;;;;;;;;;;;;;;;;;;;;;;;; IMPLEMENTATION ;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  388.  
  389. ;; INSTANCES
  390.  
  391. ; (define-predicate instance?)
  392. ; (define (make-instance dispatcher)
  393. ;    (object
  394. ;          ((instance?  self) #t)
  395. ;       ((instance-dispatcher self) dispatcher)
  396. ; )  )
  397.  
  398. (define make-instance 'bogus)  ;; defined below
  399. (define instance?     'bogus)
  400. (define-syntax INSTANCE-DISPATCHER  ;; alias so compiler can inline for speed
  401.    (syntax-rules () ((instance-dispatcher inst) (cdr inst)))
  402. )
  403.  
  404. (let ( (instance-tag "instance") ) ;; Make a unique tag within a local scope.
  405.                                        ;; No other data object is EQ? to this tag.
  406.   (set! MAKE-INSTANCE
  407.      (lambda (dispatcher) (cons instance-tag dispatcher)))
  408.  
  409.   (set! INSTANCE?
  410.      (lambda (obj) (and (pair? obj) (eq? (car obj) instance-tag))))
  411. )
  412.  
  413. ;; DEFINE-OPERATION
  414.  
  415.  
  416. (define-syntax DEFINE-OPERATION
  417.   (syntax-rules ()
  418.     ((define-operation (<name> <inst> <arg> ...) <exp1> <exp2> ...)
  419.      ;;=>
  420.      (define <name>
  421.        (letrec ( (former-inst #f) ;; simple caching -- for loops
  422.                  (former-method #f)
  423.                  (self
  424.                   (lambda (<inst> <arg> ...)
  425.                  (cond
  426.                        ((eq? <inst> former-inst) ; check cache
  427.                         (former-method <inst> <arg> ...)
  428.                        )
  429.                    ((and (instance? <inst>) 
  430.                          ((instance-dispatcher <inst>) self))
  431.                          => (lambda (method) 
  432.                                 (set! former-inst <inst>)
  433.                                 (set! former-method method)
  434.                                 (method <inst> <arg> ...))
  435.                        )
  436.                    (else <exp1> <exp2> ...)
  437.                ) ) )  )
  438.         self)
  439.   ))
  440.   ((define-operation (<name> <inst> <arg> ...) ) ;; no body
  441.    ;;=>
  442.    (define-operation (<name> <inst> <arg> ...)
  443.       (error "Operation not handled" 
  444.              '<name> 
  445.              (format #f (if (instance? <inst>) "#<INSTANCE>" "~s") <inst>)))
  446.   ))
  447. )
  448.  
  449.  
  450.  
  451. ;; DEFINE-PREDICATE
  452.  
  453. (define-syntax DEFINE-PREDICATE
  454.   (syntax-rules ()
  455.     ((define-predicate <name>)
  456.      ;;=>
  457.      (define-operation (<name> obj) #f)
  458.     )
  459. ) )
  460.  
  461.  
  462. ;; OBJECT
  463.  
  464. (define-syntax OBJECT
  465.   (syntax-rules ()
  466.     ((object ((<name> <self> <arg> ...) <exp1> <exp2> ...) ...)
  467.     ;;=>
  468.      (let ( (table
  469.               (list (cons <name>
  470.                           (lambda (<self> <arg> ...) <exp1> <exp2> ...))
  471.                       ...
  472.             ) ) 
  473.           )
  474.       (make-instance
  475.         (lambda (op)
  476.           (cond
  477.             ((assq op table) => cdr)
  478.             (else #f)
  479. ) ) )))) )
  480.  
  481.  
  482. ;; OBJECT with MULTIPLE INHERITANCE  {First Found Rule}
  483.  
  484. (define-syntax OBJECT-WITH-ANCESTORS
  485.   (syntax-rules ()
  486.     ((object-with-ancestors ( (<ancestor1> <init1>) ... ) <operation> ...)
  487.     ;;=>
  488.      (let ( (<ancestor1> <init1>) ...  )
  489.       (let ( (child (object <operation> ...)) )
  490.        (make-instance
  491.          (lambda (op) 
  492.             (or ((instance-dispatcher child) op)
  493.                 ((instance-dispatcher <ancestor1>) op) ...
  494.        ) )  )
  495.     )))
  496. ) )
  497.  
  498.  
  499. ;; OPERATE-AS  {a.k.a. send-to-super}
  500.  
  501. ; used in operations/methods
  502.  
  503. (define-syntax OPERATE-AS
  504.   (syntax-rules ()
  505.    ((operate-as <component> <op> <composit> <arg> ...)
  506.    ;;=>
  507.     (((instance-dispatcher <component>) <op>) <composit> <arg> ...)
  508.   ))
  509. )
  510.  
  511.  
  512.  
  513. ;; SET & SETTER
  514.  
  515.  
  516. (define-syntax SET
  517.   (syntax-rules ()
  518.     ((set (<access> <index> ...) <newval>)
  519.      ((setter <access>) <index> ... <newval>)
  520.     )
  521.     ((set <var> <newval>)
  522.      (set! <var> <newval>)
  523.     )
  524. ) )
  525.  
  526.  
  527. (define add-setter        'bogus)
  528. (define remove-setter-for 'bogus)
  529.  
  530. (define SETTER 
  531.   (let ( (known-setters (list (cons car set-car!)
  532.                               (cons cdr set-cdr!)
  533.                               (cons vector-ref vector-set!)
  534.                               (cons string-ref string-set!))
  535.          )
  536.          (added-setters '())
  537.        )
  538.  
  539.     (set! ADD-SETTER 
  540.       (lambda (getter setter) 
  541.         (set! added-setters (cons (cons getter setter) added-setters)))
  542.     )
  543.     (set! REMOVE-SETTER-FOR
  544.       (lambda (getter)
  545.         (cond
  546.           ((null? added-setters) 
  547.            (error "REMOVE-SETTER: Unknown getter" getter)
  548.           )
  549.           ((eq? getter (caar added-setters))
  550.            (set! added-setters (cdr added-setters))
  551.           )
  552.           (else 
  553.             (let loop ((x added-setters) (y (cdr added-setters)))
  554.               (cond
  555.                 ((null? y) (error "REMOVE-SETTER: Unknown getter" getter))
  556.                 ((eq? getter (caar y)) (set-cdr! x (cdr y)))
  557.                 (else (loop (cdr x) (cdr y)))
  558.           ) ) )
  559.      ) ) )
  560.     
  561.     (letrec ( (self
  562.                  (lambda (proc-or-operation)
  563.                    (cond ((assq proc-or-operation known-setters) => cdr)
  564.                          ((assq proc-or-operation added-setters) => cdr)
  565.                          (else (proc-or-operation self))) )
  566.             ) )
  567.       self)
  568. ) )
  569.  
  570.  
  571.  
  572. (define (%%MAKE-ACCESS-OPERATION <name>)
  573.   (letrec ( (setter-dispatch
  574.                (lambda (inst . args)
  575.                    (cond
  576.                         ((and (instance? inst)
  577.                        ((instance-dispatcher inst) setter-dispatch))
  578.                    => (lambda (method) (apply method inst args))
  579.                      )
  580.                  (else #f)))
  581.             )
  582.             (self
  583.                (lambda (inst . args)
  584.               (cond
  585.                      ((eq? inst setter) setter-dispatch) ; for (setter self)
  586.                  ((and (instance? inst) 
  587.                        ((instance-dispatcher inst) self))
  588.                   => (lambda (method) (apply method inst args))
  589.                      )
  590.                  (else (error "Operation not handled" <name> inst))
  591.                 )  )
  592.             )
  593.           )
  594.  
  595.           self
  596. ) )
  597.  
  598. (define-syntax DEFINE-ACCESS-OPERATION
  599.   (syntax-rules ()
  600.     ((define-access-operation <name>)
  601.      ;=>
  602.      (define <name> (%%make-access-operation '<name>))
  603. ) ) )
  604.  
  605.  
  606.  
  607. ;;---------------------
  608. ;; general operations
  609. ;;---------------------
  610.  
  611. (define-operation (PRINT obj port) 
  612.   (format port
  613.           ;; if an instance does not have a PRINT operation..
  614.           (if (instance? obj) "#<INSTANCE>" "~s") 
  615.           obj
  616. ) )
  617.  
  618. (define-operation (SIZE obj)
  619.   ;; default behavior
  620.   (cond   
  621.     ((vector? obj) (vector-length obj))
  622.     ((list?   obj) (length obj))
  623.     ((pair?   obj) 2)
  624.     ((string? obj) (string-length obj))
  625.     ((char?   obj) 1)
  626.     (else 
  627.       (error "Operation not supported: size" obj))
  628. ) )
  629.  
  630.  
  631. ;;                       --- E O F "yasos.scm" ---                       ;;
  632.