Thursday, April 04, 2013

Paradigmas en programación... ¿verdad o mentira?


Los lenguajes de programación se basan en diferentes paradigmas. Unos son imperativos. Otros usan la lógica de predicados para funcionar (como Prolog), otros más han definido la programación orientada a objetos, con los subsecuentes beneficios que esto tiene en general para los desarrolladores. Por ello, parece ser necesario saber de qué se trata esto para poder decidir -en algún momento- cuál es el lenguaje a usar.

Curiosamente, como veremos más adelante, hay algo perturbador en esta idea de los paradigmas en los lenguajes de programación y la conclusión a la que llegaremos resulta en alguna medida, inesperada. Entremos pues en materia:

Consideremos las redes semántica, las cuales se representan comúnmente como gráficas consistiendo de nodos que se conectan a través de líneas. Los nodos representan objetos y los enlaces entre nodos representan las relaciones entre esos objetos.

Una red semántica simple puede verse en la siguiente imagen:



Nótese que los enlaces son flechas, lo cual implica una dirección. Así, el perro persigue al gato pero éste no persigue al primero. Esto podría ocurrir pero la red semántica no lo plantea explícitamente.

Las redes semánticas plantean una manera muy intuitiva de representar conocimiento sobre objetos y las relaciones entre ellos. Los datos de una red así se basan en un dominio en particular. Esto hace que el esquema sea limitado. Por ejemplo, no podemos establecer la regla de que "el perro no es un gato".

Cabe decir que muchas de las relaciones son evidentes por sí mismas, pero hacen uso del conocimiento externo que tenemos del mundo. En principio, deberíamos definir dichas relaciones para evitar ambigüedades.

Herencia

Es una relación que puede ser particular útil. La idea de la herencia se entiende fácilmente de forma intuitiva. Por ejemplo, decimos que los mamíferos dan a luz bebes vivos y podemos decir también que todos los perros son mamíferos por lo que podemos concluir que un pero da a luz mamíferos vivos. Sin embargo, no estamos diciendo nada sobre el sexo del perro y por ello la relación no necesariamente sería cierta.

La herencia nos permite especificar propiedades de una superclase y así poder definir una subclase, la cual hereda las propiedades de la superclase. En nuestro ejemplo los mamíferos son una superclase y los perros una subclase.

Frames (marcos)

Los marcos son un desarrollo de las redes semánticas y permiten expresar la idea de herencia. Un sistema de marcos consiste en un conjunto de marcos (o nodos) quienes están conectados por una relación. Cada marco describe una instancia (un marco instancia) o clase (marco clase).

En este contexto, los objetos que se representan son objetos físicos pero no necesariamente tienen que serlo. Un objeto puede ser una propiedad (un color, una forma), un sentimiento, un lugar, una situación. La idea de los objetos en este sentido es idéntica a los que se ven en la Programación Orientada a Objetos (POO).

Cada marco tiene una o más ranuras, también podrían llamárseles "propiedades, a las que se le asignan valores. Esta es la manera en que una red de marcos se construye. En lugar de simplemente tener enlaces entre marcos, cada relación se expresa con un valor en una de las ranuras.

Por ejemplo, cuando decimos que "Fido es un perro" lo que queremos decir es que "Fido es una instancia de la clase perro"  o bien, que Fido es un miembro de la clase perro". Aquí la relación "es un" (is-a) es muy importante en una representación de marcos porque nos permite expresar que alguien es miembro de una clase. Esto se conoce como una generalización porque referirse a la clase de mamíferos es más general que referirse a la clase de perros y referirse a la clase de perros es más general que referirse a Fido.

Es también útil hablar de un objeto que es parte de otro objeto.  Por ejemplo Fido tiene cola, por lo que la cola es parte de Fido. Esto se llama agregación porque Fido puede ser un agregado de las partes de un perro.

Otra relación es la asociación. Un ejemplo es la relación de "perseguir" Esto explica cómo un perro y un gato están relacionados o asociados uno con el otro.

¿Por qué usar marcos?

La ventaja principal de usar sistemas de marcos es que la información de un objeto se encuentra toda en un solo lugar (esto es clásico en el paradigma de la POO). Además, la herencia puede extenderse de la siguiente manera. Por ejemplo:

Los perros persiguen a los gatos
Los gatos persiguen a los ratones

