Cite

This course has no released version yet: the text at this address may change. Cite a released version when one exists.

/courses/models-of-computation/while-programs
@misc{models-of-computation-while-programs,
  title = {{LOOP and WHILE programs}},
  howpublished = {Lesson 9 of \emph{Models of computation}, Computability Theory course notes},
  url = {/courses/models-of-computation/while-programs},
  note = {Unreleased working version}
}

To cite a single statement, use the # link that appears next to its heading.

Lesson 9 of 13

LOOP and WHILE programs

Structured programs with bounded and unbounded loops. The LOOP-computable functions are the primitive recursive functions, and the WHILE-computable functions are the partial recursive functions.

45 min6 questions
Models of computation · lesson 9 of 13
  1. Algorithms and partial functions
  2. Turing machines
  3. Programming Turing machines
  4. Register machines
  5. Primitive recursive functions
  6. Coding finite sequences
  7. The Ackermann function
  8. Minimization and partial recursive functions
  9. LOOP and WHILE programs
  10. The λ-calculus
  11. Computing with λ-terms
  12. Equivalence of the models
  13. The Church–Turing thesis

Register machines use jumps. Modern programming languages instead use structured control flow: sequences, conditionals and loops. We study two minimal structured languages, introduced by Meyer and Ritchie (1967): LOOP, whose only loop is a for loop executed a number of times fixed on entry, and WHILE, which adds a while loop. The distinction between the two loops corresponds exactly to the distinction between primitive recursion and minimization.

9.1 Syntax and semantics

Programs manipulate variables X0,X1,X2,…X_0, X_1, X_2, \dots, each holding a natural number.

Definition 9.1.#

The WHILE programs are generated by the grammar

P ::= Xi:=0 ∣ Xi:=Xi+1 ∣ Xi:=Xj ∣ P;P∣ LOOP Xi DO P END∣ WHILE Xi≠0 DO P END\begin{aligned} P \ ::=\ & X_i \mathbin{:=} 0 \ \mid\ X_i \mathbin{:=} X_i + 1 \ \mid\ X_i \mathbin{:=} X_j \ \mid\ P ; P \\ \mid\ & \mathtt{LOOP}\ X_i\ \mathtt{DO}\ P\ \mathtt{END} \\ \mid\ & \mathtt{WHILE}\ X_i \neq 0\ \mathtt{DO}\ P\ \mathtt{END} \end{aligned}

The LOOP programs are the WHILE programs which contain no WHILE\mathtt{WHILE} instruction.

A state is a function σ:N→N\sigma : \nat \to \nat with σ(i)=0\sigma(i) = 0 for all but finitely many ii; σ(i)\sigma(i) is the value of XiX_i. A program denotes a partial function on states.

Definition 9.2.#

The semantics [ ⁣[P] ⁣][\![P]\!] of a program PP is the partial function from states to states defined by induction on PP:

  • [ ⁣[Xi:=0] ⁣](σ)=σ[i↦0][\![X_i \mathbin{:=} 0]\!](\sigma) = \sigma[i \mapsto 0], [ ⁣[Xi:=Xi+1] ⁣](σ)=σ[i↦σ(i)+1][\![X_i \mathbin{:=} X_i + 1]\!](\sigma) = \sigma[i \mapsto \sigma(i) + 1], [ ⁣[Xi:=Xj] ⁣](σ)=σ[i↦σ(j)][\![X_i \mathbin{:=} X_j]\!](\sigma) = \sigma[i \mapsto \sigma(j)];
  • [ ⁣[P;Q] ⁣](σ)≃[ ⁣[Q] ⁣]([ ⁣[P] ⁣](σ))[\![P ; Q]\!](\sigma) \simeq [\![Q]\!]([\![P]\!](\sigma));
  • [ ⁣[LOOP Xi DO P END] ⁣](σ)≃[ ⁣[P] ⁣]n(σ)[\![\mathtt{LOOP}\ X_i\ \mathtt{DO}\ P\ \mathtt{END}]\!](\sigma) \simeq [\![P]\!]^{n}(\sigma) where n=σ(i)n = \sigma(i) and [ ⁣[P] ⁣]n[\![P]\!]^n is the nn-fold iterate of [ ⁣[P] ⁣][\![P]\!];
  • [ ⁣[WHILE Xi≠0 DO P END] ⁣](σ)≃[ ⁣[P] ⁣]n(σ)[\![\mathtt{WHILE}\ X_i \neq 0\ \mathtt{DO}\ P\ \mathtt{END}]\!](\sigma) \simeq [\![P]\!]^{n}(\sigma) for the least nn such that [ ⁣[P] ⁣]n(σ) ⁣ ⁣↓[\![P]\!]^n(\sigma)\converge and [ ⁣[P] ⁣]n(σ)(i)=0[\![P]\!]^n(\sigma)(i) = 0, provided [ ⁣[P] ⁣]m(σ) ⁣ ⁣↓[\![P]\!]^m(\sigma)\converge with [ ⁣[P] ⁣]m(σ)(i)≠0[\![P]\!]^m(\sigma)(i) \neq 0 for every m<nm < n; it is undefined if there is no such nn.

