Programando en USER RPL
Estructuras iterativas

Mario de Lama   malar@arrakis.es
http://www.arrakis.es/~malar

Regresar

Antes de nada comentar que podemos escribir estas estructuras presionando muy pocas teclas: primero PRG y BRCH. A continuación la tecla deseada pero con desplazamiento izquierdo (primero tecla morada) para las estructuras NEXT o derecho (primero tecla verde) para las STEP.

Las estructuras iterativas, o bucles, se encargan de repetir un determinado código de programa una serie de veces. Hay dos tipos: Definidos e indefinidos. Los bucles definidos llevan asociados una variable contador en la que se especifica el número de veces que ha de repetirse el código. Hay dos tipos de bucles definidos, cada uno de ellos tiene dos variantes dependiendo de si el contador se incrementa de uno en uno o de forma definida por el programador.
Los bucles indefinidos se repiten hasta que una condición establecida se cumple o deja de cumplirse.

Las distintas estructuras iterativas son:

Definidas

Indefinidas Cómo salir de un bucle definido cuando lo deseemos

Bucles anidados


La estructura START ... NEXT se traduce como INICIO ... SIGUIENTE, su sintaxis sería:

'inicio' 'fin' START código a repetir NEXT

En el nivel 2: de la pila pondremos el valor inicial del contador y en 1: el valor final. A continuación se ejecuta el código tras lo que NEXT incrementa en uno el contador interno que crea el sistema operativo de la calculadora y comprueba su valor. Si es menor o igual que 'fin' se ejecuta de nuevo el código, si es mayor no se repite y el programa continúa. El bucle se repetirá 'fin - inicio + 1' veces.

\<< "H" "O" "L" "A"
  1 3
  START
   +
  NEXT
  "A" "M" "I" "G" "O" "/" "A"
  1 6
  START
   +
  NEXT
\>>
Este ejemplo nos deja en 2: la cadena "HOLA" y en 1: "AMIGO/A"

Inicio


La estructura START ... STEP se podría traducir como INICIO ... INCREMENTO, su sintaxis sería:

'inicio' 'fin' START código a repetir 'incremento' STEP

Esta estructura sólo se diferencia de la anterior en que se puede especificar un incremento distinto de 1, que era el único que podíamos tener con la anterior.
El incremento puede ser positivo o negativo (nunca cero ya que el bucle sería infinito), si usamos un algebraico o un nombre de variable como argumento de STEP se evalúa y su resultado es con el que STEP incrementa el contador. En caso de que el incremento sea negativo 'inicio' debe ser mayor que 'fin' deteniéndose el bucle cuando el contador es menor que el valor de 'fin'

\<< "H" "O" "L" "A"
  1 0.2
  START
   + -0.3
  STEP
  "A" "M" "I" "G" "O" "/" "A"
  0 1.12
  START
   + '1-0.7'
  STEP
\>>
El resultado es el mismo que en el caso anterior.

Inicio


FOR ... NEXT tiene la siguiente sintaxis:

'inicio' 'fin' FOR 'contador' código a repetir NEXT

Este bucle tiene la ventaja de que utilizamos una variable local como contador, esto nos permite acceder a él y recuperarlo en la pila o modificarlo. FOR toma el valor inicial y final del contador y además crea la variable local con el nombre que le suministramos delante. NEXT incrementa en 1 el contador y a continuación comprueba su valor volviendo a ejecutar la cláusula si es menor o igual que 'fin'. La variable local se destruye al terminar el bucle.
Es, sin duda alguna, el más utilizado de todos los bucles lo cual no quiere decir que sea el único a utilizar ya que si no tenemos necesidad de acceder al contador es mejor utilizar las estructuras START que son más simples y rápidas al no tener que crear la variable local.

\<< \-> z
  \<<
    FOR n
     z n ^
    NEXT
  \>>
\>>
En la pila debe haber 3 números. El código "\-> z" guarda el valor de 1: en la variable local 'z' dejando en la pila el nivel 2: con el valor de 'inicio' y 1: con 'fin' para que los tome FOR. El bucle calcula distintas potencias de 'z' dependiendo de los valores 'inicio' y 'fin'

Inicio


FOR ... STEP tiene la siguiente sintaxis:

'inicio' 'fin' FOR 'contador' código a repetir 'incremento' STEP

Es la misma estructura anterior con la posibilidad de poder especificar el incremento deseado. Este puede ser también positivo o negativo y tiene todas las demás características que hemos visto en START ... STEP.

\<< 48 57
  FOR x
   x CHR STR\-> SQ 2
  STEP
\>>
Este ejemplo calcula el cuadrado de 0, 2, 4, 6 y 8

