Funciones y Procedimientos
Funciones
¿Qué es una función? Matemáticamente,
una función no es más que una aplicación, esto
es, una REGLA o CRITERIO para obtener un cierto resultado a
partir de unos valores ya existentes. Este concepto se ha trasladado
así al campo de la informática, aunque conviene
matizar un poco más la idea.
La idea de función es la de una "caja negra" en la que nosotros
metemos datos, dentro de esa "caja" pasa *algo*, y entonces,
de la "caja", sale un resultado, un "producto".
Qué pasa dentro de esa "caja negra" depende; si somos nosotros
quienes hemos de programarla, lo sabremos, pero si no, no
tenemos por qué. Para poder usar la función sólo
necesitaremos saber qué datos de entrada admite, y de
qué tipo será el resultado. Hay que remarcar un
detalle importante: las funciones devuelven un UNICO VALOR.
Por ejemplo; dentro de un programa, podemos querer calcular
la media aritmética de una serie de datos. En principio,
nosotros lo escribimos cuando tenemos que hacer los cálculos.
Pero ahora, resulta que más adelante tenemos que volver
a calcular la media aritmética de otros datos. Y más
adelante, otra vez. ¿Vamos a escribir el código tantas
veces? ¿No sería más lógico definirnos una
función que se encargara de esa parte, y llamarla cuando la
necesitemos?
Muy bien... ¿y cómo definimos una función? Pues de la
siguiente manera:
funcion NOMBRE (arg1,...,argN) : TIPO
variables
......... {se declaran}
accion1
.......
accionN
Resultado <- Valor
fin funcion
TIPO es el tipo de dato que devolverá la
función al terminar de hacer su trabajo. NOMBRE es el
nombre que le vamos a dar a la función; por ejemplo, nuestra
función se puede llamar Pepe o se puede llamar
Media_Aritmetica. arg1 ... argN es la lista de
parámetros que vamos a pasar a la función.
La sección "variables" es una sección donde
se declararán las variables a usar por la función.
Más adelante hablaré del ámbito de las variables,
para que se entienda el por qué de esto.
accion1 ... accionN es toda la faena que debe hacer la funcion.
Al final de esa faena, la función devuelve un
Resultado, que es el que hemos especificado como "Valor".
¿Y a dónde va a parar ese "Valor"? Bueno, es que para
poder usar una función, tenemos que *invocarla*, llamarla de
alguna manera. Si las funciones son cajas que devuelven valores,
tendremos que disponer algún sitio para meter ese valor que
nos devuelva la función.
¿Cómo la llamamos?
Para poder llamar a una función, tendremos que tener definida
en nuestra declaración de variables una variable del MISMO tipo
que devuelva la función. Entonces, lo que hacemos es asignar
a esa variable lo que nos devuelva la función, haciendo lo
siguiente:
Variable <- Nombre_Funcion(arg1, ..., argN)
Esta línea hace lo siguiente: llama a la función
Nombre_Funcion, pasándole los parámetros
arg1, ..., argN; entonces, se ejecuta el código
de la función, hasta que llega al final, momento en
que devuelve un valor, y este valor devuelto es asignado a la
variable Variable.
Vamos a ver un ejemplo. Supongamos que queremos hacer un programa
que calcule, en varios puntos, la suma de los N primeros
números naturales, pero este N varía conforme el programa lo
necesita. Queremos hacer una función que nos simplifique el
trabajo. ¿Cómo lo hacemos? Bueno, lo primero que hay que
plantearse siempre es qué parámetros necesita la
función para trabajar, qué tipo de valor va a devolver y,
por último, cómo va a hacer lo que tenga que hacer
la función.
En nuestro caso, la función sólo necesita saber
quién es N, que será de tipo entero; como la suma de
naturales es natural, el resultado a devolver también
tendrá que ser una variable de tipo entero. Falta ver
cómo implementamos esa función. Por ejemplo,
lo podemos hacer así (no voy a entrar ahora en mejoras):
funcion Suma_N_Naturales(ENTERO N) : ENTERO
variables
ENTERO: Suma,i
Suma <- 0
desde i<-1 hasta i=N hacer
Suma <- Suma+i
Resultado <- Suma
fin funcion
y ahora, vamos a usarla. En nuestro programa podemos poner:
Declaracion variables
ENTEROS: N, Suma
fin declaracion variables
inicio
desde N=1 hasta N=200 hacer
Suma <- Suma_N_Naturales(N);
mostrar por pantalla ('La suma de los ',N,' primeros naturales es ',Suma)
fin desde
fin
Con esto, hacemos 200 veces, incrementando en 1 cada vez N, la
asignación a la variable Suma del resultado obtenido por la
función Suma_N_Naturales, y mostrando por pantalla el resultado.
Cada vez que se llegue a la línea de la asignación, se
llamará a la función Suma_N_Naturales, se
ejecutará el código de esa función, y al
devolver el resultado, el programa principal recupera el control
de la ejecución.
Sin embargo, dentro de la función tenemos declarada una variable
que se llama Suma, y en el programa principal hay otra variable
que se llama Suma... ¿cómo sabemos cuál es la buena?
¿no se mezclan ni nada parecido los valores?
Bueno, creo que este es un buen momento para hablar de...
Ámbito de las variables
Como ya hemos visto, un programa no tiene por qué estar formado
por un único módulo (vamos a llamarle así)
principal, si no que puede estar formado por muchas funciones, y
por muchos procedimientos (de los que hablaremos más adelante).
Cada función, o cada procedimiento, puede tener, dentro de su
sección de declaración de variables, sus propias variables,
aunque se llamen igual que las de la función de más arriba,
puesto que, al declarar una función o un procedimiento, las
variables que usan son LOCALES a ellos, es decir, sólo
ellos saben que existen y, por tanto, pueden usarlas.
Como contraposición a las variables locales, tenemos las
GLOBALES, que se declaran en una sección VARIABLES
GLOBALES; estas variables son reconocidas por cualquier función
o procedimiento que exista en nuestro programa, cualquiera puede
modificar su valor en cualquier momento.
Ahora, ¿y si hay una variable global que tiene el mismo nombre
que una variable local en una función que estoy usando? En ese
caso, se usa la variable que es local a la función.
En nuestro ejemplo no se da este conflicto, al no haber una
sección de variables globales (eso implica que no las hay), ya
que cada variable Suma pertenece a una función distinta.
Algunas notas respecto al tema de funciones:
Es una buena costumbre escribir, justo antes de la definición
de la función, un comentario sobre qué hace la
función, para qué nos van a servir los parámetros
que vamos a pasarle, y qué es lo que devuelve.
Hay que distinguir entre lo que se llama parámetros FORMALES
y parámetros ACTUALES.
Cuando definimos una función, en su CABECERA (la
línea donde pone su nombre, los argumentos que recibe y el
tipo de valor que devuelve) aparecen nombrados los argumentos. El
nombre que ponemos en ese momento es lo que se llama parámetros
formales. Pero, cuando la llamamos, por ejemplo,
Suma_N_Naturales(27), le estamos pasando el parámetro
concreto 27: a estos parámetros se les llama parámetros
actuales.
Como ejercicio, escribid una función que devuelva el
resultado de:
siendo x un número real y n un número
natural.
Procedimientos
Se llama así a un subprograma que ejecuta unas ciertas acciones
sin que valor alguno de retorno esté asociado a su nombre. En
otras palabras: NO devuelven valores (en cierto sentido).
Los procedimientos son normalmente llamados desde el algoritmo
principal mediante su nombre y una lista de parámetros
actuales (como las funciones) a través de una
instrucción específica:
LLAMAR (CALL, en inglés)
Se diferencian de las funciones en que los parámetros de llamada
pueden ser modificados si así se especifica dentro del
procedimiento; en ese sentido se puede interpretar como que
devuelven valores.
La forma de declararlos es la siguiente:
PROCEDIMIENTO Nombre (Lista de parámetros formales)
variables
acción1
.......
acciónN
Fin Procedimiento
y la forma de usarlos:
LLAMAR_A Nombre(Lista de parámetros actuales)
Vamos a ver un ejemplo de todo esto: queremos tener una forma de
calcular la suma, la resta, el producto y el cociente de dos
números cualesquiera. Obviamente, vamos a necesitar 6 variables;
2 de ellas serán los factores, y las otras 4, el resultado de
las correspondientes operaciones. Podríamos pensar en 4 funciones
que devolvieran cada una de ellas un número (entero, real, ...),
pero podemos hacer esto de forma más compacta con un procedimiento.
Veamos cómo lo declararíamos:
PROCEDIMIENTO Cuentas(ENTERO a, ENTERO b, ENTERO sum, ENTERO dif,
ENTERO mul, ENTERO dif)
sum <- a+b
dif <- a-b
mul <- a*b
div <- a/b
Fin Procedimiento
y luego lo podríamos llamar así:
LLAMAR_A Cuentas(5, 3, SUMA, RESTA, MULT, DIV)
con lo que a las variables SUMA, RESTA, MULT, DIV les serían
asignados sus correspondientes valores; estas variables se
supone que ya están declaradas previamente.
Y llegamos al último punto de esta entrega:
Recursividad
Una buena definición de este concepto es la siguiente.
Recursivo: ver recursivo
... :-D ... O:-)
Aunque, si lo quereis de otra forma: propiedad de una función
o de un subprograma de llamarse a sí mismo.
Ilustremos esto con un ejemplo, nuestra función para sumar los
N primeros números naturales. Vamos a escribirla de esta otra
forma:
funcion Suma_N_Naturales(ENTERO N) : ENTERO
variables
ENTERO: Suma
si (N=1) entonces
Suma <- 1
si no
Suma <- N+Suma_N_Naturales(N-1)
fin si
Resultado <- Suma
fin funcion
Y vamos a llamarla con Suma_N_Naturales(4), detallando
los pasos:
si (4=1) {falso, no se ejecuta}
si no {cierto, se ejecuta}
Suma <- 4+Suma_N_Naturales(4-1) {4-1=3}
Entramos en Suma_N_Naturales(3):
si (3=1) {falso, no se ejecuta}
si no {cierto, se ejecuta}
Suma <- 3+Suma_N_Naturales(3-1) {3-1=2}
Entramos en Suma_N_Naturales(2):
si (2=1) {falso, no se ejecuta}
si no {cierto, se ejecuta}
Suma <- 2+Suma_N_Naturales(2-1) {2-1=1}
Entramos en Suma_N_Naturales(1):
si (1=1) entonces Suma <- 1
y se devuelve el control al punto donde se llamó a
Suma_N_Naturales(2), donde tenemos
Suma <- 2+1,
con lo que se devuelve el control al punto donde se llamó a
Suma_N_Naturales(3), teniendo
Suma<-3+(2+1),
momento en el que se devuelve el control al punto donde se llamó
a Suma_N_Naturales(4), donde tenemos
Suma <- 4+(3+(2+1)), justo el resultado esperado.