Para expresar este tipo de información, no necesitamos saber que el perro persigue al gato o que éste último persigue a los ratones. Podemos heredar la información porque un gato en particular podría ser una instancia de la clase gatos y en nuestro ejemplo, Fido es una instancia de la clase perro.

Podemos además añadir la siguiente información:

  • Los mamíferos respiran
  • Los perros son mamíferos
  • Los gatos son mamíferos

Y tenemos una superclase, mamíferos, en donde los perros y gatos son subclases. Así, no necesitamos expresar explícitamente que los perros y gatos respiran porque se puede heredar esta información.

Herencia múltiple

Es posible en un marco heredar propiedades de otro marco. En otras palabras, una clase puede ser una subclase de dos superclases y el objeto puede tener una instancia de más de una clase. Por ejemplo, podemos decir que el hombre es un constructor de casas, y que además, es un mamífero. Esto es la herencia múltiple, pero en mi opinión, es absurda si se tiene un sistema con una jerarquía bien armada. A la fecha, de hecho, no he hallado un ejemplo de la necesidad de herencia múltiple para representar conocimiento.

Procedimientos

En la POO las clases (y de hecho los objetos), tienen métodos asociados a ellos. Esto también ocurre con los marcos. Estos tienen métodos asociados a ellos llamados procedimientos.

Un procedimiento es un conjunto de instrucciones asociados al marco que puede ser ejecutado a petición. Por ejemplo, un procedimiento lector de las propiedades puede regresar un valor particular dentro del marco. Otro procedimiento puede insertar un valor en una propiedad. Un procedimiento importante es el constructor de una instancia, el cual crea la instancia de una clase.

Y si pensamos en esto, una red semántica dirigida (los marcos, pues), son un equivalente a la programación orientada a objetos, en donde se definen las propiedades de los mismos, los métodos que pueden usar y la herencia. Solamente quedaría duda de cómo usar el polimorfismo, es decir, cuándo se debe usar un procedimiento de un objeto u otro. Evidentemente esto se puede hacer y entonces, cualquier lenguaje basado en el paradigma de la POO puede ser usado para escribir programas " inteligentes". Es más, hay una clara equivalencia entre los marcos y la programación basada en la lógica de predicados y por ende, si podemos expresar un marco en la POO o bien, en la lógica de predicados, entonces en el fondo no hay un cambio de paradigma. Lo que parece ser que realmente tenemos es un esquema ded representación de conocimiento que no distingue entre paradigmas, porque en el fondo todos los lenguajes que expresan y representan conocimiento, hacen lo mismo.

Este resultado me parece asombroso en cierta medida. Así pues, no hay necesidad de elegir un lenguaje de programación que use un paradigma u otro, cualquiera puede usarse para representar conocimiento de la misma manera.

3 comments:

Angel Renato Zamudio Malagon said...

Hola,

La diferencia entre un paradigma y otro no reside en la expresividad de la información de uno con respecto a otro, sino mas bien en que tan cómodo es para un programador u otro. Por ejemplo si vas a programar un navegador web, lo puedes programar en Haskell pero como programador te va a dar muchos dolores de cabeza mientras que si lo programas en Java o C++ tal vez lo hagas mas rápido.

Saludos

Martín A. Márquez said...

En la teoría todos los lenguajes son turing-compatible, cambian en un contexto de industria, hay lenguajes de programación especifícos de dominio, donde algunos lenguajes cubren más aspectos que otros, por ejemplo: Java y .NET por estar apoyados por Oracle y Microsoft, serán mejores que python,perl o php. Esto por que MS y Oracle venden todo el stack desde el hardware hasta el software de aplicación, pasando por el sistema operativo, base de datos, paquetería de oficina, servidor web y otras cosas. Por eso al medir costos y tiempos de integración con otros lenguajes nunca serán igual.

Martín A. Márquez said...

En teoría todos los lenguajes de programación son iguales (turing-compatible), cambian en el contexto industrial, donde Java y .NET siempre serán mejores que php, python, perl, actionscript, etc. Al estar apoyados por Oracle y Microsoft que ofrecen todo el stack completo de TI desde el hardware hasta los servidores de aplicación, pasando por el sistema operativo, servidor de correo, servidor web, base de datos, paqueterìa de oficina, etc. Por eso en cuanto a cumplimiento de los requerimientos los demás lenguajes ni siquiera son rivales.