Programando desde 0: 16- Subprogramas: Funciones.

      • 320
      • mensajes
      • miembro desde
      • 07/02/07
    29/02/2012
    #1 Programando desde 0: 16- Subprogramas: Funciones.
    LECCIÓN 16: SUBPROGRAMAS - FUNCIONES

    Declaración y llamado:

    Las funciones no difieren casi en nada de los procedimientos salvo por dos cuestiones fundamentales: el encabezado, y que las funciones devuelven un valor como resultado de su trabajo.

    Como dije cuando empecé a hablar de subprogramas en la Lección 14

    Cita Escrito por Lección 14
    En muchas ocasiones ustedes han visto que he nombrado la palabra función y la palabra procedimiento, por ejemplo, al hablar del procedimiento WRITE o de la función RANDOM. En lo que sigue de este curso veremos la diferencia explícita entre lo que es un procedimiento y lo que es una función.
    Un procedimiento realiza una o varias tareas y ya. Por ejemplo, el procedimiento WRITE muestra en pantalla lo que le pasemos como parámetro y listo, luego continuamos nuestro curso. Sin embargo, la función RANDOM además de realizar sus tareas nos devuelve un valor. Explícitamente RANDOM nos devuelve un valor del tipo INTEGER dependiendo del parámetro que le pasemos al llamarla.

    Otro ejemplo es la función ORD, que recibe un caracter como parámetro y devuelve un entero como valor o CHR que recibe un entero y devuelve un caracter como valor. Sin embargo CLRSCR simplemente limpiaba la pantalla y no nos devolvía nada.

    ¿Pueden comprender la diferencia entre lo que es una función y un procedimiento? A una función la podemos poner en una asignación y o en expresiones, por ejemplo:

    Código:
    x:= RANDOM(50);
    Código:
    x:= 10 + EXP(10) + ORD('A');
    Sin embargo no podemos hacer esto con los procedimientos:

    Código:
    x:= Write(10);
    Código:
    x:= CLRSCR*ReadLn(a);
    Las funciones reciben uno o más parámetros y devuelven un valor como resultado. Por esto pueden ser usadas como parte de una asignación y/o una expresión. De ser parte de una asignación solo pueden ir a la DERECHA, no a la IZQUIERDA, o sea, no podemos hacer:

    Código:
    RANDOM(10):= 89;
    porque la función se asigna su valor a sí misma dependiendo de lo que reciba en su invocación.

    La única excepción a esta regla se da dentro del propio cuerpo de la función, pero ya lo veremos en breve.

    De este modo, para calcular el área de un triángulo lo correcto es usar una función y no un procedimiento.

    Grábense esto bien, y disculpen mi insistencia:

    LAS FUNCIONES DEVUELVEN VALORES COMO RESULTADO, LOS PROCEDIMIENTOS NO.

    Veamos como se declara una función:

    Código:
    FUNCTION nombre(parámetros): tipo;
    En vez de utilizar la palabra reservada PROCEDURE utilizamos FUNCTION. Luego le damos un nombre y entre paréntesis declaramos sus parámetros tal y como lo hacíamos con los procedimientos. Luego de la declaración de parámetros van dos puntos y el tipo de valor que devolverá la función.

    Este tipo debe ser un tipo primitivo o un Puntero (lo veremos al final), o sea, no puede ser enumerado, arreglo (array), conjunto (set) ni registro (record). Todavía no hemos hablado de algunos de ellos, pero ya lo haremos luego.

    Ahora veamos el ejemplo del área del triángulo utilizando una función que la calcule y devuelva su valor:

    Código:
    1.   PROGRAM triangulo;
    2.
    3.   Var
    4.      base, altura, area: real;
    5.
    6.   Function calcularArea(b, h: real): real;
    7.   Begin
    8.      if(b>0) and (h>0) then
    9.         calcularArea:= b*h/2
    10.    else
    11.       calcularArea:= 0;
    12. End;
    13.
    14. BEGIN
    15. //Pedimos el ingreso de datos al usuario.
    16. write('Ingaresa el valor de la base: ');
    17. readln(base);
    18. write('Ingresa el valor de la altura: ');
    19. readln(altura);
    20.
    21. //Llamamos a la función calcularArea.
    22. area:= calcularArea(base,altura);
    23. writeln('El área del triángulo es: ',area:1:2);
    24. END.
    El funcionamiento de este programa es básicamente el mismo al del anterior con la diferencia de que en vez de un procedimiento usamos una función además de que declaramos una nueva variable que contendrá el área del triángulo.

    Veamos el encabezado de la función:

    Código:
    Function calcularArea(b, h: real): real;
    Como vemos hemos declarado dos parámetros tal como lo habíamos hecho en el procedimiento. Ambos parámetros contienen valores reales. El tipo de la función lo hemos declarado como real y por tanto esta devolverá un número como resultado de sus tareas. El tipo de la función no tiene nada que ver con el tipo de sus parámetros, en este caso da la casualidad de que todo es del tipo real, pero pueden ser cualesquiera siempre y cuando el de la función sea un tipo primitivo o Puntero.

    Al igual que hacíamos en el procedimiento, en la función verificamos primero que las dimensiones ingresadas sean mayores que 0, de lo contrario diremos que el área vale 0 mediante la asignación de la línea 11. Allí pueden ver que utilizamos el identificador de la función como si fuera una variable y le asignamos el valor 0. Vemos esto también en la línea 9 donde calculamos el área en caso de que las dimensiones sean válidas y le asignamos a la función el valor de multiplicar el parámetro b por el parámetro h y dividir ese resultado entre 2.

    La función puede usarse a la izquierda de una expresión de asignación (:=) solo si estamos dentro de su bloque principal y solo cuando queramos asignarle el valor que nos devolverá. Fuera de su cuerpo la función puede ser usada solo a la derecha de las expresiones de asignación, ya sea para realizar cálculos o para que otras variables tomen su valor, tal como sucede en la línea 22 de nuestro programa.

    Mediante la expresión de asignación

    Código:
    area:= calcularArea(base,altura)
    estamos asignándole a la variable area el valor que devolverá calcularArea con los parámetros ingresados.

    Otro modo de haber escrito este programa habría sido no declarar la variable area y escribir la instrucción WRITELN de la línea 23 de esta manera:

    Código:
    writeln('El área del triángulo es: ', calcularArea(base,altura):1:2);
    Como pueden observar, incluimos dentro de la instrucción WRITE directamente la llamada a la función calcularArea para mostrar en pantalla su valor.

    -------------------------------------------------------------------------------------

    Funciones Booleanas:

    El tipo Boolean es un tipo primitivo que toma uno de dos valores posibles: TRUE (verdadero) o FALSE (falso). Esto por supuesto ustedes ya lo saben. Las funciones pueden ser del tipo boolean ya que como acabo de decir es un tipo primitivo. El hecho de que me tome un trabajo extra para tratarlas es para que ustedes puedan ver las formas más comunes en las que estas son utilizadas.

    Ahora veremos el ejemplo del área del triángulo donde tendremos dos funciones, una para verificar que lo ingresado por el usuario corresponde a dimensiones adecuadas para el triángulo, en tal caso la función devolverá TRUE y en caso contrario FALSE. Si las dimensiones son correctas entonces llamaremos a la función para calcular el área del triángulo para la cual solo nos limitaremos a hacer el cálculo ya que siempre la llamaremos en caso de que los datos ingresados sean correctos. Esto se conoce como PRE-CONDICIÓN, o sea, se llamará a la función calcularArea sí y solo sí las dimensiones son correctas, para esto necesitamos una función que sea la que verifique esto.
    Esto es lo más normal en programación, las funciones y los procedimientos tendrán pre-condiciones que siempre deberemos chequear antes de llamarlos; para estos chequeos siempre se nos darán funciones booleanas que nos dirán si las cosas son correctas o no.

    Código:
    1.   PROGRAM triangulo;
    2.
    3.   Var
    4.      base, altura, area: real;
    5.
    6.   Function verificarDatos(b, h: real): boolean;
    7.   Begin
    8.      verificarDatos:= (b>0) and (h>0);
    9.   End;
    10.
    11. Function calcularArea(b, h: real): real;
    12. Begin
    13.    calcularArea:= b*h/2;
    14. End;
    15.
    16. BEGIN
    17. //Pedimos el ingreso de datos al usuario.
    18. write('Ingaresa el valor de la base: ');
    19. readln(base);
    20. write('Ingresa el valor de la altura: ');
    21. readln(altura);
    22.
    23. If verificarDatos(base,altura) then
    24.    writeln('El área es: ',calcularArea(base,altura):1:2)
    25. else
    26.    writeln('Has ingresado alguna dimensión menor o igual a 0.');
    27. END.
    Este ejemplo debería de resultarles bien sencillo de entender. Tenemos dos funciones declaradas. Solo explicaré el funcionamiento de la función verificarDatos: Como pueden ver tiene dos parámetros reales y la función es del tipo boolean. La sentencia de la línea 8 es igual a la que se usa para las variables del tipo boolean, o sea, dicha sentencia es equivalente a escribir:

    Código:
    If (a>0) and (h>0) then
       verificarDatos:= true
    else
       verificarDatos:= false;
    Ambas formas funcionan de igual manera, pero la más correcta es la que yo utilicé en el programa. Aún así ustedes siempre tienen la libertad de utilizar las herramientas que prefieran.

    Veamos ahora el IF de la línea 23:

    Código:
    If verificarDatos(base,altura) then
    Como ya dije, las funciones pueden ser usadas como variables pero no pueden asignársele valores fuera de su bloque principal. En este caso la estamos utilizando en el IF como una variable del tipo boolean y por ende estamos preguntando si es TRUE, recuerden que solo incluir el nombre de un boolean es preguntar por su veracidad, y para preguntar por su falsedad se utiliza el operador lógico NOT.

    Ahora veamos un ejemplo un poco más complejo acerca del uso de una función booleanas. En este caso veremos una función llamada Pertenece la cual se encargará de verificar si un elemento pertenece o no a un arreglo. En caso afirmativo devolverá TRUE y en caso contrario FALSE:

    Código:
    1.   PROGRAM BooleanFunction;
    2.
    3.   Const
    4.      N= 5;
    5.
    6.   Type
    7.      arreglo = array [0..N] of integer;
    8.
    9.   Var
    10.    i, elem: integer;
    11.    a: arreglo;
    12.
    13. Function Pertenece(x: integer; A: arreglo): boolean;
    14. Var
    15.    i: integer;
    16.
    17. Begin
    18.    i:= 1;
    19.
    20.    While (i <= N) and (A[i] <> x) do
    21.       i:= i + 1;
    22.
    23.    Pertenece:= i <= N;
    24. End;
    25.
    26. BEGIN
    27. Write(‘Ingresa ‘,N,’ enteros: ‘);
    28. For i:=1 to N do
    29.    read(a[i]);
    30. Writeln;
    31. Write(‘Ingrese el elemento a buscar: ‘);
    32. readln(elem);
    33.
    34. If Pertenece(elem,a) then
    35.    writeln(‘El elemento ‘,elem,’ pertenece al arreglo.’)
    36. else
    37.    writeln(‘El elemento ‘,elem,’ no pertenece al arreglo.’);
    38.
    39. END.
    Quiero que ustedes mismos estudien este ejemplo hasta que lo comprendan. Verifíquenlo a mano si hace falta, eso muchas veces funciona para comprender como funciona un programa y es muchas veces lo que hace falta para encontrar un error que ni con el depurador (debuger) podemos hallar.
    -------------------------------------------------------------------------------------

    Llamar a un subprograma desde otro subprograma:

    Esto es realmente sencillo y según mi consideración no requiere ni de ejemplificación, solo una leve explicación para que lo sepan nada más, aunque aún daré un ejemplito genérico.
    Es posible llamar a un subprograma desde otro siempre y cuando el subprograma que estamos llamando fue declarado antes que el subprograma desde el que estamos haciendo el llamado. Veamos lo siguiente:

    Código:
    Procedure proc1(parámetros nominales);
    Begin
    //Instrucciones;
    End;
    
    Procedure proc2(parámetros nominales);
    Begin
    //Instrucciones
    Proc1(parámetros efectivos);
    End;
    Como ven aquí tenemos dos procedimientos, Proc1 y Proc2, el primero declarado antes que el segundo. En el cuerpo de Proc2 vemos una llamada a Proc1. Esto es posible porque Proc1 ya está declarado arriba, de lo contrario el compilador nos diría que no encuentra el identificador especificado. Dado esto no podemos llamar a Proc2 desde Proc1. Esto se aplica tanto para procedimientos como para funciones, y es posible llamar a una función desde otra, a un procedimiento desde una función, a una función desde un procedimiento, etc., en fin, a un subprograma desde otro.

    Como habrán visto, hasta el momento hemos usado solo el pasaje de parámetros por valor tanto para funciones como para procedimientos. La próxima lección explicará el pasaje de parámetros por referencia. Esto llevará un poco de trabajo para su entendimiento, pero si se esmeran verán que no es tan complicado.

    Espero que hasta ahora hayan entendido todo. Como ya saben pueden comentar, preguntar y aclarar lo que quieran. Saludos para todos y todas.
  1. ¿Este tema te pareció interesante? Compártelo!

    ¿No es lo que buscabas? Intenta buscar un tema similar

    2 comentarios / 2260 Visitas

      • 91
      • mensajes
      • miembro desde
      • 13/09/11
    06/03/2012
    #2 Re: Programando desde 0: 16- Subprogramas: Funciones.

    Gracias vlady

      • 320
      • mensajes
      • miembro desde
      • 07/02/07
    06/03/2012
    #3 Re: Programando desde 0: 16- Subprogramas: Funciones.

    Pues por nada.