Inicio


Podríamos traducir DO ... UNTIL ... END como HAZ ... HASTA que esta cláusula sea cierta FIN, su sintaxis sería:

DO código a repetir UNTIL condicional END

En primer lugar se ejecuta el código que hay entre DO y UNTIL tras lo que se inicia la condición o test. Estos test no sólo pueden ser tales sino cualquier algebraico u operación que devuelva un resultado a la pila. Sea cual sea el test se entiende que el resultado es verdadero si en 1: hay un número distinto de 0. END evalúa cualquier algebraico o un nombre de variable que le demos como argumento.
Si el resultado del test es falso el bucle vuelve a ejecutarse, si es verdadero el programa continúa.
Esta estructura se utiliza cuando no sepamos las veces que ha de ejecutarse un código pero si sabemos que ha de realizarse, al menos, una vez.

\<<
  IF DEPTH 0 \=/
  THEN
    0 -> pila
    \<<
      DO
        'pila' STO
      UNTIL
        DEPTH 0 == pila TYPE 8 == OR
      END
      IF pila TYPE 8 ==
      THEN
        pila "Es un programa"
      ELSE
        "No hay programas"
      END
    \>>
  END
\>>
El ejemplo anterior comprueba en primer lugar si hay algún objeto en la pila, si no lo hay termina. Si lo hay, primero crea una variable local (pila) y a continuación empieza una estructura DO ... UNTIL que guarda en la variable local el contenido de 1: para seguidamente comprobar si queda algo en la pila o bien la variable contiene un programa. Si se cumple cualquiera de las dos condiciones el bucle termina, en caso contrario sigue ejecutándose hasta hacerlo. Finalmente comprobamos si en la variable hay un programa colocando una cadena en la pila que nos lo indique.
Este programa se puede hacer también con un bucle definido pero lo complicaríamos mucho ya que no hay forma de salir de ellos sino es produciendo un error que capturemos fuera del bucle:
\<<
  IF DEPTH 0 \=/
  THEN
    0 \-> pila
    \<<
       IFERR DEPTH 1 SWAP
         START
           'pila' STO
           IF 'pila' VTYPE 8 ==
           THEN
             "" DOERR
           END
         NEXT
       THEN
         pila "Es un programa"
       ELSE
         "No hay programas"
       END
    \>>
  END
\>>

Inicio


Podríamos traducir WHILE ... REPEAT ... END como MIENTRAS esta cláusula sea cierta REPITE ... FIN, su sintaxis sería:

WHILE condicional REPEAT código a repetir END

En esta ocasión el test lo valora REPEAT: si el resultado es verdadero ejecuta el código, en caso contrario el programa continúa tras END. Vemos, por tanto, que el código puede no ejecutarse nunca mientras en la anterior cláusula siempre se ejecutaba una vez por lo menos. Otra notable diferencia es que ahora se ejecuta el código si el resultado del test es verdadero.

\<<
  IF DEPTH 0 \=/
  THEN
    \-> pila
    \<<
      WHILE
        DEPTH 0 \=/ pila TYPE 8 \=/ AND
      REPEAT
        'pila' STO
      END
      IF pila TYPE 8 ==
      THEN
        pila "Es un programa"
      ELSE
        "No hay programas"
      END
    \>>
  END
\>>
Vemos que el resultado de este programa es el mismo del anterior. ¿Cuál usar entonces? El que nos parezca más fácil en cada momento. El test de este último es más rebuscado que el del anterior y en general el programa es más confuso. En este caso yo elegiría la estructura DO ... UNTIL.

Inicio


Podemos incluir un bucle dentro de otro, a esto se le llama anidar bucles. Podemos anidar tantos como queramos teniendo una serie de precauciones:
  1. Cada bucle anidado ha de estar enteramente dentro del otro.
  2. Cada bucle ha de tener su propio nombre de contador.
  3. Es mejor no usar nombres de contador como 'i', 'e', ... que pueden ser interpretados en ciertas circunstancias como números. Esta precaución se extiende a todos los nombres de variables.
\<<
  IF DUP TYPE 3 == OVER SIZE SIZE 1 > AND
  THEN
    DUP SIZE EVAL \-> n
    \<<
      1 SWAP
      FOR fila
        1 n
        FOR columna
          DUP fila columna 2 \->LIST GET
          IF columna 1 ==
          THEN 2 *
          ELSE 2 /
          END
          fila columna 2 \->LIST SWAP PUT
        NEXT
      NEXT
    \>>
  END
\>>
Este ejemplo nos permite multiplicar la primera columna de cualquier matriz por 2, y dividir las demás columnas por 2.

Inicio