Documente Academic
Documente Profesional
Documente Cultură
Los valores o datos organizados proveen información, todos los sistemas de información tienen
como objetivo general el de hacer algo requerido por los usuarios con esta información. Por lo
tanto el estudio de los valores o datos es imprescindible dentro del área de las ciencias de la
computación.
En este capı́tulo se estudiarán los distintos tipos de valores en los lenguajes de programación y
se introducirá una notación formal, para no referirse a una sintaxis concreta de cada lenguaje
de programación. Finalmente se incorporarán conceptos de los lenguajes modernos en el manejo
de los valores.
2.1. Valor
Nuestro mundo gira en torno a valores que adquieren sentido cuando están organizados, por
ejemplo: ‘‘Marı́a’’, 20, 23452, ‘‘Rojas’’, 19, 545632, son valores distintos que al pare-
cer organizados cobrarı́an sentido. A continuación se definirá éste término dentro del contexto
de nuestro estudio.
Definición 1 Un valor es cualquier entidad que puede ser evaluada, almacenada en una estruc-
tura de datos, pasada como un argumento a una función o procedimiento, retornado como un
resultado de una función, etc. Cualquier entidad que existe durante una computación [18] .
Todos los lenguajes de programación involucran el uso de valores de alguna manera. Por ejemplo
en Java:
1
Estructura y Semántica de Lenguajes de Programación - Cap2. Teorı́a de valores y tipos - MSc. Patricia E. Romero Rodrı́guez 2
en Haskell:
2.2. Tipo
Es útil agrupar los valores en tipos. Por ejemplo; los valores de verdad se distinguen claramente
de los valores enteros, puesto que existen operaciones propias para los valores de verdad que no
son aplicables a los valores enteros y también viceversa.
Cardinalidad
Algunas veces es necesario determinar cuantos elementos tiene un conjunto, es decir, cuantos
valores tiene un tipo. Se escribe “#S 00 para determinar el número de valores distintos en S. Por
ejemplo:
# Valor Verdad = 2
# Enteros = 2*maxEnt+1
Todo lenguaje de programación tiene tipos primitivos cuyos valores son atómicos y tipos com-
puestos cuyos valores están compuestos a partir de otros valores más simples.
Un tipo primitivo es aquel cuyos valores son atómicos y por lo tanto no pueden ser descompuestos
en valores más simples.
Estructura y Semántica de Lenguajes de Programación - Cap2. Teorı́a de valores y tipos - MSc. Patricia E. Romero Rodrı́guez 3
Las opciones de tipos primitivos en un lenguaje de programación nos dicen mucho acerca del
área de aplicación predeterminada por el lenguaje. Un lenguaje predeterminado para el área de
comercio (por ejemplo Cobol) provee de tipos primitivos cuyos valores son cadenas de longitud
fija y los números de punto fijo. Un lenguaje predeterminado para la computación numérica (por
ejemplo Fortran) es probable que tenga tipos primitivos cuyos valores sean números reales (con
opción de precisión) y tal vez números complejos.
Tipos primitivos similares frecuentemente ofrecen lo mismo pero con distintos nombres en los
distintos lenguajes de programación. Por lo tanto, se utilizará una notación común (lenguaje
natural en español) para referirse a estos tipos, ver el cuadro 2.1.
enum Mes {ene, feb, mar, abr, may, jun ,jul, ago, sep,
oct, nov, dic}
Un tipo primitivo discreto es un tipo cuyos valores tienen relaciones uno-a-uno con un rango de
enteros. Esto es un concepto importante en Pascal y Ada, en los cuales los valores de cualquier
tipo primitivo discreto pueden ser usados en una variedad de operaciones, tales como conteo,
selección de casos e indexado de arreglos.
Un tipo compuesto (o tipo estructurado de datos) es un tipo cuyos valores son compuestos o
estructurados a partir de otros valores simples. Los lenguajes de programación soportan una
variedad amplia de estructuras de datos, por ejemplo: tuplas, registros, variantes, uniones, ar-
reglos, conjuntos, cadenas, listas, árboles, archivos seriales, archivos directos, relaciones, etc.
La variedad puede parecer muy amplia, pero estos tipos pueden entenderse en términos de un
pequeño número de conceptos estructurales. Estos conceptos se ven resumido en el cuadro 2.2.
Estructura y Semántica de Lenguajes de Programación - Cap2. Teorı́a de valores y tipos - MSc. Patricia E. Romero Rodrı́guez 4
Cada lenguaje de programación provee su propia notación para describir tipos compuestos. Para
definir los conjunto de valores para todos los tipos compuestos mencionados se introducirá una
notación matemática simple, estándar y satisfactoria. La notación es lo suficientemente poderosa
como para describir una variedad de estructuras de datos.
Las operaciones básicas sobre un par ordenado de valores son simplemente la selección de su
primer componente y la selección de su segundo componente.
#(S × T ) = #S ∗ #T
S1 × S2 × · · · × SN (2.2)
Las estructuras de datos pueden ser entendidas en términos de productos cartesianos, por ejem-
plo:
struct empleado {
int codigo;
char *nombre;
Estructura y Semántica de Lenguajes de Programación - Cap2. Teorı́a de valores y tipos - MSc. Patricia E. Romero Rodrı́guez 5
float salario;
}
Tupla homogénea
Una tupla homogénea es un caso especial del producto cartesiano, donde todos los componentes
de la tupla son elegidos del mismo conjunto. Se escribe de la siguiente manera:
Sn = S × · · · × S (2.3)
#(S n ) = #(S)n
Tupla cero
Una tupla cero es un caso especial del producto cartesiano de la ecuación 2.3, donde S 0 contiene
exactamante una tupla sin valores. Se define:
En una unión disyunta de dos conjuntos o tipos, cada valor es marcado con una etiqueta que
indica a que tipo pertene. Formalmente:
Los valores elegidos de S están etiquetados con izq y los valores elegidos de T estan etiquetados
con der.
S1 + · · · + Sn
Los registros invariantes de Pascal y Ada, las uniones de C++, los constructores de Haskell, etc.
pueden entenderse en términos de uniones disyuntas.
o en ML:
Las etiquetas EsEnt y EsReal se utilizan para identificar el tipo de valor de EntOReal, en
conceptos estructurales se representará el tipo de EntOReal como: Entero + Real
Estructura y Semántica de Lenguajes de Programación - Cap2. Teorı́a de valores y tipos - MSc. Patricia E. Romero Rodrı́guez 7
2.4.3. Mapeo
La cardinalidad de S −→ T = #T #S .
Ejemplo 4 Dado el parámetro n de tipo entero, la función par retorna como resultado true si
n es par, false en caso contrario.
bool par(int n) {
return (n mod 2==0);
}
Esta abstracción de función implementa un mapeo particular del conjunto de los enteros a los
valores de verdad, en términos formales:
Considerar los valores de S, estamos interezados en los subconjunto de S que son por sı́ mismos
valores de S. El conjunto de todos estos subconjuntos es llamado conjunto potencia de S, y es
escrito ℘(S). Formalmente:
Las operaciones básicas sobre un conjunto usualmente son las operaciones de la teorı́a de con-
juntos: prueba de membresı́a, prueba de inclusión, unión, e intersección.
#(S) = 2#S
Pascal es uno de los pocos lenguajes de programación que soporta conjuntos en forma directa.
Un tipo conjunto en Pascal tiene la sintaxis de la forma: set of T.
Pascal permite solamente conjuntos de valores de tipos primitivos discretos (es decir, conjunto
de valores de verdad, caracteres, enteros, enumerandos y conjuntos de enteros), debido a estas
restricciones se permite una implementación muy eficiente de conjuntos.
Un tipo recursivo es aquel cuyos valores estan compuestos a partir de otros valores del mismo
tipo. Un tipo recursivo es definido en términos de sı́ mismo. En general, el conjunto de valores
de un tipo recursivo T , será definido por un conjunto de ecuaciones de la forma:
Listas
Una lista es una secuencia de valores. Una lista puede tener cualquier número de componentes,
incluyendo nada. El número de componentes es llamado longitud de la lista. Una lista sin
componentes es llamada lista vacı́a. Una lista es homogénea si todos los componentes son del
mismo tipo.
Podemos definir como una lista vacı́a o como un par ordenado que consiste de un entero y el
resto de la lista (su cola). Esta es una definición recursiva y es escrita de la siguiente manera:
Generalizando :
L = U nit + (S × L)
Vamos ha introducir una nueva notación debido a su utilidad, para toda la lista infinita de
valores elegidos de S, ası́:
S ? = U nit + (S × S ? )
#S ? = #U nit + #(S × S ? )
#S ? = 1 + (#S ∗ #S ? )
#S ? = 1 + (#S ∗ (1 + (#S ∗ #S ? ))
#S ? = 1 + (#S ∗ (1 + (#S ∗ #(· · · ))
Los lenguajes funcionales permiten definir tipos recursivos directamente, ver el ejemplo 7, escrito
en ML donde se define una lista de enteros.
En cambio en otros lenguajes ésto no es posible de manera directa, en C++ por ejemplo, se
definen los tipos recursivos de manera indirecta a través de punteros.
En términos formales el tipo de Arbol es: α = α + (α × α). La letra griega α para indicar que
el tipo de árbol puede ser una familia de tipos (enteros, reales, caracteres, etc.), es decir de tipo
polimórfico.
Estructura y Semántica de Lenguajes de Programación - Cap2. Teorı́a de valores y tipos - MSc. Patricia E. Romero Rodrı́guez 10
2.5. Cadenas
Una cadena es una secuencia de caracteres. Las cadenas son soportadas por todos los lenguajes
de programación, sin embargo, no hay un consenso sobre cual serı́a la clasificación de éstas. Los
puntos de discusión son los siguientes:
Una posibilidad es hacer que la cadena sea un valor primitivo como en ML o Snobol, con valores
que son cadenas de cualquier longitud.
Otra propuesta es definir a las cadenas como arreglos de caracteres, entonces todas las op-
eraciones sobre los arreglos están automáticamente permitidas para las cadenas, con todas las
consecuencias que esto conlleva, por ejemplo en Pascal.
En Java las cadenas son clases, donde las operaciones permisibles sobre las cadenas son métodos.
En otros lenguajes las cadenas son secuencias de caracteres (listas) como en Prolog y Haskell.
Para asegurarse que las operaciones no deseadas sean prevenidas, la implementación del lenguaje
debe hacer la verificación de tipos sobre los operandos. Por ejemplo, antes que una multiplicación
sea realizada, ambos operandos deben ser verificados para asegurarse que son números.
En el caso de tipos compuestos, se deben considerar tanto la forma de la composición y los tipos
de los componentes individuales.
En un lenguaje de tipificación estática, cada variable y parámetro tiene un tipo fijo que es elegido
por el programador, ası́ el tipo de cada expresión y cada operación puede ser deducida con la
Estructura y Semántica de Lenguajes de Programación - Cap2. Teorı́a de valores y tipos - MSc. Patricia E. Romero Rodrı́guez 11
En un lenguaje de tipificación dinámica, sólo los valores tienen tipos fijos. Una variable o
parámetro no tiene un tipo designado, pero puede tomar valores de diferentes tipos en tiempo
de ejecución. Esto implica que la verificación de tipos de los operandos debe hacerse inmediata-
mente antes de realizar una operación en tiempo de corrida. Lisp y Smalltalk son ejemplos de
lenguajes dinámicamente tipados.
valores primitivos,
valores compuestos,
punteros,
referencia a variables,
La lista incluye abstracciones de procedimientos y funciones. Ellas cuentan como valores por que
pueden ser utilizadas como argumentos; pero no pueden ser evaluadas, ni asignadas, ni pueden
ser componentes de otros valores más complejos, son en efecto valores de segunda clase. Por otro
Estructura y Semántica de Lenguajes de Programación - Cap2. Teorı́a de valores y tipos - MSc. Patricia E. Romero Rodrı́guez 12
lado, los valores primitivos, arreglos, etc., pueden ser utilizados en todas las formas de definición
de valor, éstos son valores de primera clase.
Este tipo de distinción de clases era común en varios de los lenguajes de programación antigüos,
ahora en lenguajes más modernos, se evita este tipo de distinción y permite a todos los valores,
incluyendo a las abstracciones, ser manipuladas en forma similar a los valores primitivos, tal es
el caso de Haskell, donde todos sus valores son de primera clase.
Teorema 1 (El principio de completitud de tipos) Ninguna operación deberı́a ser arbi-
trariamente restringida en los tipos de los valores involucrados [18].
Éste principio señala que los lenguajes de programación no deberı́an discriminar operaciones
entre sus tipos, porque las restricciones arbitrarias tienden a reducir el poder expresivo de un
lenguaje de programación.
Los lenguajes de programación clásicos como Pascal y C tienen sistema de tipos muy simples.
Cada constante, variable, resultado de función, y parámetro formal debe ser declarado con un
tipo especı́fico. Un tipo de sistema como este es llamado monomórfico donde la verificación de
tipos es estática.
2.8.1. Monomorfismo
Un sistema de tipos donde los valores tienen tipos definidos y únicos es llamado Sistema de tipos
Monomórfico.
Por ejemplo, en C/C++ cada función es forzada a devolver un tipo especı́fico y único de datos
(al menos que sea definida con un Template1 racias a los templates o plantillas, se permite el
polimorfismo de funciones en C++) como consecuencia, cada función es monomórfica.
W rite(E)
1
G
Estructura y Semántica de Lenguajes de Programación - Cap2. Teorı́a de valores y tipos - MSc. Patricia E. Romero Rodrı́guez 13
Write, es una abstracción de procedimiento propia del lenguaje Pascal, el efecto de tal proced-
imiento depende del tipo de E, write simultáneamente denota muchos procedimientos distintos
cada uno con parámetro de distinto tipo, éste es un ejemplo de sobrecarga.
Otro ejemplo:
eof (F )
es una función propia del Pascal, ésta función verifica si es fin de archivo, su argumento F es un
archivo que puede ser de cualquier tipo, éste tipo de función es llamada polimórfica.
Significa que un número de abstracciones distintas tienen el mismo identificador; estas abstrac-
ciones no necesariamente tienen tipos relacionados.
Se debe advertir que el lenguaje deberı́a establecer reglas para evitar la ambigüedad al invo-
car funciones sobrecargadas. Por ejemplo con la llamada suma(2.5,3) ¿cuál de las funciones
Estructura y Semántica de Lenguajes de Programación - Cap2. Teorı́a de valores y tipos - MSc. Patricia E. Romero Rodrı́guez 14
será invocada?. Cada lenguaje tiene una forma distinta de encarar éste problema, en Java por
ejemplo se hacen conversiones de tipos internamente sin perder información.
Para identificar la función ha ser invocada, aparte de utilizar el número de parámetros o los
tipos de los parámetros, además se puede utilizar información del contexto de la llamada, lo que
se denomina sobrecarga dependiente del contexto.
procedure overload is
a: integer;
b: float;
begin
a:=max(2,3); -- invocacion a funcion 1
b:=max(2,3); -- invocacion a funcion 2
end overload.
2.8.3. Polimorfismo
Es una propiedad donde una única abstracción actúa sobre una familia de tipos relacionados; la
abstracción opera uniformemente sobre sus argumentos, cualquiera sean sus tipos. Utilizaremos
letras griegas para referirnos a familias de tipos. Existen distintas formas de polimorfismo, incluso
la sobrecarga se dice que es una clase de polimorfismo. Sin embargo, el propósito verdadero del
polimorfismo son las funciones polimórficas, como en el siguiente ejemplo:
max x y = x > y
Examine el tipo variable (variant) de Object Pascal, que es capaz de albergar valores que cambien
su tipo en tiempo de ejecución, lo cual es útil cuando no se conoce el tipo de los datos en tiempo
de compilación [7].
Program UnEjemploConVariant
var Comodin1, Comodin2, Comodin3, Comodin4 : Variant;
begin
Comodin1:=1.37;
Comodin2:=’Esto es una cadena’;
Comodin3:=’345.98’;
Comodin4:=Comodin1+Comodin3;
end.
El polimorfismo, es un concepto importante que merece ser estudiado con mayor detenimiento.
Debido a la necesidad de convertir valores de un tipo a valores de otro tipo, algunos lenguajes
asocian la conversión en su sistema de tipos de forma que las conversiones se las haga en forma
automática, en algunos casos el programador debe hacer explı́citas estas conversiones.
Coerción
Es la conversión implı́cita o automática de un tipo a otro. Por ejemplo: Sea la sqrt una función
que calcula la raı́z cuadrada de un número real. La llamada sqrt(5) presenta como argumento
el número entero 5, este valor es automáticamente convertido al valor real 5.0, sin que el
programador se percate de ello para que pueda efectuarse la operación.
class Imprime{
public static void main(Strings args[]) {
int i=2; double x=8.1; String p="palabra";
System.out.println(i+x);
System.out.println(p+i*x);
}
}
Conversión explı́cita
Ejemplo 13 En C:
...
int x;
...
x = (int) (1.5 + (double) (x/2));
...
En C++:
...
int x;
...
x = int(1.5 + double(x/2));
...
Bibliografı́a
[2] DACONTA MICHAEL C. Java for C/C++ programmers. Wiley & Sons. (1996).
[3] DEITEL H. M. - DEITEL P.J. Como programar en C/C++. Prentice Hall. (1994).
[5] JOYANES AGUILAR LUIS. Programación orientada a objetos. Mc Graw Hill. (1998).
[10] PITTMAN TOM.Tools for the professional programmer, The return of tiny basic. Dr.
Dobb’s. (January 2006)
[12] SAMMMET JEAN E. Programming Language: History and Future. Communications of the
ACM, Volume 15, Number 7, July 1972.
[15] SWAINE MICHAEL. The World of Software Development: Ruby On Rails. Dr. Dobb’s.
(June 2006).
[16] SWAINE MICHAEL. Software Tools for the professional programmer: Programmings
Paradigms. Dr. Dobb’s. (July 2005).
17
Estructura y Semántica de Lenguajes de Programación - Cap2. Teorı́a de valores y tipos - MSc. Patricia E. Romero Rodrı́guez 18
[17] PERELMAN-HALL DAVID. Tools for the professional programmer, Sorting in Java & C#.
Dr. Dobb’s. (January 2006)
[18] WATT DAVID A. Programming Language Concepts and Paradigms. Prentice Hall (1990).
[19] WATT DAVID A. Programming Language Syntax and Semantics. Prentice Hall (1991).