Search code examples
moduleracketrequire

How do you use the contents of a Racket submodule, which uses definitions from the defining module, in the defining module?


I need to require a module that horribly pollutes the namespace, and I'd rather not use prefix-in because it makes the code that uses it really ghastly, so I decided to try to move the code that uses this module into a submodule.

However, I can't seem to get the functions defined in that module out, while getting their dependencies in.

Here is what I've tried, with the corresponding errors I get:

#lang racket
(define foo 3)
(module mod1 racket/base
  (provide bar1)
  (require pollute)
  (define bar1 (+ 1 foo)))
(require 'mod1)
(define (biz1 e) (+ e bar1))

; foo: unbound identifier

Second attempt:

#lang racket
(define foo 3)
(module+ mod2 #f
  (provide bar2)
  (require pollute)
  (define bar2 (+ 2 foo)))
(define (biz2 e) (+ e bar2))

; bar2: unbound identifier

Third attempt:

#lang racket
(define foo 3)
(module+ mod3 #f
  (provide bar3)
  (require pollute)
  (define bar3 (+ 3 foo)))
(require 'mod3)
(define (biz3 e) (+ e bar3))

; require: unknown module
;   module name: 'mod3

Fourth attempt:

#lang racket
(define foo 3)
(module+ main
  (provide bar4)
  (require pollute)
  (define bar4 (+ 4 foo)))
(define (biz4 e) (+ e bar4))

; bar4: unbound identifier

Is this possible? Am I doing something simple wrong? Do I need to fall back on using prefix-in?


Solution

  • There are two types of submodules; those created with module that can be imported into the containing module with (require (submod "." foo)) or (require 'foo) but don't have access to the containing module's environment, and those created with module*, which can see the containing module's environment, but whose provided identifiers can't be exported to the containing module. There's no type of submodule that goes both ways; Racket doesn't support circular dependencies.

    In addition to prefix-in, you might investigate only-in to get just the identifiers from pollute that you need instead of everything.

    Or you can create a submodule with the things used both by mod1 submodule and the top level module, and require it in both:

    #lang racket/base
    
    (module foo-wrapper racket/base
      (provide foo)
      (define foo 3))
    
    (module mod1 racket/base
      (provide bar1)
      (require pollute (submod ".." foo-wrapper))
      (define bar1 (+ 1 foo)))
    
    (require 'foo-wrapper 'mod1)
    (define (biz1 e) (+ e bar1))
    (println (biz1 foo)) ; 7