Fundamentos de programación con Módula-2 (20)

Tema 9
Tipos Definidos:
Enumeración y Conjuntos

 

Después de haber sido introducidas todas las estructuras fundamentales para la construcción de programas, ahora se pasa a estudiar las estructuras de datos. En este Tema se indican las primeras formas en que el programador puede definir sus propios tipos de datos.

En primer lugar se estudian los tipos escalares simples definidos por enumeración y cómo se utilizan. Como caso especial de tipo enumerado ya predefinido se hace especial hincapié en el tipo BOOLEAN, precisando su importancia dentro de la programación. A continuación se estudia la estructura conjunto y se muestra la diferencia que existe entre los conjuntos en Modula-2 y el concepto matemático de conjunto.

Para finalizar, se presentan varios ejemplos que emplean los tipos introducidos y muestran las posibilidades que ofrecen.

9.1 Definición de tipos

Una de las ventajas fundamentales de los lenguajes de alto nivel es la posibilidad que ofrecen al programador de definir sus propios tipos de datos. Los tipos predefinidos: INTEGER, CARDINAL, CHAR y REAL, ya presentados en el Tema 2, nos han permitido la elaboración de programas para la realización de cálculos o el manejo de caracteres. Sin embargo, si se trata de realizar un programa para jugar al ajedrez resulta mucho más adecuado utilizar datos que representen a los peones, caballos, torres, alfiles, reyes y reinas del tablero. Razonamientos similares se pueden hacer si se quieren realizar programas que manejen días de la semana, deportes, colores, alimentos, etc.

Mediante la definición de tipos de datos por el programador se consigue que cada información que maneja el computador tenga su sentido específico. El tipo establece los posibles valores que puede tomar ese dato. Además, al igual que sucedía con los tipos predefinidos, a cada nuevo tipo que se define se asocian un conjunto de operaciones que se pueden realizar con él. Por tanto, la definición de tipos supone crear un nuevo nivel de abstracción dentro del programa.

En Modula-2 la declaración de los tipos se realiza, junto a la declaración de las constantes y variables, dentro de la Parte_declarativa de cualquier Bloque, en el programa principal o en cualquiera de sus procedimientos o funciones. Esta declaración se inicia con la palabra clave TYPE. Por ejemplo:

TYPE
   TipoEdad = INTEGER;
   TipoSexo = CHAR;

Cada tipo se define mediante un nombre o identificador seguido del símbolo igual (=), y a continuación la descripción concreta del tipo que se quiere definir. Esta última parte de la declaración es el objeto de los apartados siguientes de este Tema. Las diferentes definiciones de tipos se separan mediante punto y coma (;).

En las declaraciones anteriores se definen nuevos tipos, haciéndolos equivalentes o sinónimos de otros tipos ya definidos (en este caso, predefinidos). Quizá en estos ejemplos la declaración de tipo no cubre todos los objetivos señalados anteriormente, pues no establece ninguna especificidad. Esto es, convendría establecer que la edad no puede ser negativa ni superior a un valor determinado o que el sexo sólo puede tomar determinados valores. En todo caso es importante señalar que la definición de un nuevo tipo puede utilizar (y normalmente utiliza) otros tipos ya definidos.

La definición de tipos es solamente una declaración de los esquemas de datos que se necesitan para organizar la información de un programa. Para almacenar información es necesario declarar y utilizar variables de los correspondientes tipos, de la misma forma que se hace con los tipos predefinidos.

Por ejemplo, se podrían usar los tipos sinónimos anteriores en la forma:

VAR edad1, edad2: TipoEdad;
        sexo: TipoSexo;
. . . .
edad2 := edad1 + 1;
sexo := "V";
. . . .

De manera formal, la sintaxis y ubicación de la declaración de tipos dentro de la Parte_declarativa del Bloque es la siguiente:

Bloque ::= Parte_declarativa Parte_ejecutiva END
Parte_declarativa ::= { Declaración }
Declaración ::= Declaración_de_constantes |
                       Declaración_de_tipos |
                       Declaración_de_variables |
                       Declaración_subprograma
