[plt-scheme] get the list of modules in a namespace

From: YC (yinso.chen at gmail.com)
Date: Fri Aug 1 03:03:18 EDT 2008

On Wed, Jul 30, 2008 at 6:57 PM, Eli Barzilay <eli at barzilay.org> wrote:

>
> Seems like there is only `namespace-module-registry', which returns a
> value that you can't really use for anything (see the docs).  But I
> think that to merge two namespaces you'll need to scan the bindings
> from each one and create the appropriate bindings in the result, and
> `identifier-binding' is what is needed for doing this.
>

Thanks Eli.

I got from identifier-binding to resolved-module-path, and was able to get
quite a bit to work, except the following issues:

   1. namespace-require does not work with built-in modules such as %network
   2. namespace-require also does not work with top-level modules such as
   'cake
   3. top-level bindings requires a different approach

Lastly - it appears expensive to having to loop through all bindings...
hopefully something like namespace-module-registry can offer more in the
future? ;)

Below is what I've got in case anyone is interested...

;; retrieve the module binding by sym and namespace
(define (get-module-binding sym (ns (current-namespace)))
  (parameterize ((current-namespace ns))
    (identifier-binding (namespace-symbol->identifier sym))))

;; retrieve the module path (resolved) by sym and namespace
(define (get-module-path sym (ns (current-namespace)))
  (parameterize ((current-namespace ns))
    (let ((binding (get-module-binding sym ns)))
      (cond ((or (eq? binding #f) (equal? binding 'lexical))
             binding)
            (else
             (resolved-module-path-name
              (module-path-index-resolve
               (car binding))))))))

;; filters duplicates in a list.
(define (list->unique-list lst)
  (define (helper rest acc)
    (cond ((null? rest) (reverse acc))
          (else
           (if (member (car rest) acc)
               (helper (cdr rest) acc)
               (helper (cdr rest) (cons (car rest) acc))))))
  (helper lst '()))

;; turn the symbols into module path and filter dupes.
(define (namespace->module-paths (ns (current-namespace)))
  (list->unique-list
   (map (lambda (sym)
          (get-module-path sym ns))
        (namespace-mapped-symbols ns))))

;; compare two module paths and return the differences (one way)
(define (namespace-module-paths-diff from-ns to-ns)
  (let ((from-paths (namespace->module-paths from-ns))
        (to-paths (namespace->module-paths to-ns)))
    (filter (lambda (p)
              (not (member p to-paths)))
            from-paths)))

;; take the diffs in module paths and require them.
(define (namespace-merge from-ns to-ns)
  (let ((ns-paths (namespace-module-paths-diff from-ns to-ns)))
    (parameterize ((current-namespace to-ns))
      (for-each (lambda (path)
                  (when path
                    ;; doesn't work with #%network or top-level modules
                    (namespace-require path)))
                ns-paths))))

;; examples...
(define ns (make-base-namespace))

;; current-namespace in top-level is scheme. will choke on #%network for
now.
(namespace-merge (current-namespace) ns)
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.racket-lang.org/users/archive/attachments/20080801/33772b9a/attachment.html>

Posted on the users mailing list.