Bohdan Ivanov
Bohdan Ivanov

Reputation: 816

How to avoid loading cycle in Racket?

I have quite simple set of .rkt sources and, say, "a.rkt" and "b.rkt" among them. I'd like to be able to write (require "a.rkt") in "b.rkt" and vice versa. Now I'm facing error about "loading cycle".

Can I solve this issue with bare modules without adding units? Does Racket have anything similar to forward declaration so I could simple add missing signature instead of requiring? If both answers are "No", does someone know good and understandable tutorial on how to implement units with typed/racket (aside of official docs)?

Upvotes: 6

Views: 551

Answers (1)

Greg Hendershott
Greg Hendershott

Reputation: 16260

You can use lazy-require:

;; a.rkt
#lang racket
(require racket/lazy-require)
(lazy-require ["b.rkt" (b)])
(provide a)
(define (a) 'a)
(list (a) (b))

;; b.rkt
#lang racket
(require racket/lazy-require)
(lazy-require ["a.rkt" (a)])
(provide b)
(define (b) 'b)
(list (a) (b))

Notice that you must tell lazy-require the specific things you want to import. That's because it is implemented in terms of dynamic-require plus set!.

If you peek at the source for xrepl, you'll see it define a defautoload macro, which (modulo some N/A details) is simply:

(define-syntax-rule (defautoload libspec id ...)
  (begin
    (define id
      (make-keyword-procedure
       (λ (kws kw-args . args)
         (set! id (dynamic-require 'libspec 'id))
         (keyword-apply id kws kw-args args))))
    ...))

Upvotes: 7

Related Questions