Declaración_de_tipos ::= TYPE { Definición_de_tipo ; }
Definición_de_tipo ::= Identificador = Esquema_de_tipo
Esquema_de_tipo ::= Identificador_de_tipo |
                                Tipo_enumerado |
                                Tipo_subrango |
                                Tipo_conjunto              (etc…)

En los apartados siguientes se indica la forma en que se pueden definir los esquemas de los tipos enumerados, subrango o conjuntos.

9.2 Tipos enumerados

Aparte de los valores predefinidos básicos (números, caracteres, etc.) en Modula-2 se pueden definir y utilizar nuevos valores simbólicos de la manera que se indica a continuación.

9.2.1 Definición de tipos enumerados
Una manera sencilla de definir un nuevo tipo de dato es enumerar todos los posibles valores que puede tomar. En Modula-2 esta enumeración se realiza mediante una lista con los valores separados por comas (,) y encerrados entre paréntesis. Cada posible valor describe mediante un identificador. Estos indentificadores al mismo tiempo quedan declarados como valores constantes. Por ejemplo:

TYPE
   TipoDia = (Lunes, Martes, Miercoles, Jueves, Viernes, Sabado, Domingo);
   TipoMes = (Enero, Febrero, Marzo, Abril, Mayo, Junio, Julio, Agosto, Septiembre, Octubre, Noviembre, Diciembre);
   EstadoCivil = (Casado, Soltero, Viudo, Divorciado);
   Color = (Rojo, Amarillo, Azul);
   Frutas = (Pera, Manzana, Limon, Naranja, Kiwi);
   Cardinal = (Norte, Sur, Este, Oeste);
   Pieza = (Rey, Dama, Alfil, Caballo, Torre, Peon);

La enumeración implica un orden que se establece entre los valores enumerados. Este orden se define de forma implícita e impone que el primer elemento de la lista ocupa la posición 0, el siguiente la 1, y así sucesivamente hasta el último, que ocupa la posición N-1, siendo N el número de elementos enumerados. Los tipos de datos enumerados forman parte de una clase de tipos de Modula-2 denominados tipos ordinales, a la cual pertenecen también los tipos INTEGER, CARDINAL y CHAR, pero no el tipo REAL.

La sintaxis exacta de la declaración de los tipos enumerados es la siguiente:

Tipo_enumerado ::= (Lista_de_identificadores)
Lista_de_identificadores ::= Identificador { , Identificador }

9.2.2 Uso de tipos enumerados
Los tipos enumerados se emplean de manera similar a los tipos predefinidos. El identificador de tipo se puede emplear para definir variables de ese tipo, y los identificadores de los valores enumerados se emplean como las constantes con nombre. Usando las definiciones anteriores podremos escribir:

VAR diaSemana : TipoDia;
        colorCoche : Color;
        mes : TipoMes;
. . . .
diaSemana := Lunes;
colorCoche := Azul;
FOR mes := Junio TO Diciembre DO . . . .
. . . .

Puesto que entre los valores enumerados existe un orden definido, podremos emplear con ellos los operadores de comparación, y escribir:

IF mes >= Julio THEN . . . .
. . . .
WHILE diaSemana < Sabado DO . . . .
. . . .
IF coloCoche = Rojo THEN . . . .

Al igual que para el resto de los tipos ordinales, con los tipos enumerados se pueden utilizar la función predefinida ORD para obtener la posición de un valor en la lista de valores del tipo. Por ejemplo:

ORD( Casado )            = 0
ORD( Kiwi )                 = 4
ORD( Diciembre )         = 11

La operación inversa, que permita conocer qué valor enumerado ocupa una determinada posición, se consigue mediante la función predefinida VAL, que se invoca en la forma:

VAL( T, N )

y devuelve el valor que ocupa la posición N en la colección de valores del tipo T. Con los ejemplos anteriores se cumple que:

VAL( EstadoCivil, 0 )        = Casado
VAL( Frutas, 4 )               = Kiwi
VAL( TipoMes, 11 )          = Diciembre

Otras operaciones aplicables a los tipos ordinales, y por tanto a los enumerados, corresponden a los procedimientos predefinidos INC y DEC, que reemplazan un valor por el siguiente o anterior, respectivamente (o por el N-esimo siguiente o anterior, si se invoca con dos argumentos). Por ejemplo:

colorCoche := Rojo;
mes := Diciembre;
INC( colorCoche );
DEC( mes, 3 )

da como resultado

colorCoche = Amarillo     y      mes = Septiembre

Sin embargo

mes := Diciembre;
INC( mes )

provocará un error, ya que no existe el mes siguiente a Diciembre.

Un dato de tipo enumerado se puede pasar como argumento de procedimientos o funciones y puede ser el resultado de una función. Por ejemplo, si conocemos el día de la semana de hoy y queremos calcular qué día de la semana será dentro de N días, podemos emplear la siguiente función:

PROCEDURE SumarDias( Hoy: TipoDia; N: INTEGER): TipoDia;
   CONST DiasSemana = 7;
   VAR aux: INTEGER;
BEGIN
   aux := ( ORD(Hoy) + N) MOD DiasSemana;
   RETURN VAL( TipoDia, aux );
END SumarDias;

Como se puede observar, primeramente se calcula el ordinal del nuevo dia entre 0 y 6, según el orden establecido en la definición de TipoDia y finalmente se devuelve este ordinal convertido al tipo correspondiente mediante la función predefinida VAL.

9.3 El tipo predefinido BOOLEAN

Al introducir las estructuras de selección o iteración se han descrito sentencias de Modula-2 que utilizan expresiones lógicas o de condición. En ese momento se dijo, de manera informal, que el valor de una condición podía ser cierto o falso. De manera más precisa podemos indicar ahora que en Modula-2 existe el tipo predefinido BOOLEAN que responde a la siguiente definición, análoga a la de un tipo enumerado:

TYPE BOOLEAN = (FALSE, TRUE)

Esta definición no es necesario escribirla ya que está implícita en el lenguaje. El nombre BOOLEAN es el identificador del tipo, y las constantes simbólicas TRUE y FALSE corresponden a los valores de verdad cierto y falso, respectivamente. Como tipo ordinal se cumple:

ORD( FALSE )    = 0
ORD( TRUE )      = 1

A partir del tipo predefinido BOOLEAN, ahora es posible declarar variables de este tipo y utilizarlas, de forma similar al resto de variables, para guardar resultados de expresiones condiconales. Por ejemplo

VAR bisiesto : BOOLEAN;
. . . .
bisiesto := (anno MOD 4) = 0;

Asimismo, es posiblre realizar operaciones entre ellas. En concreto, entre operandos booleanos (variables o no) es posible realizar las operaciones lógicas ya indicadas en el Tema 5 para formar expresiones lógicas y cuyos operandos son los siguientes:

Operador                               Operación lógica
AND o el símbolo &                 Conjunción
OR                                         Disyunción
NOT o el símbolo ~                  Negación

Esto permite formar expresiones y sentencias tales como la siguiente:

IF bisiesto AND (mes > Febrero) THEN
   totalDias := totalDias + 1
END;

Los resultados de las expresiones lógicas para los distintos operandos y operadores son los siguientes:

   a             b           a AND b           a OR b           NOT a
TRUE      TRUE        TRUE              TRUE             TRUE
TRUE      FALSE      FALSE            TRUE             FALSE
FALSE    TRUE

        FALSE            TRUE             TRUE
FALSE    FALSE      FALSE            FALSE           TRUE

El tipo booleano, como cualquier otro tipo enumerado, se puede pasar como argumento de un procedimiento o función y puede ser devuelto como resultado de una función. De hecho es bastante habitual definir funciones cuyo resultado es un valor booleano, cuando se quiere realizar un test sobre los argumentos de la función. Este tipo de funciones se denominan predicados. Un ejemplo de este tipo de funciones es la función predefinida ODD. Esta función determina si el valor del argumento es impar. Por ejemplo:

ODD( 7 )      = TRUE
ODD( 2 )      = FALSE

9.4 Tipos subrango

Otra forma de especificar nuevos tipos de datos es estableciendo rangos parciales de valores de otro tipo ya existente. Con esto no se definen nuevos valores, pero sí un nuevo tipo con una colección limitada de valores válidos.

9.4.1 Definición de tipos subrango
Un tipo subrango se define a partir de otro tipo ordinal ya definido, que se toma como tipo base. La forma de realizar esto es declarar un identificador diferente para el nuevo tipo y establecer los límites mínimo (primero) y máximo (último) del subrango de variación. Estos límites, en Modula-2, se escriben separados por dos puntos seguidos (..) y se encierran entre corchetes:

[primero .. último]

Los valores primero y último serán valores constantes del tipo base que deben cumplir la relación:

primero < último

Por ejemplo:

TYPE Laborable = [ Lunes .. Viernes];
          PrimerSemestre = [ Enero .. Junio];
          Citricos = [ Limon .. Naranja ];
          Porcentaje = [ -100 .. 100 ];
          RangoLetras = [ "A" .. "Z" ];
          RangoDigitos = [ "0" .. "1" ];

Como se puede observar, el tipo base puede ser cualquier tipo ordinal, bien sea predefinido o definido por enumeración. Normalmente no es necesario indicar explícitamente cuál es ese tipo base, ya que se deduce fácilmente de los valores dados como primero y último. Sin embargo hay situaciones ambiguas, y en particular cuando se hacen definiciones como la siguiente:

RandoDias = [ 1 .. 31 ];

La ambigüedad se produce porque este rango de valores enteros positivos es común a los tipos INTEGER y CARDINAL. Por defecto, el compilador consideraría que el tipo base de este ejemplo es CARDINAL. Si queremos que sea INTEGER, podemos indicarlo expresamente en la forma:

RandoDias = INTEGER[ 1 .. 31 ];

Aunque resulte superfluo, la indicación explícita del tipo base se puede hacer siempre que se desee. Las declaraciones anteriores pueden reeescribirse como:

TYPE Laborable = TipoDia[ Lunes .. Viernes];
          PrimerSemestre = TipoMes[ Enero .. Junio];
          Citricos = Frutas[ Limon .. Naranja ];
          Porcentaje = INTEGER[ -100 .. 100 ];
          RangoLetras = CHAR[ "A" .. "Z" ];
          RangoDigitos = CHAR[ "0" .. "1" ];

Sobre el tipo REAL no es posible definir ningún subrango, debido a que este tipo no es tipo ordinal.

Las reglas BNF para la definición de tipos subrango son las siguientes:

Tipo_subrango ::= [ Identificador_de_tipo ]
                           [ Límite_inferior .. Límite_superior ]
Límite_inferior ::= Expresión_constante
Límite_superior ::= Expresión_constante

En esta reglas se indica, además, que para expresar los límites se pueden emplear expresiones cuyo resultado sea un valor constante del tipo adecuado.

9.4.2 Uso de tipos subrango
Las variables de un tipo subrango tienen la misma consideración que las variables de su tipo base. Por tanto, se pueden utilizar en expresiones o sentencias de asignación como si fueran variables del tipo base. Por ejemplo, una variable de tipo RangoLetras se puede utilizar como si fuera de tipo CHAR. La ventaja principal que ofrecen el tipo subrango es que, previamente a cualquier asignación a una variable, se puede comprobar automáticamente que el valor a asignar está dentro de los límites declarados. Si dicho valor está fuera del rango, el programa finaliza inmediatamente por error.

9.5 Tipos estructurados

Todos los tipos de datos presentados hasta este momento se denominan escalares, y son datos simples, en el sentido de que no se pueden descomponer. En general, no tiene sentido tratar de reconocer fragmentos de información independientes dentro de un valor entero, o un carácter, o el valor simbólico de un día de la semana o el número de un día del mes.