In a LOOP\mathtt{LOOP} instruction, the number of iterations is the value of XiX_i on entry: modifying XiX_i inside the body does not change it. In a WHILE\mathtt{WHILE} instruction, the condition is re-evaluated before each iteration.

Definition 9.3.#

A program PP computes the partial function f:Nk⇀Nf : \nat^k \rightharpoonup \nat defined by f(x⃗)≃[ ⁣[P] ⁣](σx⃗)(0)f(\vec x) \simeq [\![P]\!](\sigma_{\vec x})(0), where σx⃗(i)=xi\sigma_{\vec x}(i) = x_i for 1≤i≤k1 \leq i \leq k and σx⃗(i)=0\sigma_{\vec x}(i) = 0 otherwise. In words: the input is placed in X1,…,XkX_1, \dots, X_k, all other variables are 00, and the output is read in X0X_0. A function is LOOP-computable (resp. WHILE-computable) if it is computed by a LOOP (resp. WHILE) program.

Proposition 9.4.#

For every LOOP program PP, [ ⁣[P] ⁣][\![P]\!] is total. Hence every LOOP-computable function is total.

Proof of Proposition 9.4.

By induction on PP: assignments are total, composition of total functions is total, and a finite iterate of a total function is total.

9.2 Programming in LOOP

We use abbreviations, each of which stands for a LOOP program using fresh auxiliary variables.

  • Addition X0:=X1+X2X_0 \mathbin{:=} X_1 + X_2:  X0:=X1; LOOP X2 DO X0:=X0+1 END\ X_0 \mathbin{:=} X_1 ;\ \mathtt{LOOP}\ X_2\ \mathtt{DO}\ X_0 \mathbin{:=} X_0 + 1\ \mathtt{END}.
  • Predecessor X0:=X1−˙1X_0 \mathbin{:=} X_1 \dotminus 1:  X0:=0; X2:=0; LOOP X1 DO X0:=X2; X2:=X2+1 END\ X_0 \mathbin{:=} 0 ;\ X_2 \mathbin{:=} 0 ;\ \mathtt{LOOP}\ X_1\ \mathtt{DO}\ X_0 \mathbin{:=} X_2 ;\ X_2 \mathbin{:=} X_2 + 1\ \mathtt{END}. After n≥1n \geq 1 iterations, X2=nX_2 = n and X0=n−1X_0 = n - 1.
  • Conditional IF Xi≠0 THEN P END\mathtt{IF}\ X_i \neq 0\ \mathtt{THEN}\ P\ \mathtt{END}: compute Y=sg(Xi)Y = \mathrm{sg}(X_i) in a fresh variable YY (by a loop setting YY to 11 at each iteration), then LOOP Y DO P END\mathtt{LOOP}\ Y\ \mathtt{DO}\ P\ \mathtt{END}.

9.3 LOOP programs compute the primitive recursive functions

Theorem 9.5 (Meyer–Ritchie).#

A function is LOOP-computable if and only if it is primitive recursive.

