Skip to main content
Log in

Path resolution for nested recursive modules

  • Published:
Higher-Order and Symbolic Computation

Abstract

The ML module system facilitates the modular development of large programs, through decomposition, abstraction and reuse. To increase its flexibility, a lot of work has been devoted to extending it with recursion, which is currently prohibited. The introduction of recursion adds expressivity to the module system. However it also creates problems that a non-recursive module system does not have.

In this paper, we address one such problem, namely resolution of path references. Paths are how one refers to nested modules in ML. Without recursion, well-typedness guarantees termination of path resolution, in other words, we can statically determine the module that a path refers to. This does not always hold with recursive module extensions, since the module system then can encode a lambda-calculus with recursion, whose termination is undecidable regardless of well-typedness. We formalize this problem of path resolution by means of a rewrite system on paths and prove that the problem is undecidable even without higher-order functors, via an encoding of the Turing machine into a calculus with just recursive modules, first-order functors, and nesting. Motivated by this result, we introduce a further restriction on first-order functors, limiting polymorphism on functor parameters by requiring signatures for functor parameters to be non-recursive, and show that this restriction is decidable and admits terminating path resolution.

This is a preview of subscription content, log in via an institution to check access.

Access this article

Price excludes VAT (USA)
Tax calculation will be finalised during checkout.

Instant access to the full article PDF.

Fig. 1
Fig. 2
Fig. 3
Fig. 4
Fig. 5
Fig. 6
Fig. 7
Fig. 8
Fig. 9
Fig. 10

Similar content being viewed by others

Notes

  1. In Traviata, structures as well as signatures for structures are also extended with declarations of self variables, or recursion variables. That extension is not essential with respect to OCaml, but rather a design choice at the level of the surface syntax, which facilitates the formal study.

  2. This problem alone could be fixed by adapting Dreyer’s proposal [7]. But as motivated by the earlier examples, we believe our approach is more robust in the presence of recursion.

  3. The general form of an abbreviation binding for p is m=λ(x 1)…λ(x n )p.