En muchas aplicaciones resulta conveniente, o incluso necesario, manejar globalmente elementos de información que agrupan colecciones de datos. Por ejemplo, puede ser apropiado manejar como un dato único el valor de una fecha que incluye la información del día, el mes y el año como elementos componentes separados. Con este objetivo, los lenguajes de programación dan la posibilidad de definir tipos de datos estructurados.

Un tipo estructurados de datos, o estructura de datos, es un tipo cuyos valores se construyen agrupando datos de otros tipos más sencillos. Los elementos de información que integran un valor estructurado se denominan componentes. Todos los tipos estructurados se definen, en último término, a partir de tipos simples combinados.

Los próximos apartados están dedicados al tipo estructurado conjunto, y en temas sucesivos se estudiarán las formaciones y los registros.

9.6 Conjuntos

Con el tipo enumerado Frutas definido en el apartado 9.2.1 sólo es posible tener variables que guarden en cada momento un valor único de fruta. Por ejemplo, si declaramos la variable:

VAR miFruta : Frutas;

con ella sólo es posible guardar un determinado valor de fruta en cada momento:

miFruta := Pera;     (* miFruta ahora es Pera *)
INC(miFruta);          (* miFruta pasaría a ser Manzana *)

Supongamos una frutería que se dedica al comercio de todas las frutas definidas anteriormente por enumeración como el tipo Frutas. Dependiendo de la temporada o del momento del día es posible que alguna de las frutas esté agotada, pero habitualmente la frutería dispondrá de existencias de hasta las cinco clases de frutas diferentes: Pera, Manzana, Limon, Naranja, Kiwi. Si se quiere conocer en cada momento de que fruta hay o no hay existencias sería necesario disponer de tantas variables del tipo Frutas como frutas diferentes hayan sido declaradas. Por ejemplo:

VAR
   fruta1, fruta2, fruta3, fruta4, fruta5 : Frutas;

Los incovenientes de esta solución son los siguientes:

  • Cualquiera de estas variables sería un "contenedor" capaz de guardar cualquier clase de fruta y varias o todas ellas podrían guardar la misma clase de fruta. Hay que recordar que nuestro objetivo sólo es saber de que clase de fruta hay o no hay existencias.
  • Sería necesario poder indicar cuando una variable "contenedor" está vacía y esto no es posible dado que las variables de tipo Frutas sólo pueden contener valores de ese tipo y no existe el valor NoFruta dentro del tipo enumerado Frutas.

Una posible solución alernativa sería declarar tantas variables de tipo BOOLEAN como clases de frutas tenemos. Por ejemplo:

VAR
   hayPera, hayManzana, hayLimon, hayNaranja, hayKiwi: BOOLEAN;

Los incovenientes de esta solución son los siguientes:

  • Estas variables no tienen ninguna relación con el tipo enumerado Frutas y cualquier modificación por separado con el tipo enumerado o en las variables booleanas puede ser causa de un error difícil de detectar y corregir.
  • Para ambas soluciones, con Frutas o BOOLEAN, se necesitan declarar tantas variables como clases de frutas existan y en el caso habitual de disponer de varias decenas de frutas diferentes  está no parecer ser una solución razonable.

Como conclusión se puede decir que necesitamos un nuevo tipo de dato estructurado, capaz de agrupar en una misma variable todos los indicadores de si hay o no hay elementos de un tipo referencial previamente enumerado. Este nuevo tipo de dato estructurado se denomina conjunto y está asociado al concepto matemático de CONJUNTO para el que los matemáticos han establecido un álgebra específica que determina sus propiedades y operaciones.

Como ejemplo, a partir del tipo referencial Frutas podemos definir una variable estructurada de tipo conjunto cuyos posibles valores serían los siguientes:

1 valor con NINGUNA fruta:                           1 valor con TODAS las frutas:

     CONJUNTO VACÍO                                        COJUNTO REFERENCIAL

