PROGRAMACIÓN IMPERATIVA
Un programa en un lenguaje imperativo aparece como una lista de instrucciones u órdenes elementales que han de ejecutarse una tras otra, en el orden en que aparecen en el programa. Las instrucciones de un programa imperativo utilizan datos almacenados en la memoria del computador, llamados variables. Para realizar algún cálculo, se parte de ciertos datos almacenados y se realizan diversas operaciones (instrucciones); al final, el resultado está almacenado en alguna celda de memoria.
A este tipo de paradigma de programación se le suele llamar algorítmico, dado que el significado de algoritmo es análogo al de receta, método, técnica, procedimiento o rutina, y se define como "un conjunto finito de reglas diseñadas para crear una secuencia de operaciones para resolver un tipo específico de problemas".
Las principales características de la programación imperativa son:
- Concepto de variable. El componente principal es la memoria, compuesto por un gran número de celdas donde se almacenan los datos y que son referenciadas por medio de su nombre (variable). El conjunto de valores de todas las variables del programa en un momento dado representa el estado del programa.
- Operaciones de asignación. Cada valor calculado debe ser asignado a la variable mediante operaciones de asignación. De esta forma se modifica el estado del programa.
- Repetición. Un programa imperativo, normalmente realiza su tarea ejecutando repetidamente una secuencia de pasos elementales.
- Secuencialidad: las instrucciones se ejecutan en base al orden en que fueron escritas. Su esencia es el cálculo iterativo, paso a paso, de valores de nivel inferior y su asignación a posiciones de memoria.
El paradigma imperativo es una abstracción del lenguaje ensamblador. En los términos mencionados anteriormente, el modelado se realiza más cerca del “espacio de la solución” que del “espacio del problema”.
Algunos de los lenguajes de programación que siguen el paradigma imperativo son BASIC, Pascal, Modula y C.
PROGRACIÓN ORIENTADA A OBJETOS
Existen varios conceptos relacionados con la programación orientada a objetos: clases, estructuras, sobrecarga de operadores, interfaces… Pero se considera que un lenguaje es totalmente orientado a objetos si contiene las siguientes características: herencia, polimorfismo y encapsulamiento; muy relacionada con esta última tenemos también que destacar la abstracción de datos.
Estos cuatro conceptos se encuentran muy relacionados: La herencia organiza y facilita el polimorfismo y el encapsulamiento permitiendo a los objetos ser definidos y creados como tipos especializados de objetos preexistentes
- Abstracción: Se puede definir como la capacidad de examinar algo obviando aquellos detalles que no son esenciales y sin preocuparse de los detalles internos. El cómo se realiza la tarea no es importante; mientras el procedimiento sea fiable se puede utilizar sin tener que conocer cómo funciona su interior.
- Encapsulamiento: Muy ligado a la abstracción esta la "ocultación de la información" o encapsulamiento. El aislamiento protege a las propiedades de un objeto contra su modificación por quien no tenga derecho a acceder a ellas, solamente los propios métodos internos del objeto pueden acceder a su estado. Esto asegura que otros objetos no pueden cambiar el estado interno de un objeto de maneras inesperadas, eliminando efectos secundarios e interacciones inesperadas.
- Polimorfismo: Se refiere al hecho de que una misma operación puede tener diferente comportamiento en diferentes objetos. El operador + realiza la suma de dos números de diferente tipo. Además se puede definir la operación de sumar dos cadenas mediante el operador suma.
- Herencia: Impone una relación jerárquica entre clases en la cual una clase hija hereda de su clase padre. Si una clase sólo puede recibir características de otra clase base, la herencia se denomina herencia simple. Si una clase recibe propiedades de más de una clase base, la herencia se denomina herencia múltiple.
PROGRAMACIÓN DECLARATIVA
Los lenguajes declarativos están más cercanos a la forma de pensar del programador (son de más alto nivel), y no necesitan la especificación de la secuencia en la que tienen lugar las operaciones elementales dentro de la máquina. El tamaño de los programas y el tiempo necesario para desarrollarlos son sensiblemente menores, en general, que los correspondientes en cualquier lenguaje imperativo. Como contrapartida, los programas desarrollados en lenguajes funcionales suelen ser más ineficientes que los programas imperativos y lenguajes máquina: lo que se gana en transparencia y en tiempo de desarrollo, se pierde en eficiencia. Hasta hace poco, la diferencia estribaba en que existían compiladores muy buenos para lenguajes imperativos que permiten su uso a escala industrial, pero no para lenguajes declarativos, considerados como productos de “laboratorio”. En la actualidad están empezando a usarse lenguajes lógicos y funcionales para aplicaciones y proyectos a gran escala, y es posible que en un futuro no muy lejano lenguajes como los funcionales sean preferidos por una mayoría de programadores.
Programación funcional
La programación funcional es una forma de programar que pone el énfasis en la evaluación de expresiones en lugar de en la ejecución de órdenes. La ejecución de un programa funcional no es sino la aplicación de una función a unos datos; la expresión que resulta se reduce, mediante re-escrituras sucesivas, a expresiones equivalentes más sencillas, hasta llegar a una expresión irreducible que se considera el resultado de la ejecución del programa. Una característica esencial de los lenguajes funcionales es que pueden existir funciones de orden superior, es decir, funciones que tienen como argumento a otras funciones (dicho de otra forma, programas que tienen como argumentos otros programas). Otra característica esencial es la evaluación perezosa (sólo se realiza un cálculo cuando otro cálculo posterior lo necesita), que permite la definición de estructuras infinitas de datos, así como de funciones y tipos de datos no estrictos.
Los lenguajes funcionales han sido, desde la invención del Lisp, los más utilizados en Inteligencia Artificial. En los últimos años, la consolidación de estándares como el Haskell y la aparición de compiladores cada vez más eficientes han hecho que se estén comenzando a utilizar en aplicaciones industriales.
Programación lógica
Por programación lógica se entiende el uso de la lógica para representar problemas y métodos de resolución de problemas (en forma de hechos y reglas) junto con la utilización de procedimientos automáticos de prueba para la solución efectiva de los problemas. Tal y como define Kowalski: algoritmo = lógica + control.
La programación lógica trabaja con relaciones más que con funciones. Un programa convencional distingue entre datos de entrada (argumentos) y datos de salida (resultados). El equivalente en Prolog es una relación entre todas las variables que intervienen, sin distinguir entre argumentos y resultados. En general, esa relación sirve para encontrar los valores posibles de cualquier variable a partir de los valores conocidos del resto.
La programación lógica –en particular, el Prolog– se utilizó, en sus orígenes, en el campo del procesamiento del lenguaje natural. Desde entonces, su uso se ha extendido a la construcción de sistemas expertos, búsquedas en bases de datos, diseño de compiladores, especificación de algoritmos, etc.
Conceptos básicos:
- Transparencia referencial: esta propiedad se puede definir como que cada elemento de su dominio se corresponde con un único elemento del rango, es decir, el resultado de aplicar una función sobre sus argumentos viene dada solamente por el valor de dichos argumentos.
- Modularidad: la composición de funciones es la principal técnica que utiliza la programación funcional, lo cual nos permite la construcción de programas mediante la utilización de funciones primitivas o previamente definidas por el usuario. Todo esto refuerza la modularidad de los programas.
- Funciones como objetos de primera clase: este tipo de lenguajes emplea las funciones como objetos muy importantes dentro del lenguaje, puesto que se pueden almacenar en estructuras de datos, pasarse como argumentos a otras funciones y devolverse como resultados.
- Evaluación perezosa: consiste en que si el resultado de evaluar el primer operando permite deducir el resultado de la operación, entonces no se evalúa el segundo y se devuelve dicho resultado directamente.
- Polimorfismo paramétrico: permite que una determinada función tenga la capacidad de aceptar como parámetros una variedad de tipos distintos cada vez que sea llamada, sin que esto influya en que la función pueda obtener y regresar el resultado esperado.