References

  1. Boudol, G.: The recursive record semantics of objects revisited. J. Funct. Program. 14, 263–315 (2004)

    Article  MathSciNet  MATH  Google Scholar 

  2. Crary, K., Harper, R., Puri, S.: What is a recursive module? In: ACM SIGPLAN Conference on Programming Language Design and Implementation, pp. 50–63 (1999)

    Google Scholar 

  3. Cremet, V., Garillot, F., Lenglet, S., Odersky, M.: A core calculus for Scala type checking. In: Int. Symposium on Mathematical Foundations of Computer Science (2006)

    Google Scholar 

  4. Dauchet, M., Tison, S.: The theory of ground rewrite systems is decidable. In: IEEE Symposium on Logic in Computer Science (1990)

    Google Scholar 

  5. Dreyer, D.: A type system for well-founded recursion. In: ACM SIGPLAN-SIGACT Symposium on Principles of Programming Languages (2004)

    Google Scholar 

  6. Dreyer, D.: Recursive type generativity. In: ACM SIGPLAN International Conference on Functional Programming (2005)

    Google Scholar 

  7. Dreyer, D.: Post to the Caml mailing list. (2007). http://caml.inria.fr/pub/ml-archives/caml-list/2007/03/73e1ea81e35002046fdce6f14c1d8848.en.html

  8. Dreyer, D.: A type system for recursive modules. In: ACM SIGPLAN International Conference on Functional Programming (2007)

    Google Scholar 

  9. Dreyer, D., Crary, K., Harper, R.: A type system for higher-order modules. In: ACM SIGPLAN-SIGACT Symposium on Principles of Programming Languages, pp. 236–249 (2003)

    Chapter  Google Scholar 

  10. Dreyer, D., Rossberg, A.: Mixin’ up the ML module system. In: ACM SIGPLAN International Conference on Functional Programming, pp. 307–320 (2008)

    Google Scholar 

  11. Harper, R., Mitchell, J.C., Moggi, E.: Higher-order modules and the phase distinction. In: ACM SIGPLAN-SIGACT Symposium on Principles of Programming Languages, pp. 341–354 (1990)

    Google Scholar 

  12. Hirschowitz, T., Leroy, X.: Mixin modules in a call-by-value setting. In: European Symposium on Programming. Springer LNCS, vol. 2305, pp. 6–20 (2002)

    Google Scholar 

  13. Hopcroft, J., Motwani, R., Ullman, J.: Introduction to Automata Theory, Languages, and Computation. Addison-Wesley, Reading (2001)

    MATH  Google Scholar 

  14. Im, H., Nakata, K., Garrigue, J., Park, S.: A syntactic type system for recursive modules. In: ACM SIGPLAN Conference on Object-Oriented Programming, Systems, Languages, and Applications, pp. 993–1012 (2011)

    Google Scholar 

  15. Kahn, G.: Natural semantics. In: Symposium of Theoretical Aspects of Computer Science, pp. 22–39 (1987)

    Google Scholar 

  16. Leroy, X.: Applicative functors and fully transparent higher-order modules. In: ACM SIGPLAN-SIGACT Symposium on Principles of Programming Languages, pp. 142–153. ACM Press, New York (1995)

    Google Scholar 

  17. Leroy, X.: A syntactic theory of type generativity and sharing. J. Funct. Program. 6(5), 667–698 (1996)

    Article  MathSciNet  MATH  Google Scholar 

  18. Leroy, X.: A modular module system. J. Funct. Program. 10(3), 269–303 (2000)

    Article  MATH  Google Scholar 

  19. Leroy, X.: A proposal for recursive modules in Objective Caml. Available at http://caml.inria.fr/pub/papers/xleroy-recursive_modules-03.pdf (2003)

  20. Leroy, X., Doligez, D., Garrigue, J., Rémy, D., Vouillon, J.: The Objective Caml System, Release 3.11. Software and documentation available on the Web, http://caml.inria.fr/ (2008)

  21. Milner, R., Tofte, M., Harper, R., MacQueen, D.: The Definition of Standard ML—Revised. MIT Press, Cambridge (1997)

    Google Scholar 

  22. Montagu, B., Rémy, D.: Modeling abstract types in modules with open existential types. In: ACM SIGPLAN-SIGACT Symposium on Principles of Programming Languages, pp. 354–365 (2009)

    Google Scholar 

  23. Mottl, M.: OCaml bug report. http://caml.inria.fr/mantis/view.php?id=3476 (2005)

  24. Nakata, K.: OCaml bug report. http://caml.inria.fr/mantis/view.php?id=3674. (2005)

  25. Nakata, K., Garrigue, J.: Recursive modules for programming. In: ACM SIGPLAN International Conference on Functional Programming. ACM Press, New York (2006)

    Google Scholar 

  26. Nakata, K., Garrigue, J.: Path resolution for recursive nested modules is undecidable. In: Int. Workshop on Termination (WST), Paris, France (2007)

    Google Scholar 

  27. Nakata, K., Ito, A., Garrigue, J.: Recursive object-oriented modules. In: Int. Workshop on Foundations of Object-Oriented Languages (2005)

    Google Scholar 

  28. Russo, C.: First-class structures for standard ML. In: European Symposium on Programming. Springer LNCS, vol. 1782 (2000)

    Google Scholar 

  29. Russo, C.: Recursive structures for standard ML. In: ACM SIGPLAN International Conference on Functional Programming, pp. 50–61. ACM Press, New York (2001)

    Google Scholar 

  30. Russo, C.: Non-dependent types for standard ML modules. In: ACM SIGPLAN Symposium on Principles and Practice of Declarative Programming. Springer LNCS, vol. 1702, pp. 80–97 (1999)

    Google Scholar 

  31. Washburn, G.A.: Scala Mailing List. http://article.gmane.org/gmane.comp.lang.scala/13573/ (2008)

Download references

Acknowledgements

We thank the referees for helping us improve this article, and Olivier Danvy for his editorial support. James Chapman made helpful comments on the final version.

K. Nakata’s research was supported by the European Regional Development Fund (ERDF) through the Estonian Centre of Excellence in Computer Science (EXCS), the Estonian Ministry of Education and Research target-financed research theme no. 0140007s12, and the Estonian Science Foundation grant no. 9398.

Author information

Authors and Affiliations

Authors

Corresponding author

Correspondence to Jacques Garrigue.

Appendix A: Proofs for terminating path evaluation

Appendix A: Proofs for terminating path evaluation

In this appendix, we give proofs for the properties and theorems of Sect. 6.

1.1 A.1 Safe programs

We first define a notion of safety for termination, which will be needed to prove Proposition 2.

Definition 6