5 valores con una sola fruta:                          5 valores con cuatro frutas:

     Pera                                                              Pera – Manzana – Limon – Naranja
     Manzana                                                       Pera – Manzana – Limon – Kiwi
     Limon                                                            Pera – Manzana – Naranja – Kiwi
     Naranja                                                          Pera – Limon – Naranja – Kiwi
     Kiwi                                                              Manzana – Limon – Naranja – Kiwi

10 valores con dos frutas:                              10 valores con tres frutas:

     Pera – Manzana                                             Pera – Manzana – Limon
     Pera – Limon                                                 Pera – Manzana – Naranja
     Pera – Naranja                                               Pera – Manzana – Kiwi
     Pera – Kiwi                                                    Pera – Limon – Naranja
     Manzana – Limon                                           Pera – Limon – Kiwi
     Manzana – Naranja                                         Pera – Naranja – Kiwi
     Manzana – Kiwi                                              Manzana – Limon – Naranja
     Limon – Naranja                                              Manzana – Limon – Kiwi
     Limon – Kiwi                                                  Manzana – Naranja – Kiwi
     Naranja – Kiwi                                                Limon – Naranja – Kiwi

Como se puede observar, el orden de las frutas no es relevante ya que el valor del conjunto: (Pera – Manzana) es el mismo que el del conjunto: (Manzana – Pera), esto es: hay Manzana y hay Pera.

También se puede observar que tenemos 32 valores diferentes, que son todos los subconjuntos posibles que se pueden obtener a partir del CONJUNTO REFERENCIAL que contiene a todas las frutas. En general, a partir de un tipo referencial de N valores posibles se forman conjuntos con 2^N valores. Por tanto, en nuestro caso para los 5 valors posibles del tipo enumerado Frutas tenemos 32 subconjuntos posibles.

La utilización de los conjuntos tiene como ventajas adicionales que todos los lenguajes disponen de las operaciones básicas entre conjuntos: Unión, Intersección, etc. Así, para actualizar las existencias de frutas de nuestra frutería cuando llega un camión con nuevas frutas, sólo se necesita realizar la operación UNIÓN entre los conjuntos de frutas de la frutería y frutas del camión.

Una aplicación típica de los conjuntos aparece en el tratamiento del estado y las alarmas de los equipos conectados a un computador (modem, impresora, ratón, teclado, etc.). En general, lo que más nos interesa saber es si hay o no hay conexión, sobretemperatura, error de paridad, atasco, etc. A lo largo de este capitulo se detallan más ejemplos de la utilidad de los conjuntos.

9.6.1 Definición de tipos conjunto
Para manejar este tipo de datos en Modula-2 se pueden definir tipos conjunto. La definición de un tipo conjunto se realiza tomando como base o conjunto referencial el conjunto de todos los valores posibles de un tipo ordinal definido previamente. Por analogía con el vocabulario de conjuntos, llamaremos tipo referencial a este tipo base. En el ejemplo anterior el tipo referencial es el tipo Frutas.

La definición de un tipo conjunto en Modula-2 utiliza las palabras clave SET OF, seguidas de la indicación del tipo referencial en el que está basado, de la siguiente forma:

TipoConjunto = SET OF TipoReferencial

Por ejemplo:

TYPE Existencias = SET OF Frutas;
         Caracteres = SET OF CHAR;
          Letras = SET OF [ "A" .. "Z" ];
          Digitos = SET OF RangoDigitos;
          Errores = SET OF (Exceso, Defecto);
          Mezcla = SET OF Color;
          Tabla = SET OF [ 1 .. 49 ];

Como se puede observar, en la definición se pueden utilizar tipos ordinales definidos anteriormente en el programa o tipos predefinidos del lenguaje, o enumeraciones o subrangos de cualquiera de ellos introducidos en la propia definición. No se pueden declarar conjuntos sobre valores reales, ya que no es un tipo ordinal y no se pueden declarar subrangos sobre ellos.