We prove the two directions separately. In the first direction, programs for subfunctions are combined using fresh auxiliary variables, so that they do not interfere with each other.

Proof of Theorem 9.5.

Primitive recursive ⇒ LOOP. We show by induction on a derivation of f:Nk→Nf : \nat^k \to \nat that for all distinct indices o,i1,…,iko, i_1, \dots, i_k there is a LOOP program, written Xo:=f(Xi1,…,Xik)X_o \mathbin{:=} f(X_{i_1}, \dots, X_{i_k}), which, started in any state σ\sigma, sets XoX_o to f(σ(i1),…,σ(ik))f(\sigma(i_1), \dots, \sigma(i_k)) and modifies no variable other than XoX_o and a finite set of auxiliary variables, which may be chosen disjoint from any given finite set of indices.

  • Basic functions: Xo:=0X_o \mathbin{:=} 0, then Xo:=Xi1;Xo:=Xo+1X_o \mathbin{:=} X_{i_1} ; X_o \mathbin{:=} X_o + 1, and Xo:=XijX_o \mathbin{:=} X_{i_j}.
  • Composition f=h∘(g1,…,gm)f = h \circ (g_1, \dots, g_m): choose fresh Y1,…,YmY_1, \dots, Y_m, and run Y1:=g1(X⃗);… ;Ym:=gm(X⃗);Xo:=h(Y1,…,Ym)Y_1 \mathbin{:=} g_1(\vec X) ; \dots ; Y_m \mathbin{:=} g_m(\vec X) ; X_o \mathbin{:=} h(Y_1, \dots, Y_m), with auxiliary variables of each subprogram chosen disjoint from XoX_o, X⃗\vec X, Y⃗\vec Y.
  • Primitive recursion, f(x⃗,0)=g(x⃗)f(\vec x, 0) = g(\vec x), f(x⃗,y+1)=h(x⃗,y,f(x⃗,y))f(\vec x, y + 1) = h(\vec x, y, f(\vec x, y)): with fresh CC, VV, NN, run
V:=g(X⃗); C:=0; N:=Xik+1;LOOP N DOV:=h(X⃗,C,V); C:=C+1END; Xo:=V.\begin{aligned} & V \mathbin{:=} g(\vec X) ;\ C \mathbin{:=} 0 ;\ N \mathbin{:=} X_{i_{k+1}} ; \\ & \mathtt{LOOP}\ N\ \mathtt{DO} \\ & \qquad V \mathbin{:=} h(\vec X, C, V) ;\ C \mathbin{:=} C + 1 \\ & \mathtt{END} ;\ X_o \mathbin{:=} V. \end{aligned}

By induction on the number of iterations, after jj iterations C=jC = j and V=f(x⃗,j)V = f(\vec x, j). For k=0k = 0, where gg is a constant aa, the first assignment is V:=0V \mathbin{:=} 0 followed by aa instructions V:=V+1V \mathbin{:=} V + 1. The subprograms never rely on the initial values of their auxiliary variables, since each of these is assigned before being read; this is why they can be run repeatedly inside the loop. (Writing V:=h(X⃗,C,V)V \mathbin{:=} h(\vec X, C, V) is allowed: the program for hh reads VV and writes into a fresh variable, which is then copied into VV.)

The function ff itself is computed by X0:=f(X1,…,Xk)X_0 \mathbin{:=} f(X_1, \dots, X_k), whose auxiliary variables are chosen distinct from X0,…,XkX_0, \dots, X_k.