A path p reduces safely for termination to q with respect to a program P when P t pq is derivable, ⊢ t being the inference system obtained by adding the rules d-dot  and d-app  of Fig. 11 to the rules in Fig. 8 where ⊢ is replaced by ⊢ t . A path p is safe for termination for the signature S with respect to P when P t p:S is derivable. It is just safe for termination if P t p:{}. A substitution θ is safe for termination with respect to P when P t θ safe is derivable.

Fig. 11
figure 11

Safety for termination

Lemma 1

(Typing equivalence)

If Pp:S, Ppq, and Pp′↓q, then Pp′:S.

Proof

(Coq-checked) By inversion of s-rec. □

Lemma 2

(Substitution)

If Pp:S and \(P \vdash \theta ~\textsf {safe}\), then Pθ(p):S. Moreover, if Ppq, then Pθ(p)↓θ(q) when q is rooted, and otherwise Pθ(p)↓r and Pθ(q)↓r for the same path r. Both results also hold for t .

Proof

(Coq-checked) We prove these statements by mutual induction on the structure of the derivation of Pp:S and the safe reductions and safe substitutions involved. The last rule is necessarily s-rec, with first premise Ppq. We perform case analysis on q.

Case 1::

q is a rooted path.

We first show that Pθ(p)↓θ(q) by induction on the derivation of Ppq with case analysis on the last rule used.

Case r-src::

We have p=q, Pp↦(θ′,e) and Pθ′ safe for some θ′ and e. After substitution we have Pθ(p)↦(θ(θ′),e). By induction hypothesis, for any x in dom θ′ we have Pθ(θ′(x)):sig P (x), so that Pθ(θ′) safe, and we conclude.

Case r-exp::

The hypotheses are Pp↦(θ′,p′), Pθ safe′ and Pθ′(p′)↓q. If θ′(p′) were a variable path, we would have Pθ′(p′)↓θ′(p′), and q would be a variable path too, which contradicts our assumption. Therefore we have Pθ(p)↦(θ(θ′),p′), Pθ(θ′) safe and, by induction hypothesis, Pθ(θ′(p′))↓θ(q), and we conclude.