La definición del lenguaje Modula-2 establece que el compilador determine limitaciones para el tipo referencial. La limitación es que los ordinales del rango de valores del referencial deben estar comprendidos entre cero y un límite positivo particular para cada compilador. Este límite suele permitir definir conjuntos sobre el tipo CHAR, pero no es posible, en general, definir conjuntos directamente sobre los tipos CARDINAL o INTEGER.

Formalmente, la declaración de un tipo conjunto tiene la siguiente sintasix:

Tipo_conjunto ::= SET OF Tipo_simple

Tipo_simple ::=
         Identificador_de_tipo |
         Tipo_enumerado |
         Tipo_subrango

9.6.2 Construcción de conjuntos
A partir de la definición de los tipos conjuntos se pueden hacer declaraciones y posteriormente trabajar con ellas. Por ejemplo:

VAR mercadoHoy: Existencias;
        boleto: Tabla;
        listaLetras: Letras;
        paleta: Mezcla;

Para asignar valores a las variables es necesario, obviamente, indicar el valor de tipo conjunto que se desa asignar. Una forma de expresar un valor de tipo conjunto es indicar expresamente cuáles son sus elementos. Esto se hace mediante una expresión de construcción de conjunto, en la que se enumeran, entre llaves ({}), los elements del conjunto a incluir, separados por comas (,) y precedidos por el identificador del tipo del conjunto al que pertenecen los elementos. Por ejemplo:

mercadoHoy := Existencias{ Kiwi, Limon, Pera };
…..
listaLetras := Letras{ };
…..
paleta := Mezcla{ Rojo };

Si no se indica ningún elemento dentro de los corchetes, el conjunto asignado es el conjunto vacío. La lista de elementos puede ser tan larga como sea necesario y el orden en que se relacionan es irrelevante. Para abreviar, si hay varios elementos consecutivos basta con indicar el primero y el último separados por dos puntos seguidos (..). Por ejemplo:

listaLetras := Letras{ "A", "D", "H" .. "M" };
…..
boleto := Tabla{ 1 .. 5, 10 .. 15, 20 .. 25 };

En el caso de que el ordinal del primer elemento sea superior al del último, el rango que se está indicando es un rango vacío. Por ejemplo:

paleta := Mezcla{ Azul .. Rojo };

asigna el conjunto vacío a la variable paleta. Como se puede obsevar existen distintas formas de indicar el mismo conjunto. Por ejemplo:

mercadoHoy := Existencias{ Limon, Naranja .. Kiwi, Pera };
mercadoHoy := Existencias{ Pera, Limon, Naranja, Kiwi };
mercadoHoy := Existencias{ Pera, Limon .. Kiwi };
mercadoHoy := Existencias{ Pera, Limon .. kiwi, Naranja };

Todas estas expresiones dan como resultado el mismo conjunto. En el último caso, aunque se repite la inclusión del elemento Naranja, este sólo aparece una vez en el conjunto asignado a la variable mercadoHoy.

Las versiones modernas de Modula-2 permiten que los valores de los elementos del conjunto que se construye puedan ser dados en forma de expresión. Por ejmplo:

boleto := Tabla{ x .. (x+y) };

Esta misma manera de formar conjuntos también se puede utilizar para declarar constantes de tipo conjunto. Por ejemplo:

CONST
           Verde = Mezcla{ Azul, Amarillo };
           todasLasFrutas = Existencias{ Pera .. Kiwi };
           boletoInicial = Tabla{ };

En este caso, si se usarán expresiones para los elementos del conjunto, deberán ser expresiones constanes.

Las reglas BNF para las expresiones de construcción de conjuntos son las siguientes:

Construcción_de_conjunto ::=
      Identificador_de_tipo { Lista_de_elementos }
Lista_de_elementos ::= [ Elementos {, Elementos }]
Elementos ::= Expresión_constante [.. Expresión_constante]

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión /  Cambiar )

Google photo

Estás comentando usando tu cuenta de Google. Cerrar sesión /  Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión /  Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión /  Cambiar )

Conectando a %s