Module inter-depandancies

hello,

In R6RS code i have a module A (assignment) that needs a module B (set-values-plus) and B also needs module A. Should i put all code in the same module? or is there a way to solve this problem otherwise,because when i ran a test code using modules A and B it seems to goes in an infinite loop....

here is the headers containing the import of my modules for now:

set-values-plus.sls :

#!r6rs

(library (set-values-plus) 

  (export set!-values-plus
	  return-values
	  create-return-values
	  define-or/and-set!-values)

  
  (import (rnrs base (6))
	      (Scheme+R6RS assignment))


assignment.sls :

#!r6rs

(library (assignment) ; R6RS

  (export  <- ->
	   ← →
	   :=  =:
	   <v v>
	   ⇜ ⇝)


  (import (rnrs base (6))
	  (for (rnrs base (6)) expand) ; import at expand phase (not run phase)
	  (for (rnrs syntax-case (6)) expand)
	  (for (only (rnrs io simple (6)) display newline) expand)
	  (for (Scheme+R6RS parse-square-brackets) expand) ; import at expand phase (not run phase)
	  (only (rnrs control (6)) when)
	  (only (srfi :1) first second third fourth fifth)
	  (only (srfi :13) string-set! string-copy!)
	  (srfi :25)
	  (only (srfi :43) vector-copy vector-copy!)
	  (srfi :69) ; hash table
	  (rename (flomat) (repeat repeat-flomat)
			    (shape shape-flomat)
			    (transpose transpose-flomat))
	  (Scheme+R6RS parse-square-brackets)
	  (Scheme+R6RS for_next_step)
	  (Scheme+R6RS array)
	  (Scheme+R6RS slice)
	  (Scheme+R6RS declare)
	  (Scheme+R6RS block)
	  (Scheme+R6RS def)
	  (Scheme+R6RS bracket-apply)
	  (Scheme+R6RS set-values-plus)
	  (Scheme+R6RS overload)
	  (only (racket match) match ==))

 

i add that i even checked the Guile version of the same code and all is working without the 'import':

(define-module (set-values-plus)

  #:export (set!-values-plus
	    return-values
	    create-return-values))


idem for the Kawa version:

(define-library (set-values-plus) ; R7RS

  (import (kawa base))

  (export set!-values-plus
	  return-values
	  create-return-values)

no specific 'import' of the other module are required.

finally just put all the definition in the same module and it works.

R6RS libraries cannot have cyclic dependencies. It is hard to find an explicit statement of this fact: the best I came up with is Rationale chapter 7, which says, “The library system does not address the following goals, which were considered during the design process … mutually dependent libraries …”. Similarly, the implicit phasing paper says:

In general, each library is expanded before it is imported into dependent libraries. The import forms of a set of libraries implicitly define a dependency graph. The graph is necessarily acyclic because a [sic] library import relationships cannot be recursive

In the report itself, I haven't found an direct statement, though I think the requirement can be inferred from various passages, e.g. this one from chapter 7:

The transformer expressions and bindings are evaluated and created from left to right, as described in chapter 10. The expressions of variable definitions are evaluated from left to right, as if in an implicit letrec*, and the body expressions are also evaluated from left to right after the expressions of the variable definitions. A fresh location is created for each exported variable and initialized to the value of its local counterpart. The effect of returning twice to the continuation of the last body expression is unspecified.

There are various techniques for breaking cycles. You can see some examples in the implementation of Racket CS and the "Rumble" layer, e.g.:

The need for an imperative hook is typical, so, yes, it is almost always best to restructure your code to avoid the dependency cycle.

The current implementation of modules in Guile allows cyclic dependencies, though cycles can easily create use-before-definition errors that, in my experience, are obscure and painful to debug. I say “current implementation” because I know several Guile folks find the current (ill-defined) semantics regrettable, and I think there's interest in forbidding cycles if acceptable solutions can be found for existing code bases that use them (e.g. Guix). Here's some relevant discussion from a blog post by Andy Wingo, the Guile maintainer:

The underlying Racket module system does not support cyclic dependencies, either, but Racket's unit system is a mechanism for modular code that does support cyclic dependencies. (In fact, unit predates module in Racket.)

yes "mutual dependencies" are not allowed in R6RS. Not sure about Racket but Kawa and Guile yes. I make this part run by putting all the definitions in the same file but this could have failed because, in my code i define a macro <- that use another macro set!-values-plus that itself use <- . That could lead to infinite recursive loops ! but as there is some conditionals (branching) in the 2 macros , it is written a way it is not possible of course to branch in infinite loop.

Basically set!-values-plus set! many values to identifier using <- which is an enhanced set! but itself <- allow multiple bindings and reuse set!-values-plus... Finally it finish using set! when the multiple-values are simplify in one-value assignment.

example from code comments:

(define T (make-vector 5))
{(x {T[4]} z) <v (values 1 2 3)}

 {T[4]}
 2

 (declare u v w a b c)
 {(a b c) <v (x {T[4]} z) <v (u v w) <v (values 1 2 3)}

(list a b c x {T[4]} z u v w)
 '(1 2 3 1 2 3 1 2 3)

<v is a multiple values assignment operators like in Python with tuples (a, b , c) = (1 , 2 ,3)

<v use set!-values-plus that use <- , <- can use set! or more complex assignment like vector-set! for vector, or other for hash tables....

About the python global variables, it is true it is not always obvious when reading code which value take a global variable, but it is clearly know by the program at runtime. There is the same thing in Scheme when defining a toplevel variable....