Cases r-dot and r-app: Immediate. Note that p′ and \(p'_{1}\) cannot be variable paths.

Finally, we need to show that Pθ(q):S, relying on the second premise of s-rec (Pq.m i :S i ). By induction hypothesis we have Pθ(q.m i ):S i , and since θ(q.m i )=θ(q).m i we conclude Pθ(q):S by s-rec.

Case 2::

q is a variable path.

Suppose q=x.m 1m n . If θ(x) is a variable path, then θ(q) is a variable path, and Pθ(q)↓θ(q) by Pθ safe and r-vp. We can prove by an easy induction that Pθ(p)↓θ(q) (which also gives us the extra result with r=θ(q)), and we obtain Pθ(p):S like in Case 1.

If θ(x) is not a variable path, we must be more careful, as new reduction steps may appear, both in the reductions of p and of its submodules for s-rec. For this reason we prove Pθ(p):S by induction on the derivation of Ppq, assuming Pp:S as extra hypothesis. We perform case analysis on the last rule used.

Case r-src::

impossible.

Case r-vp::

immediate by Pθ safe; we trivially have convergence since p=q.

Case r-exp::

We have Pp↦(θ′,p′) and Pθ′(p′)↓q. By applying the induction hypothesis to the latter, we obtain Pθ(θ′(p′)):S and conclude by r-exp.

Case r-dot::

By hypothesis Pp.m:S, so that Pp:{m:S}, and by induction hypothesis Pθ(p):{m:S}, thus Pθ(p.m):S. For convergence, either p′ is rooted, and the new left premise is Pθ(p)↓θ(p′), so that we can conclude using the induction hypothesis for the right premise; or p′ is a variable path, and there exists a path r such that Pθ(p)↓r and Pθ(p′)↓r. We know that Pr:{m:S} by typing equivalence, so that there is a r′ such that Pr.mr′, and as result both Pθ(p.m)↓r′ and Pθ(p′.m)↓r′ by the uniqueness of safe reductions.

Case r-app::

\(p'_{1}\) cannot be a variable path, since \(p'_{1}(p_{2})\) would not be valid. Thus we have \(P \vdash \theta (p_{1}) \downarrow \theta (p_{1}')\). From the hypothesis Pp 1(p 2):S, we obtain \(P \vdash p'_{1}(p_{2}) :S\), since they both reduce to the same q. By induction hypothesis we obtain \(P \vdash \theta (p'_{1}(p_{2})) : S\), thus Pθ(p 1(p 2)):S by r-app. We obtain convergence in the same way.

The same proof applies to ⊢ t : a dangling path, as in the conclusion of rules d-dot and d-app, is a rooted path such that none of its prefixes refers to an abbreviation, but itself cannot be looked up. This property is preserved by substitution. □

The following lemma relates reduction steps and safety derivations. It is used in the ensuing proof of termination.

Lemma 4

If P is safe, Pq:S, and qqby a reduction step of \(\it Rules_{P}\), then Pq′:S, and the size of its derivation is strictly smaller than the size of Pq:S. This also holds for P safe for termination and t .

Proof

First note that it is sufficient to prove this property for S={}: Pq:S is equivalent to ∀apS,Pq.ap:{}, and if qq′ then q.apq′.ap.

We prove it by induction on the structure of q.

If the reduction step was on q itself (i.e. not on one of its arguments), then there can be only one such redex, and this reduction corresponds exactly to the first use of r-exp in our derivation. After reduction, this r-exp step disappears, replaced by its third premise, and the derivation is otherwise unchanged, so the size of the derivation is strictly smaller.

If the reduction was done on an argument of q, by inversion of Pq:{}, this argument must be safe for a signature S appearing in P. By induction hypothesis, after reduction this proof of safety becomes smaller. Moreover, if this argument is required for reducing q, i.e. if by some use of r-exp it becomes the head of the path we are reducing, then the next step in the derivation was necessarily to reduce it, so that a second occurrence of r-exp disappears. □

Proposition 2

If P is safe (or safe for termination) and q is a ground path, then the evaluation of q (in the sense of Definition 3) with respect to P terminates.

Proof

Note that any safe program is also safe for termination, so we only consider the second case.

We first prove that for any signature S used in P, P t q:S can be derived by induction on q. This amounts to proving that there is a path q″ such that P t q.apq″, for any access path ap in S. We prove it by induction on q′=q.ap.

  • If q′=ϵ, P t ϵϵ by r-src.

  • If q′=p.m, then by induction hypothesis P t pp′, and either p′.m is dangling thus P t p.mp′.m holds by d-dot, or there exist θ and e such that Pp′.m↦(θ,e), and since P t pp′, the arguments of p′, i.e. θ, are safe for termination. If e is a path, then by the safety of P, P t e:{}, and by our substitution lemma, P t θ(e):{}. Otherwise Pp′.mp′.m by r-src.

  • If q′=p 1(p 2), then by induction hypothesis \(P \vdash _{\mathsf {t}}p_{1} \downarrow p'_{1}\) and P t p 2:S 2 for any S 2 in P, and either \(p'_{1}(p_{2})\) is dangling, and \(P \vdash _{\mathsf {t}}p_{1}(p_{2}) \downarrow p'_{1}(p_{2})\) by d-app, or there exist θ and e s.t. \(P \vdash p'_{1}(p_{2}) \mapsto (\theta , e)\), and from our two induction hypotheses, the arguments of \(p'_{1}(p_{2})\), i.e. θ, are safe for termination, which lets us conclude as in the p.m case.

Next we show that the evaluation of q terminates by induction on the size of the derivation of P t q:{}. This size is finite, and Lemma 4 provides the induction step. □

1.2 A.2 Correctness of semi-ground normalization

Theorem 1

(Correctness)

For any program P, lock π and path p, if sgnlz(P,π,p) = q then Ppq. Moreover, for any substitution θ, if \(\mathsf{vp\_subs}(P,\pi ,\theta ) = \rho \), then \(P \vdash \theta ~\textsf {safe}\), and for any x∈dom(θ) and \(ap\in \textsf {sig}(x)\), Pθ(x.ap)↓ρ(x.ap).

Proof

(Coq-checked) We prove both properties by functional induction.

If p=x or p=ϵ, then Ppp.

If p is a variable path x.ap, then sgnlz will call expand, which in turn checks that ap is in the signature of x, and returns p itself, and Ppp.

If p=p 1(p 2), we assume sgnlz(P,π,p 1)=q 1. By induction hypothesis on p 1, Pp 1q 1. We call expand on q 1(p 2). First we call lookup to obtain θ and e. Then we call vp_subs to obtain ρ, so that Pθ safe by induction hypothesis. If e is not a path, we have Pq 1(p 2)↓q 1(p 2) by r-src, and Pp 1(p 2)↓q 1(p 2) by r-app. Let e be the path q i. By induction hypothesis, we have Pqq′ with q′=sgnlz(P,{i}∪π,q). If q′ is a rooted path, by the substitution lemma, we have Pθ(q)↓θ(q′), so that Pq 1(p 2)↓θ(q′) by r-exp. If q′ is a variable path x.ap, by inversion we have apsig P (x). If x∉dom(θ), by the substitution lemma we have Pθ(q)↓x.ap (=ρ(x.ap) since x.ap∉dom(ρ)). Otherwise, by induction hypothesis on vp_subs, we have Pθ(x.ap)↓ρ(x.ap), so that Pθ(q)↓ρ(x.ap) by the substitution lemma. In both cases we conclude that Pq 1(p 2)↓ρ(x.ap) by r-exp.

If p=p 1.m, we prove the property in the same way, replacing occurrences of p 1(p 2) and q 1(p 2) by p 1.m and q 1.m respectively, and r-app by r-dot.

Next we prove the property on vp_subs. This amounts to proving that for each xp in θ, if \(\mathsf{sig\_subs}(P,\pi ,x,p,\textsf {sig}(x)) = \rho \), then Pp:sig P (x) and for all apsig P (x), Pp.apρ(x.ap). Since the latter implies the former, we just need to prove the latter.

If p is a variable path y.ap′, then we just check that y.ap′.ap is valid, and return ρ(x.ap)=y.ap′.ap, so that Py.ap′.apρ(x.ap) by r-vp.

If p is a rooted path, then sgnlz(P,π,p.ap)=q for some q, Pp.apq, and ρ=[x.apq]. As a result, Pp.apρ(x.ap). □

Theorem 2

(Termination)

For any program P, lock π and path p, sgnlz(P,π,p) is terminating.

Proof

Termination is guaranteed since any recursive call sgnlz(P,π,p) is strictly decreasing with respect to a well-founded lexicographic ordering ≺ on pairs (π,p) of a path and a lock, where the two constituent ordering ≺ π on locks and ≺ p on paths are respectively defined as follows.

  • π 1 π π 2 if π 2π 1Labels(P).

  • p 1 p p 1.m for any field name m

  • p 1 p p 1(p 2) for any path p 2

  • p 2.ap p p 1(p 2) for any path p 1 and access path apS, where S is the union of all access signatures of P.

Since Labels(P) and S are finite, both ≺ π and ≺ p are well-founded, thus its lexicographic combination ≺ is well-founded too. □

1.3 A.3 Safe rewriting

Before proving the completeness of semi-ground normalization, we first need to introduce an alternative definition of safety, in terms of termination of a term rewriting system. We will show that the two definitions of safety are equivalent (Proposition 3). Then, we prove that when semi-ground normalization fails for a program, one can build an infinite reduction in this rewriting system, hence the program is unsafe according to the definition in Sect. 6.2. This alternative definition is also interesting for itself, since it gives a more computational view of what safety means, which may be more intuitive.

A way to formalize invalid paths concisely in the framework of path rewriting systems is to transform invalid paths into non-termination. That is, we introduce conditional path rewriting rules Errors P for a program P that cause non-termination whenever invalid paths appear during reduction:

$$\begin{array}{l@{\quad}l} (1)\ \texttt {x}.ap \rightarrow \texttt {x}.ap & \mbox{for any {\texttt {x}} and $ap$ s.t. $ap \notin \textsf {sig}_{P}(\texttt {x})$} \\[3pt] (2)\ \texttt {x}.ap(x) \rightarrow \texttt {x}.ap(x) & \mbox{for any path variable $\texttt {x}$ and access path $ap$}\\[3pt] (3)\ p.m \rightarrow p.m & \mbox{if $P \vdash p \mapsto (\theta , e)$, $e$ not a path, and $P \vdash p.m \not \mapsto $} \\[3pt] (4)\ p(x) \rightarrow p(x) & \mbox{if $P \vdash p \mapsto (\theta , e)$, and $e$ is a structure} \\ \end{array} $$

Here x indicates a path variable appearing in paths to be rewritten, not to be confused with the x used for rewriting rule variables. The first two rule sets cause non-termination when a variable is either decomposed beyond its access signature or applied; both cases break our syntactic restriction. The third one transforms dangling references to non-termination. The fourth one ensures that only functors are applied; otherwise it causes non-termination.

We also need to enforce the safety check on path arguments. For this we modify rewrite rules generated for functors, using the last rule of Errors P to let reduction progress.

$$\begin{array}{l} \mathit{Rules}(p,\lambda (x:S)e)\\[3pt] \quad = \mathit{Rules}(p!(x),e) \cup \{p(x) \rightarrow \textrm{snd}(\textrm{chk}(x.ap_1, \dots, x.ap_n),p!(x)) \\[3pt] \quad \mbox{where $ap_{1}\dots ap_{n}$ are the maximal access paths of $S$, i.e. all the}\\[3pt] \quad \mbox{paths s.t. $ap_{i} \in S \land \forall m\ ap_{i}.m \notin S$.} \end{array} $$

The idea is that p(q).p′ is a path where q has not been checked for safety as argument of p yet, and p!(q).p′ is the same path appearing in a context where the safety of q may have been checked. Actual path expansion occurs in two steps. First we rewrite p(q).p′ into snd(chk(q.ap 1,…,q.ap n ),p!(q)).p′. Here snd and chk are added to evaluation contexts, with an extra rule for snd,

so that one can reduce any of the q.ap i , checking the safety of q as argument of p. Note that depending on which submodules of q are actually accessed in p!(q).p′, rewriting q.ap i may introduce a non-termination behavior that would not appear otherwise. One can then use rule (snd) to discard chk(q.ap 1,…,q.ap n ). Then we are just left with p!(q).p′, which can be rewritten according to the definitions in P once all the applications have been converted. We also add the following rule to the lookup predicate, so that rules (3) and (4) of \(\it Errors_{P}\) will work on both forms of applications.

$$\frac{P \vdash p(q) \mapsto (\theta , e)}{ P \vdash p!(q) \mapsto (\theta , e)} $$

Definition 7

A program P is safe for evaluation if for all paths p appearing as right hand side of an abbreviation binding in P, there is no infinite reduction using Rules P Errors P .

Proposition 3

For any program P, safety (Definition 5) and safety for evaluation (Definition 7) are equivalent.

Proof

We first show that if a program is safe, then it is safe for evaluation. I.e., for any path q, if Pq:{} then there is no infinite reduction starting from q using the rules of \(\it Rules_{P} \cup Errors_{P}\). For a term t of our path rewriting system, containing possibly some snd and chk, we define the pure path of t, noted pp(t), as t where all occurrences of snd were reduced (and, as a result, all occurrences of chk discarded), and all ! were removed. The number of pure applications in t, noted pa(t), is the number of path applications contained in t, after having reduced all the snd, and excluding the !-applications. We define the multiset of implicit paths of t, noted pps(t), by induction on the structure of t:

$$\begin{array}{rcl} \mathrm{pps}(t) & = & \mathrm{pa}(t) \times \Bigl(\bigl\{\mathrm{pp}(t) \bigr\} \cup \bigcup\bigl\{\mathrm{pps}(t') \mid t' \in \mathrm{chks}(t)\bigr\}\Bigr) \\[3pt] \mathrm{chks}(\epsilon ) & = & \emptyset \\[3pt] \mathrm{chks}(\texttt {x}) & = & \emptyset \\[3pt] \mathrm{chks}(t.m) & = & \mathrm{chks}(t) \\[3pt] \mathrm{chks}(t_1(t_2)) & = & \mathrm{chks}(t_1) \cup \mathrm{chks}(t_2) \\[3pt] \multicolumn{3}l{\mathrm{chks}\bigl(\mathrm{snd}\bigl(\mathrm{chk}(\it t_1, \dots, t_n),t\bigr)\bigr) = \{t_1,\dots t_n\} \cup \mathrm{chks}(t)} \end{array} $$

By n×S we mean that we duplicate n times the contents of the multiset S. We define the measure of a term t as the multiset of the sizes of the derivations of Pp:{}, for p in pps(t). We prove that any reduction step tt′ keeps the typability of the paths in pps(t′), and decreases this measure according to the multiset ordering. If the reduction is one of the original ones, then according to lemma 4, each path in pps(t) is either reduced into a corresponding path in pps(t′), with its derivation size reduced, or it remains unchanged, and at least one pure path is reduced. If the new rule p(x)→snd(chk(x.ap 1,…,x.ap n ),p!(x)) is applied, then the number of pure applications of p(q) is reduced by 1, and we replace this p(q) by q.ap 1, …, q.ap n , which were already contained in the derivation of Pp(q):{}, so that they are safe, and the measure decreases. If snd(x,y)→y is applied, then we discard the first argument, which leaves pp(t′) intact, and the measure decreases. Rules (1)–(4) cannot apply, since pp(t) is safe.

Since the multiset ordering is well-founded, this proves that there cannot be infinite reductions.

Conversely, we prove that if there is no infinite reduction using \(\it Rules_{P} \cup Errors_{P}\), then P must be safe. We define the relation pq iff p can be rewritten into a path q 0 such that C[θ(q)]∈pps(q 0) for some path context C and substitution θ. This relation must be antisymmetric on the paths appearing in P (i.e. we never have both pq and qp, otherwise we could easily build an infinite reduction.) As a result ≻ can be topologically extended into a total order on the paths appearing as right hand side of abbreviation bindings in P.

We prove that if there is no infinite reduction starting from p, then Pp:{}, starting with the smallest paths in this topological order (those with no q in P such that pq). We rewrite p using a customized strategy. That is, we basically use a call-by-name strategy (not reducing arguments), with the exception of the arguments of chk which we reduce to normal form before discarding them with snd. Thanks to this strategy, we are able to build our safety derivation straightforwardly. Namely, we obtain the safety of substitutions from the normalization of chk, and then actually apply the original rewriting rule on the non-reduced argument, as does our inference system. Moreover, since we check following a topological order, we can use our substitution lemma to build the third premise of r-exp rule. Other inference rules need just to be inserted as glue, as they perform no actual reduction. □

1.4 A.4 Completeness proof

The following lemmas are used by the completeness proof. The first one proves that postponing substitution is correct.

Lemma 3

(Postponement)

If p is a rooted path, sgnlz(P,π′,p)=q and \(\mathsf{vp\_subs}(P,\pi ,\theta ) = \rho \) with ππ′, then sgnlz(P,π,θ(p))=subs(θ,ρ,q).

Proof

(Coq-checked) By functional induction on sgnlz(P,π′,p). □

Lemma 5

(Idempotence)

If sgnlz(P,π,p)=q, then sgnlz(P,π,q)=q.

Proof

By functional induction, using Lemma 3. □

Theorem 3

(Completeness)

For any program P and path p, if P is safe and Pp:{}, then \(\mathsf {sgnlz}(P, \emptyset, p) \neq \textsf {error}\).

Proof

By Proposition 3, Pp:{} implies that there is no infinite reduction from p using \(\it Rules_{P} \cup Errors_{P}\).

We show by functional induction that sgnlz(P,π,p)=error implies the existence of such an infinite reduction starting from either p or an abbreviation in P, assuming that for each iπ, there are paths p i and q i such that Pp i ↦(id,(q i )i), and reductions \(q_{i} \stackrel {\ast }{\rightarrow }C_{i}[\theta _{i}(p)]\). In case of repeated attempts to expand the same abbreviation, we will use them to build an infinite reduction. Since some recursive calls to sgnlz will be on paths that do not appear in P, we also keep a reduction \(q_{0} \stackrel {\ast }{\rightarrow }C_{0}[p]\), q 0 being either the original p, or the last abbreviation in P we are currently normalizing. This last reduction will be used for errors, producing an infinite reduction with rules of \(\it Errors_{P}\). For the sake of simplicity, we do not distinguish normal applications and !-applications in the paths we reduce. We just assume that where needed we can get the arguments of chk, in order to build an infinite reduction.

We start with π=∅ and q 0=p, so that our only reduction is the 0-step one from q 0 to p.

If p=x or p=ϵ, then sgnlz(P,π,p)=perror.

If p=p 1.m or p=p 1(p 2), then we first try to evaluate sgnlz(P,π,p 1). If it results in an error, then we can reuse our reductions \(q_{i} \stackrel {\ast }{\rightarrow }C_{i}[\theta _{i}(p)]\) (iπ), as C i [θ i (p)] contains θ i (p 1) (e.g. C i [θ i (p)]=C i [θ i (p 1).m] in the first case), and \(q_{0} \stackrel {\ast }{\rightarrow }C_{0}[p]\) since p contains p 1. Using the induction hypothesis we conclude that there is an infinite reduction.

If \(\mathsf {sgnlz}(P, \pi , p_{1}) = p'_{1}\), then we call expand(P,π,p′), with p′ either \(p'_{1}.m\) or \(p'_{1}(p_{2})\), and since by correctness we have a reduction \(p_{1} \stackrel {\ast }{\rightarrow }p'_{1}\), we also have a reduction \(p \stackrel {\ast }{\rightarrow }p'\), and we can complete all reductions \(q_{i} \stackrel {\ast }{\rightarrow }C_{i}[\theta _{i}(p)]~(i\in \pi )\) into reductions \(q_{i} \stackrel {\ast }{\rightarrow }C_{i}[\theta _{i}(p')]\), and \(q_{0} \stackrel {\ast }{\rightarrow }C_{0}[p']\). If p′=x.ap, then to have an error it must be apsig P (x), and we can use a reduction (1) of \(\it Errors_{P}\) to create an infinite reduction \(q_{0}\stackrel {\ast }{\rightarrow }C_{0}[p'] \rightarrow C_{0}[p'] \rightarrow \cdots{}\). If p′ is a rooted path, then we first call lookup(P,p′). If this fails we can use either a reduction (3) or (4) of \(\it Errors_{P}\) to create an infinite reduction. Otherwise, we obtain θ and e.

Then we call \(\mathsf{vp\_subs}(P,\pi ,\theta )\). From the reduction point of view, if \(p'_{j}\) is an argument of p′, then there is a prefix \(p_{j}(p'_{j})\) of p′, and we can find a step \(p_{j}(p'_{j}) \rightarrow \mathrm{snd}(\mathrm{chk}(p'_{j}.ap_{j1},\dots,p'_{j}.ap_{jn_{j}}),p_{j}!(p'_{j}))\) inside the reduction leading to p′, allowing us to check all the required subpaths of the argument \(p'_{j}\). This is also what \(\mathsf{sig\_subs}(P,\pi ,x_{j},p'_{j},\allowbreak \textsf {sig}_{P}(x_{j}))\) does. If \(p'_{j}\) is a variable path x.ap, then it checks for each ap′∈sig P (x j ) whether ap.ap′∈sig P (x). Since all those ap′ are prefixes of some of the ap jk , if we have an error then we can build an infinite reduction starting from \(p'_{j}.ap_{jk}\). If \(p'_{j}\) is a rooted path, then for each ap′∈sig P (x j ), we call \(\mathsf {sgnlz}(P, \pi , p'_{j}.ap')\). If one of them fails, we can construct a context C such that \(p' \stackrel {\ast }{\rightarrow }C[p'_{j}.ap_{jk}]\), so that we can complete all our reductions into \(q_{i} \stackrel {\ast }{\rightarrow }C_{i}[\theta _{i}(C[p'_{j}.ap_{jk}])]~(i \in \pi )\) and \(q_{0} \stackrel {\ast }{\rightarrow }C_{0}[C[p'_{j}.ap_{jk}]]\), and by induction hypothesis we have an infinite reduction starting from q 0.

If \(\mathsf{vp\_subs}(P,\pi ,\theta )\) succeeds, the next step is either to return successfully from expand, which contradicts the presence of an error, or we have e=q i, and we check whether iπ. If iπ, then since p′→θ(q)=θ(q i ), we have a reduction \(q_{i} \stackrel {\ast }{\rightarrow }C_{i}[\theta _{i}(p')] \rightarrow C_{i}[\theta _{i}(\theta (q_{i}))]\), so that we can build an infinite reduction by repeatedly appending it to itself, i.e. \(q_{i} \stackrel {\ast }{\rightarrow }C_{i}[\theta _{i}(\theta (q_{i}))] \stackrel {\ast }{\rightarrow }C_{i}[\theta _{i}(\theta (C_{i}[\theta _{i}(\theta (q_{i}))]))] \stackrel {\ast }{\rightarrow }\cdots{}\).

If iπ, we call sgnlz(P,{i}∪π,q), which must fail. First we need to extend our reductions. We have Pp′↦(θ,q), and \(p' \stackrel {\ast }{\rightarrow } \theta (q)\). We can combine this reduction with our other reductions to obtain \(q_{j}\stackrel {\ast }{\rightarrow }C_{j}[\theta _{j}(\theta (q))]~(j\in \pi )\). Since q is an abbreviation in P, we update q 0 to q, with new reductions \(q_{i} = q \stackrel {\ast }{\rightarrow }q\), and \(q_{0} = q \stackrel {\ast }{\rightarrow }q\). So by induction hypothesis, in case of error we have an infinite reduction starting from one of the q i or q 0. □

Rights and permissions

Reprints and permissions

About this article

Cite this article

Garrigue, J., Nakata, K. Path resolution for nested recursive modules. Higher-Order Symb Comput 24, 207–237 (2011). https://doi.org/10.1007/s10990-012-9083-6

Download citation

  • Published:

  • Issue Date:

  • DOI: https://doi.org/10.1007/s10990-012-9083-6

Keywords

Navigation