LOOP ⇒ primitive recursive. Let PP be a LOOP program computing f:Nk→Nf : \nat^k \to \nat, and let mm be larger than kk and than the indices of all variables occurring in PP. Variables of index ≥m\geq m are not modified by PP and do not influence its effect on the others. We code the relevant part of a state by the sequence code s=[σ(0),…,σ(m−1)]s = [\sigma(0), \dots, \sigma(m-1)] of the lesson Coding finite sequences, and define FP(s)F_P(s) as the code of the state reached from ss. We show by induction on subprograms QQ of PP that FQF_Q is primitive recursive (on codes of length mm):

  • assignments: FXi:=0(s)=set(s,i,0)F_{X_i := 0}(s) = \mathrm{set}(s, i, 0), FXi:=Xi+1(s)=set(s,i,(s)i′+1)F_{X_i := X_i + 1}(s) = \mathrm{set}(s, i, (s)'_i + 1), FXi:=Xj(s)=set(s,i,(s)j′)F_{X_i := X_j}(s) = \mathrm{set}(s, i, (s)'_j);
  • sequence: FQ;R=FR∘FQF_{Q ; R} = F_R \circ F_Q;
  • loop: FLOOP Xi DO Q END(s)=G(s,(s)i′)F_{\mathtt{LOOP}\ X_i\ \mathtt{DO}\ Q\ \mathtt{END}}(s) = G(s, (s)'_i) where G(s,0)=sG(s, 0) = s and G(s,n+1)=FQ(G(s,n))G(s, n + 1) = F_Q(G(s, n)), a primitive recursion.

Finally f(x⃗)=(FP([0,x1,…,xk,0,…,0]))0′f(\vec x) = \big(F_P([0, x_1, \dots, x_k, 0, \dots, 0])\big)'_0, with mm entries in the code, is primitive recursive.

9.4 WHILE programs compute the partial recursive functions

Theorem 9.6.#

A partial function is WHILE-computable if and only if it is partial recursive.

Proof of Theorem 9.6.

Partial recursive ⇒ WHILE. We extend the first part of the previous proof. The constructions for composition and primitive recursion are unchanged; with partial functions, the program simply does not terminate when one of the subprograms does not, which matches the conventions for partial functions. For minimization, f(x⃗)≃μy [g(x⃗,y)=0]f(\vec x) \simeq \mu y\, [g(\vec x, y) = 0], with fresh YY and TT:

Y:=0; T:=g(X⃗,Y);WHILE T≠0 DOY:=Y+1; T:=g(X⃗,Y)END; Xo:=Y.\begin{aligned} & Y \mathbin{:=} 0 ;\ T \mathbin{:=} g(\vec X, Y) ; \\ & \mathtt{WHILE}\ T \neq 0\ \mathtt{DO} \\ & \qquad Y \mathbin{:=} Y + 1 ;\ T \mathbin{:=} g(\vec X, Y) \\ & \mathtt{END} ;\ X_o \mathbin{:=} Y. \end{aligned}

This program evaluates g(x⃗,0),g(x⃗,1),…g(\vec x, 0), g(\vec x, 1), \dots in order and stops at the first zero; it does not terminate if one of these computations does not, or if there is no zero. This is exactly the definition of minimization.

WHILE ⇒ partial recursive. As in the LOOP case, define for each subprogram QQ the partial function FQF_Q on codes of states, and show by induction that it is partial recursive. Assignments, sequences and LOOP\mathtt{LOOP} instructions are handled as before, now with partial functions (the iteration GG is defined by primitive recursion for partial functions). For W=WHILE Xi≠0 DO Q ENDW = \mathtt{WHILE}\ X_i \neq 0\ \mathtt{DO}\ Q\ \mathtt{END}, let G(s,0)≃sG(s, 0) \simeq s and G(s,n+1)≃FQ(G(s,n))G(s, n + 1) \simeq F_Q(G(s, n)). Then

FW(s)≃G(s, μn [ (G(s,n))i′=0 ]).F_W(s) \simeq G\big(s,\ \mu n\, [\,(G(s, n))'_i = 0\,]\big).

By the definition of minimization, the search succeeds at nn exactly when G(s,m)G(s, m) is defined with Xi≠0X_i \neq 0 for m<nm < n, and G(s,n)G(s, n) is defined with Xi=0X_i = 0: this matches the semantics of the WHILE\mathtt{WHILE} instruction.

Corollary 9.7.#

Every WHILE program is equivalent, for the computation of functions, to a WHILE program containing a single WHILE\mathtt{WHILE} instruction.

Proof of Corollary 9.7.

The function computed by the program is partial recursive. By Kleene’s normal form (Theorem 8.6, proved in the lesson Equivalence of the models without using this corollary), it can be written U(μs Tk(e,x⃗,s))U(\mu s\, T_k(e, \vec x, s)) with UU and TkT_k primitive recursive. By Theorem 9.5, UU and χTk\chi_{T_k} are computed by LOOP programs, and the construction above for the minimization uses one WHILE\mathtt{WHILE} instruction.

This is related to the Böhm–Jacopini theorem (1966): every flow diagram can be rewritten using only sequencing, conditionals and while loops, at the cost of auxiliary variables. The form in which a single while loop suffices is the “folk” version of this theorem discussed by Harel (1980).

9.5 WHILE programs and register machines

Proposition 9.8.#

Every WHILE-computable partial function is URM-computable.

Proof of Proposition 9.8.

Let PP compute f:Nk⇀Nf : \nat^k \rightharpoonup \nat, and let mm be larger than kk and than the indices of all variables of PP. The variable XiX_i, for i<mi < m, is represented by the register Ri+2R_{i+2}; the register R1R_1 is kept equal to 00 and serves for unconditional jumps J(1,1,q)J(1, 1, q) and for tests against 00. Each occurrence of a LOOP\mathtt{LOOP} instruction in PP receives two registers Ra,RbR_a, R_b of its own, with indices larger than m+1m + 1. For each subprogram QQ of PP we define a URM program Q∗Q^* in standard form, by induction on QQ; let tt denote the length of the translation of the body.

  • (Xi:=0)∗=Z(i+2)(X_i \mathbin{:=} 0)^* = Z(i+2), (Xi:=Xi+1)∗=S(i+2)(X_i \mathbin{:=} X_i + 1)^* = S(i+2), (Xi:=Xj)∗=T(j+2,i+2)(X_i \mathbin{:=} X_j)^* = T(j+2, i+2).
  • (Q;Q′)∗(Q ; Q')^* is the concatenation Q∗Q′∗Q^* Q'^* of Definition 4.7.
  • (WHILE Xi≠0 DO Q END)∗(\mathtt{WHILE}\ X_i \neq 0\ \mathtt{DO}\ Q\ \mathtt{END})^* is J(i+2,1,t+3)J(i+2, 1, t+3), followed by Q∗Q^* with all jump targets increased by 11, followed by J(1,1,1)J(1, 1, 1).
  • (LOOP Xi DO Q END)∗(\mathtt{LOOP}\ X_i\ \mathtt{DO}\ Q\ \mathtt{END})^*, with the registers Ra,RbR_a, R_b of this occurrence, is T(i+2,a)T(i+2, a), Z(b)Z(b), J(a,b,t+6)J(a, b, t+6), followed by Q∗Q^* with all jump targets increased by 33, followed by S(b)S(b), J(1,1,3)J(1, 1, 3).

In each case the jump targets are at most the length plus one, so Q∗Q^* is in standard form. We show by induction on QQ: if Q∗Q^* is started at its first instruction in a register state rr with r(1)=0r(1) = 0 and r(i+2)=σ(i)r(i+2) = \sigma(i) for all i<mi < m, then Q∗Q^* halts if and only if [ ⁣[Q] ⁣](σ) ⁣ ⁣↓[\![Q]\!](\sigma)\converge, and in that case it halts in a state r′r' with r′(1)=0r'(1) = 0 and r′(i+2)=[ ⁣[Q] ⁣](σ)(i)r'(i+2) = [\![Q]\!](\sigma)(i) for all i<mi < m. Assignments are immediate, and sequences follow from Lemma 4.8. For a WHILE\mathtt{WHILE} instruction, by induction on nn, the program reaches its first instruction for the (n+1)(n+1)-th time if and only if [ ⁣[Q] ⁣]n(σ) ⁣ ⁣↓[\![Q]\!]^n(\sigma)\converge and [ ⁣[Q] ⁣]j(σ)(i)≠0[\![Q]\!]^j(\sigma)(i) \neq 0 for all j<nj < n, and then the registers represent [ ⁣[Q] ⁣]n(σ)[\![Q]\!]^n(\sigma); since R1=0R_1 = 0, the first jump exits exactly when the represented value of XiX_i is 00, as in Definition 9.2. For a LOOP\mathtt{LOOP} instruction, RaR_a holds the value of XiX_i on entry and is not modified by Q∗Q^*, which only uses the registers of the occurrences inside QQ; by induction on jj, the test J(a,b,⋅)J(a, b, \cdot) is reached for the (j+1)(j+1)-th time with Rb=jR_b = j and the registers representing [ ⁣[Q] ⁣]j(σ)[\![Q]\!]^j(\sigma), so the program exits after σ(i)\sigma(i) iterations.

The program for ff consists of T(k,k+2),T(k−1,k+1),…,T(1,3)T(k, k+2), T(k-1, k+1), \dots, T(1, 3), which move the input to the registers of X1,…,XkX_1, \dots, X_k (in decreasing order, so that no input is overwritten before it is copied), then Z(1)Z(1), Z(2)Z(2), then P∗P^*, then T(2,1)T(2, 1). After the first part, R1=0R_1 = 0 and Ri+2R_{i+2} holds σx⃗(i)\sigma_{\vec x}(i) for every i<mi < m, and the registers of the LOOP\mathtt{LOOP} occurrences hold 00 (they are not used before being set anyway). By the claim, the program halts if and only if f(x⃗) ⁣ ⁣↓f(\vec x)\converge, and then R1R_1 contains [ ⁣[P] ⁣](σx⃗)(0)=f(x⃗)[\![P]\!](\sigma_{\vec x})(0) = f(\vec x).

9.6 Exercises

Exercise 9.9 ★.

Write LOOP programs computing x⋅yx \cdot y, xyx^y, and sg(x)\mathrm{sg}(x).

Solution

x⋅yx \cdot y: X0:=0; LOOP X2 DO LOOP X1 DO X0:=X0+1 END ENDX_0 \mathbin{:=} 0 ;\ \mathtt{LOOP}\ X_2\ \mathtt{DO}\ \mathtt{LOOP}\ X_1\ \mathtt{DO}\ X_0 \mathbin{:=} X_0 + 1\ \mathtt{END}\ \mathtt{END}.

xyx^y: X0:=0;X0:=X0+1; LOOP X2 DO Y:=0; LOOP X1 DO LOOP X0 DO Y:=Y+1 END END; X0:=Y ENDX_0 \mathbin{:=} 0 ; X_0 \mathbin{:=} X_0 + 1 ;\ \mathtt{LOOP}\ X_2\ \mathtt{DO}\ Y \mathbin{:=} 0 ;\ \mathtt{LOOP}\ X_1\ \mathtt{DO}\ \mathtt{LOOP}\ X_0\ \mathtt{DO}\ Y \mathbin{:=} Y + 1\ \mathtt{END}\ \mathtt{END} ;\ X_0 \mathbin{:=} Y\ \mathtt{END} (each round multiplies X0X_0 by xx).

sg(x)\mathrm{sg}(x): X0:=0; LOOP X1 DO X0:=0; X0:=X0+1 ENDX_0 \mathbin{:=} 0 ;\ \mathtt{LOOP}\ X_1\ \mathtt{DO}\ X_0 \mathbin{:=} 0 ;\ X_0 \mathbin{:=} X_0 + 1\ \mathtt{END}.

Exercise 9.10 ★★.

Show that the functions computed by LOOP programs of nesting depth at most 11 (no LOOP\mathtt{LOOP} inside a LOOP\mathtt{LOOP}) are bounded by linear functions: for each such program computing ff there are a,ba, b with f(x⃗)≤a⋅∣x⃗∣+bf(\vec x) \leq a \cdot |\vec x| + b. Deduce that multiplication requires nesting depth at least 22.

Solution

Consider a state σ\sigma and let M=max⁡iσ(i)M = \max_i \sigma(i). Each assignment increases the maximum of the values by at most 11. A loop-free program with cc instructions therefore maps a state of maximum MM to one of maximum at most M+cM + c. A loop LOOP Xi DO Q END\mathtt{LOOP}\ X_i\ \mathtt{DO}\ Q\ \mathtt{END} with loop-free QQ, entered in a state of maximum M′M', runs at most M′M' times, so the maximum becomes at most M′+cM′M' + cM'. A sequence of ℓ\ell such instructions multiplies the maximum by at most a constant and adds a constant. Hence f(x⃗)≤a∣x⃗∣+bf(\vec x) \leq a |\vec x| + b. Multiplication is not linearly bounded (x⋅xx \cdot x), so it needs nested loops. (Meyer and Ritchie studied the classes Ln\mathcal{L}_n of functions computed by LOOP programs of nesting depth at most nn. For n≥2n \geq 2, Ln\mathcal{L}_n is the level En+1\mathcal{E}^{n+1} of the Grzegorczyk hierarchy, which stratifies the primitive recursive functions by growth rate.)

Exercise 9.11 ★★.

Show directly, without using partial recursive functions, that every URM-computable partial function is WHILE-computable, by a WHILE program with a single WHILE\mathtt{WHILE} instruction. (The converse is Proposition 9.8.)

Solution

Let I1,…,IsI_1, \dots, I_s compute f:Nk⇀Nf : \nat^k \rightharpoonup \nat, and let ρ\rho be the largest of kk and the register indices of the program. Represent RnR_n by XnX_n for 1≤n≤ρ1 \leq n \leq \rho, and use fresh variables PC\mathrm{PC} (the index of the next instruction) and HH. The program is: PC:=1\mathrm{PC} \mathbin{:=} 1; H:=χ≤(PC,s)H \mathbin{:=} \chi_{\leq}(\mathrm{PC}, s); WHILE H≠0 DO B END\mathtt{WHILE}\ H \neq 0\ \mathtt{DO}\ B\ \mathtt{END}; X0:=X1X_0 \mathbin{:=} X_1. The body BB executes the instruction of index PC\mathrm{PC} and updates PC\mathrm{PC}: it first copies PC\mathrm{PC} into a fresh variable PC′\mathrm{PC}', then performs a sequence of ss conditionals “if PC′=j\mathrm{PC}' = j then execute IjI_j”, where Z(n)Z(n), S(n)S(n), T(m,n)T(m, n) become Xn:=0X_n \mathbin{:=} 0, Xn:=Xn+1X_n \mathbin{:=} X_n + 1, Xn:=XmX_n \mathbin{:=} X_m followed by PC:=PC+1\mathrm{PC} \mathbin{:=} \mathrm{PC} + 1, and J(m,n,q)J(m, n, q) sets PC\mathrm{PC} to qq if Xm=XnX_m = X_n and to j+1j + 1 otherwise. Since the conditionals test PC′\mathrm{PC}', which is not modified, exactly one of them applies in each pass (when H≠0H \neq 0, 1≤PC≤s1 \leq \mathrm{PC} \leq s). At the end of BB, H:=χ≤(PC,s)H \mathbin{:=} \chi_{\leq}(\mathrm{PC}, s). Equality tests, χ≤\chi_\leq and the conditionals are LOOP-definable, by Theorem 9.5 and the conditional of the section on programming in LOOP. By induction on the number of steps, after nn passes through BB the variables PC,X1,…,Xρ\mathrm{PC}, X_1, \dots, X_\rho hold the configuration of the URM after nn steps, so the loop terminates exactly when the URM halts, with f(x⃗)f(\vec x) in X1X_1.

9.7 Notes and references

LOOP programs and the characterization of the primitive recursive functions are due to Meyer and Ritchie, who also related the nesting depth of loops to the Grzegorczyk hierarchy. The elimination of jumps in favor of structured control flow is the subject of the Böhm–Jacopini theorem; Harel discusses its folk versions and their history.

  • A. R. Meyer, D. M. Ritchie, The complexity of loop programs, Proceedings of the 22nd ACM National Conference (1967), 465–469.
  • C. Böhm, G. Jacopini, Flow diagrams, Turing machines and languages with only two formation rules, Communications of the ACM 9 (1966), 366–371.
  • D. Harel, On folk theorems, Communications of the ACM 23 (1980), 379–389.