0% encontró este documento útil (0 votos)
95 vistas50 páginas

C03 Subprogramas 2020

Este documento describe los subprogramas y sus características principales. Un subprograma es una unidad de código reutilizable que puede ser llamada desde diferentes partes de un programa. Los subprogramas permiten compartir código y datos a través de parámetros y valores de retorno. Existen diferentes mecanismos para la transferencia de información entre un subprograma y el programa principal, como la transferencia por valor, referencia y resultado.
Derechos de autor
© © All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como PDF, TXT o lee en línea desde Scribd
0% encontró este documento útil (0 votos)
95 vistas50 páginas

C03 Subprogramas 2020

Este documento describe los subprogramas y sus características principales. Un subprograma es una unidad de código reutilizable que puede ser llamada desde diferentes partes de un programa. Los subprogramas permiten compartir código y datos a través de parámetros y valores de retorno. Existen diferentes mecanismos para la transferencia de información entre un subprograma y el programa principal, como la transferencia por valor, referencia y resultado.
Derechos de autor
© © All Rights Reserved
Nos tomamos en serio los derechos de los contenidos. Si sospechas que se trata de tu contenido, reclámalo aquí.
Formatos disponibles
Descarga como PDF, TXT o lee en línea desde Scribd

Maestría en Ciencia de la Computación

Universidad de Oriente

Subprogramas
Subprograma
 Entidad compuesta de declaraciones de datos e instrucciones, conformando una
unidad de cómputo, que puede ser invocado (llamado) desde diferentes partes
del programa, constituyendo una forma primaria de reuso de código.
 Cada método de una clase se representa mediante un subprograma.
 Cada subprograma tiene un único punto de entrada.
 Cuando un subprograma es llamado se le pasa un conjuntos de argumentos que
son usados para modificar cada ejecución del subprograma, enviar datos al
subprograma o recibir los resultados del cómputo realizado por el
subprograma.
 La unidad de programa invocante queda suspendida durante la ejecución del
subprograma llamado, por lo que solo un subprograma está en ejecución en un
momento dado.
 El control retorna al invocante cuando termina la ejecución del subprograma
llamado.
2
Funciones en C++
double f (double x)
{ return x / (1 + x*x) ;
}

void intercambiar (double& x, double& y )


{ double t ;
t=x;
x=y;
y=t;
} // intercambiar

3
Llamada de una función

void intercambiar (double& x, double& y) ;


{
...........

} Correspondencia entre
parámetros

intercambiar (a , b ) ; / /llamada a la función

4
Mecanismos de intercambio de información del subprograma

 Parámetros: Se distinguen entre parámetros formales, que aparecen en


la definición del subprograma (en la parte de encabezamiento) y
parámetros o argumentos actuales que aparecen en la llamada al
subprograma. Los parámetros formales son denotados por nombres y se
comportan como declaraciones locales al subprograma.
 Valor de retorno: Algunas funciones intercambian información con el
resto del programa retornando un valor como resultado de la propia
función.
 Ambiente no local: Constituye el mecanismo más atrasado de
intercambio de información entre el subprograma y el resto del programa.
Si el cuerpo de la función modifica una variable no local a él, esta
modificación afecta a las partes del programa donde dicha variable es
visible.
5
Estructura de un subprograma
 Encabezamiento que contiene el nombre del subprograma y los parámetros
formales del subprograma y opcionalmente un tipo para el resultado.
 Cuerpo que contiene las declaraciones propias del subprograma y el conjunto de
instrucciones.
 Existen lenguajes que permiten subprogramas anidados, es decir, que permiten
declarar subprogramas dentro de las declaraciones propias de un subprograma. Tal
es el caso Pascal. Otros lenguajes no lo permiten, como C y descendientes.

6
Mecanismos de traspaso de parámetros en subprogramas

 Es la acción de control asociada a los subprogramas y que ejecuta los


siguientes pasos:
Establecer el conjunto de variables no locales al subprograma.
Ejecutar el mecanismo de transferencia entre los parámetros actuales (de la
llamada) y los formales (que aparecen en el encabezamiento de su
definición).
Reservar memoria para las variables locales al subprograma.
Ejecutar su conjunto de instrucciones.
Restablecer las condiciones previas (el ambiente de referencia al momento
de la invocación)

7
Modelos semánticos de traspaso de parámetros
 Modo entrada
 Modo salida
 Modo entrada/salida

X usa modo entrada;


Y modo salida;
Z modo entrada/salida

8
Ligadura (correspondencia) entre parámetros
formales y argumentos actuales
 Posicional: primer argumento actual con primer parámetro formal y así
sucesivamente. Es la forma más segura y eficiente para listas de parámetros
pequeñas.
 Nominal: para listas largas de parámetros. En este caso los parámetros actuales se
asignan a nombres que corresponden a los de los parámetros formales, y la
correspondencia en la invocación se establece entre argumentos actuales y formales
del mismo nombre.

9
Ejemplo en R de correspondencia entre parámetros
formales y argumentos actuales
 Subprograma para calcular el área de un trapecio:
[Link] <- function(a,c,h)
{ area <- ((a+c)/2)*h
area
}
Una llamada con correspondencia posicional: [Link] (2,5,4). La salida es 14.
Una llamada con correspondencia nominal: [Link](a=2, h=4, c=5). También la salida es 14.
 La ventaja de la correspondencia nominal es que los parámetros formales pueden aparecer
en cualquier orden en la lista de parámetros actuales.
 Si un parámetro es nominal, entonces los siguientes deben usar esta forma de
correspondencia.
 R y Python son ejemplos de LP que admiten ambas formas de correspondencia.

10
Formas fundamentales de mecanismos de
transferencia de parámetros
 Transferencia por valor
 Transferencia por referencia
 Transferencia por valor constante
 Transferencia por resultado
 Transferencia por valor-resultado
 Transferencia por nombre
 Transferencia de subprogramas.

11
Transferencia por valor
Modelo de implementación para parámetros de modo entrada.

Dirección Valor Valor Dirección

156 156
XXXX YYYY
Traspaso por
valor

Argumento actual Parámetro formal

Ventaja: Seguridad; rapidez, cuando se pasa un valor escalar


Desventajas: Consumo de tiempo y espacio si se traspasan valores que
ocupan mucho espacio.
12
Ejemplo transferencia por valor
intercambiar(int x, int y) 3, Y = 3
6
X = 6,
{ int temp = x;
x = y;
y = temp;
}
//función principal
principal()
{ int A[10]; I=3
int I = 3; A[I] = 6; A[3] = 6
intercambiar(I, A[I]);
cout << I << A[I]);
} Salida: 3 6

13
Ejemplo traspaso por valor
void nocambiar (int z)
{ z =50 ;
} // fin de cambiar

int main()
{ int x=100;
cout <<"Valor antes de ejecutar el procedimiento: " <<x <<endl;
nocambiar(x);
cout <<"Valor después de ejecutar el procedimiento: " <<x <<endl;
}

14
Traspaso por referencia
Modelo de implementación para parámetros de modo entrada/salida.

Argumento actual Parámetro formal

Dirección Valor Dirección


Valor

Referencia a

XXXX 156 XXXX YYYY

Traspaso por
referencia

Algunos lenguajes exigen que el argumento actual sea un l-valor, aunque se han
incorporados formas de semántica de movimiento que admiten r-valores.
15 En otros puede ser un valor cualquiera (FORTRAN).
Ejemplo traspaso por referencia
void cambiar (int& z)
{ z =50 ;
} // fin de cambiar
int main()
{ int x=100;
cout <<"Valor antes de ejecutar el subprograma: " <<x <<endl;
cambiar(x);
cout <<"Valor después de ejecutar el subprograma: " <<x <<endl;
}

16
Ejemplo transferencia por referencia
intercambiar(int x, int y) X = 3, Y = 6
{ int temp = x;
x = y;
y = temp; X = 6, Y = 3
}
//función principal
principal()
{ int A[10];
int I = 3; A[I] = 6; I=3 A[3]=6
intercambiar(I, A[I]); I=6 A[3]=3
cout << I << A[I]);
} Salida: 6 3

17
Ventajas-desventajas traspaso por referencia
 Proceso de traspaso eficiente: no copias, ni espacio duplicado.
 Desventajas:
 Acceso a parámetros formales probablemente más lento debido a direccionado
indirecto.
 Modificación no deseada de un parámetro actual.
 Pueden aparecer alias:
Sea void fun(int@ w, int@ z)
Con la llamada fun(a,a) son alias w y z
Con fun(x[i], x[j]), i=j alias w y z

18
Transferencia por resultado
 Modelo de implementación para parámetros de modo salida, vía de comunicación del
subprograma hacia la rutina que lo invocó, para transmitirle un valor de
salida.
 Cuando el subprograma es llamado, se salva la dirección del parámetro actual que se
corresponde con uno formal por resultado. Cuando concluye la ejecución del
subprograma, se copia el valor del parámetro formal en la dirección salvada de su
correspondiente parámetro actual, que debe ser una variable.
 Ada implementa esta transferencia a través de los parámetros out (copia de salida).

19
Transferencia por resultado …
 Comparte con la transparencia por valor la segunda ventaja y la desventaja.
 Surgen problemas si hay colisión de nombres en los parámetros actuales.
Ejemplo (C#):
void Fixer(out int x, out int y) {
x = 17;
y = 35;
}
. . .
[Link](out a, out a);
El parámetro a toma valor 35, pero si se invierten las instrucciones de Fixer toma
valor17.

20
Transferencia por resultado…
intercambiar(int x, int y) Error de indefinición:
{ int temp = x; X e Y sólo envían
x = y; valores de resultado
y = temp;
}
//función principal
principal()
{ int A[10];
int I = 3; A[I] = 6; I=3 A[3]=6
intercambiar(I, A[I]);
cout << I << A[I]);
}

21
Transferencia por valor-resultado
 Combina las transferencias por valor y resultado.
 Tiene un efecto similar al mecanismo por referencia, aunque reservando memoria
al parámetro formal que se inicializa con el valor del parámetro actual. La
dirección del parámetro actual es salvada.
 Al concluir la ejecución del subprograma y antes de destruir el ambiente local se
copia el valor del parámetro formal en la dirección salvada del parámetro actual.
 Si los parámetros de nuestro ejemplo fuesen por valor-resultado la salida sería la
misma que si se usara transferencia por referencia.
 Esto último es lo usual, excepto cuando se tienen en el subprograma expresiones
diferentes para un mismo valor (p.e., por aliasing).
 El lenguaje Ada usa esta forma de transferencia a través de sus parámetros in out.
Sin embargo, el peligro de aliasing no existe, ya que el lenguaje lo da como error.
22
Transferencia por valor-constante
 La llamada por valor es muy costosa para parámetros de gran tamaño, tanto en
espacio a reservar para el parámetro formal como tiempo de copia byte-byte del
argumento actual al parámetro formal.
 Una posible solución: para parámetros de entrada muy grandes es emplear para
ellos la transferencia por referencia, manteniendo la semántica de paso por valor.
 Esto constituye la transferencia de parámetro de sólo copia o por valor constante.
 Por ejemplo, en C++, declarando el parámetro formal const tipo &.

23
Transferencia por nombre
 Modelo de implementación para parámetros de modo entrada/salida.
 Similar a la transferencia por referencia, pero el cálculo de la dirección del
argumento actual no sólo ocurre al momento de la invocación, sino cada vez
que se use el formal correspondiente, pues el texto literal del parámetro actual
remplaza cada ocurrencia de su correspondiente parámetro actual. Las variables
que aparezcan en tales expresiones se consideran globales al subprograma
llamado.
 Si los argumentos actuales son variables simples, esta forma de transferencia es
equivalente a emplear el mecanismo por referencia.
 La transferencia por nombre resulta un mecanismo flexible, poderoso, pero
poco eficiente en virtud de tantos cálculos de direcciones, que puede constituir
fuente de errores y puede producir cálculos impredecibles. Fue implementada
en ALGOL-60 y usada luego en [Link] no es parte de ningún lenguaje
24 de amplio uso.
Ejemplo transferencia por nombre
intercambiar(int x, int y) X = 3, Y = 6
{ int temp = x;
x = y; X = 6,
y = temp; Y = 3  A[6]=3
}
//función principal
principal()
{ int A[10];
int I = 3; A[I] = 6; I=3 A[3]=6
intercambiar(I, A[I]); I=6 A[6]=3
cout << I << A[I]);
} Salida: 6 3 (a[6])

25
Transferencia de subprogramas
 Un subprograma es de orden superior si acepta
como parámetro o retorna otro subprograma Con int g(int h(int b)) {...}
como su resultado. denotamos la declaración de una función g con
 Lo primero es bastante común, lo segundo es un parámetro h que a su vez retorna un valor
menos común, pero es un mecanismo entero. Dos puntos clave en el ejemplo son:
fundamental de los lenguajes de programación
funcionales. • El hecho de que f es argumento actual en la
llamada a g y luego es llamado a través del
 Ejemplo en seudocódigo C.
parámetro formal h.
int x=1;
int f(int y) • El nombre x es usado más de una vez, por lo
{ return x+y; que es necesario establecer cuál es el
} ambiente no local en el cual f será evaluada.
int g (int h (int b)) Clausura de fun =
{ int x = 2;
return h(3) + x; // 7 <fun, AmbRef(fun)>
} Ejemplo: Clausura(f)=<f,{x/1}>
...
{ int x = 4;
int z = g(f); // 11
}
26
Transferencia de subprogramas…

 Ejemplo en seudocódigo C. En C++ (con algunos adornos).


int x=1; typedef int TFuncion(int);
int f(int y) int x{1};
{ return x+y; int f(int y)
{ return x+y;
} }
int g (int h (int b)) int g (TFuncion& h)
{ int x{2};
{ int x = 2; cout <<h(3) <<endl;
return h(3)+x; //7 return h(3) + x;
} }
int main()
... { int x{4};
{ int x = 4; int z{g(f)};
cout <<"X=" <<x <<"Z=" <<z <<endl;
int z = g(f); // 11
}
}
27
Transferencia de subprogramas…
 Posibilidades de seleccionar el ambiente no local a usar cuando se ejecute f
invocado usando el parámetro formal h:
 Política de enlace profundo: Cuando un subprograma se pasa como parámetro, se
pasa su clausura  usar el ambiente activo en el momento en que se crea el enlace
entre h y f (línea 11).
 Política de enlace superficial: Enlazar el ambiente de referencia del subprograma
cuando efectivamente es llamado  usar el ambiente que está activo cuando la llamada
a f usando h ocurre (línea 7).

28
Transferencia de subprogramas…
 Los lenguajes más conocidos que usan alcance estático emplean enlace profundo.
 Esto no queda claro para lenguajes con alcance dinámico, ya que hay lenguajes que
emplean enlace profundo o y otros superficial.

29
Transferencia de subprogramas…
 Siguiendo el ejemplo anterior las diferentes
formas de alcance y políticas de enlace derivan int x=1;
en los siguientes casos: int f(int y)
 Alcance estático y enlace profundo: la llamada { return x+y;
h(3) retorna 4 y g retorna 6. La x en el cuerpo }
de f cuando es llamada usando h es la del bloque int g (int h (int b))
más externo. { int x = 2;
 Alcance dinámico y enlace profundo: la llamada return h(3) + x;
h(3) retorna 7 y g retorna 9. La x en el cuerpo }
de f cuando es llamada usando h es la local al ...
bloque en el cual g(f) ocurre. { int x = 4;
 Alcance dinámico y enlace superficial: la llamada
int z = g(f);
h(3) retorna 5 y g retorna 7. La x en el cuerpo }
de f al momento de su llamada a través de h es la
local a g.

30
Tipo de valor retornado por una función
 La mayoría de los lenguajes imperativos restringen los tipos de valores que pueden ser retornados
por una función.
 C permite retornar valores de cualquier tipo excepto arreglos y funciones.
 C++ es parecido a C, permitiendo además retornar valores de tipos definidos por el programador
o clases.
 Ada, Python, Ruby y Lua están entre los pocos lenguajes imperativos cuyas funciones y/o métodos
pueden retornar valores de cualquier tipo.
 En el caso de Ada, como no existen tipos función, no pueden retornarse valores función (aunque
si punteros a funciones).
 En algunos LP las funciones son objetos de primera clase, por lo que pueden ser pasadas como
parámetros y retornadas desde una función. Los métodos son objetos de primera clase en
lenguajes imperativos como Python, Ruby y Lua; esto se cumple también en la mayoría de los
lenguajes funcionales.
 Ni Java ni C# tiene funciones, aunque si métodos. Como los métodos no son tipos, no pueden
ser retornados.

31
Retorno de funciones por funciones
Acción que resulta usual en LP funcionales.
Ejemplo en otros paradigmas (Swift) en que una función puede retornar otra función como su valor:
func makeIncrementer() -> ((Int) -> Int) {
func addOne(number: Int) -> Int {
return 1 + number
}
return addOne
}
var increment = makeIncrementer()
increment(7)
En Kotlin
fun bar(): (String) -> String = { str -> [Link]() }
 Invocar bar() retorna una función de string a string. En este caso se invierte una cadena.
val reversi = bar()
reversi("hello")
32 reversi("world")
Efectos colaterales en llamadas de funciones
 Un efecto colateral es una modificación que se efectúa dentro de una función a
elementos (por ejemplo, variables) que le son globales o no locales.
 En el caso de una función void, o sea, que no retorna valor, las únicas formas de dar
valores de salida es a través de los parámetros que se transfieren por referencia.
Cualquier otra modificación que se realice sobre variables globales o no locales a la
función constituye un efecto colateral.
 En el caso de una función con tipo, la única forma previsible en que se devuelve valor
de la función es a través de su nombre, por lo que cualquier modificación a variables
globales, incluso por la vía de parámetros por referencia (a menos que se use el
mecanismo por referencia para ahorrar espacio y tiempo en la transferencia) son
considerados efectos colaterales.
 Las funciones en matemática no tienen efectos colaterales, ya que no hay noción de
variable. Lo mismo se cumple para lenguajes funcionales puros, como Haskell.
33
Ejemplo de efectos colaterales en llamadas de
funciones
int x, y; // variables declaradas globales
int f(int a)
{ return (x=a+1); // Introduce como efecto colateral
// la modificación de la variable x
}
int main()
{ int x{};
int y{f(x) - f(x)}; // ¿Cero?
cout <<"El valor de y es: " << y << '\n';
}
 El valor que se imprime no es cero, ya que la primera llamada de f(x) corresponde a la evaluación f(0),
pero la segunda llamada de f(x) corresponde a la evaluación f(1), puesto que en la anterior llamada el
valor de x se había incrementado de forma colateral.
 Los efectos colaterales son considerados, en términos generales, una mala práctica de programación, ya
que complican la comprensión del programa y le resta independencia a la función.
34
Argumentos por defecto
 Son valores que deben asignarse automáticamente a los parámetros formales en caso que no sean
especificados para ellos valores de argumentos actuales en la llamada de la función.
 Los parámetros por defecto se especifican cuando se declara la función, asignándoles un valor dado.
 Ejemplo C++:
void print(int valor, int base= 10)
{ cout <<valor <<base ;
}

Los llamados: Parámetro con valor


por defecto 10
print(31)
print(31,10)

ejecutarían las mismas acciones, imprimir los valores 31 y 10.

35
Argumentos por defecto en C++
 Los parámetros por defecto deben ser los últimos argumentos en la lista de parámetros. Si
alguno de los parámetros no tiene un valor por defecto, ningún parámetro previo puede
tener un valor por defecto.
 Los parámetros formales por defecto deben ser siempre declarados por valor.
 Python, JavaScript, C++ y PHP (p.e) permiten parámetros formales por defecto.

36
Sobrecarga de funciones
 Uso del mismo nombre de función para acciones con similar valor semántico,
aunque implementadas de forma diferente, en el mismo ambiente de referencia.
 La sobrecarga usa la cantidad o el tipo de los argumentos para distinguir entre
idénticos nombres de funciones o de operadores y quizás el tipo retornado.

37
Ejemplo de sobrecarga de funciones C++
// Definición de Suma para dos parámetros
double Suma(double a, double b)
{ return a+b;
}
// Definición de Suma para tres parámetros
double Suma(double a, double b, double c)
{ return a+b+c;
}
int main()
{ double f{50}, g{60}, h{100};
// Invocación de Suma con dos parámetros.
cout <<"Valor de la suma (dos valores a sumar): " <<Suma(f,g) <<endl;
// Invocación de Suma con tres parámetros.
cout <<"Valor de la suma (tres valores a sumar): " <<Suma(f,g,h) <<endl;
}

Salida
Valor de la suma (dos valores a sumar): 110
Valor de la suma (tres valores a sumar): 210
38
Subprogramas anidados
 La idea de subprogramas anidados surge con ALGOL 60.
 Motivación: crear una jerarquía de la lógica de programación y de los alcances.
 Si un subprograma solo es necesitado dentro de otro subprograma, ¿por que no colocarlo dentro y
ocultarlo del resto del programa?
 Dado que el alcance estático es común en lenguajes que permiten anidamiento de subprogramas,
se proporciona también una manera altamente estructurada que garantizar acceso a variables no
locales en los subprogramas anidados.
 Durante mucho tiempo los únicos LP que permitían subprogramas anidados fueron descendientes
directos de ALGOL 60, como ALGOL 68, Pascal y Ada.
 Muchos LP descendientes directos de C no permiten subprogramas anidados
 Incorporan esta característica recientemente (ejemplos): JavaScript, Python, Ruby, Lua, Swift, etc.
 La mayoría de los lenguajes funcionales incorporan subprogramas anidados.

39
Corrutinas
 Las corrutinas constituyeron el primer intento histórico de incluir elementos de
programación para simular la concurrencia en los lenguajes.
 La ejecución de los subprogramas es asimétrica en el sentido que si un
procedimiento A llama a uno B durante la ejecución de A, es necesario que B
complete su ejecución ante de que A la retome.
 Las corrutinas son unidades de programación con los siguientes principios:
No destruir el registro de activación de B cuando se produce un retorno a A.
Incluir una forma adicional de llamada que permita reanudar la ejecución del
procedimiento en el punto que quedó antes de su último retorno.

40
Corrutinas …
Coroutine A Coroutine B
begin begin
A1; B1;
Resume B; Resume A;
A2; B2;
Resume B; Resume A;
A3; B3;
end; end;

 Una llamada Resume permite que la corrutina que se está ejecutando se desactive en favor de
otra, la cual comenzará a ejecutarse en el punto en que anteriormente fue interrumpida.
 Si la corrutina A fuese llamada, el orden de ejecución que se establece es A1-B1-A2-B2-A3.
 Las corrutinas fueron implementadas en lenguajes como SIMULA, Modula-2, etc, pero en la
actualidad en contados LP se emplea. Un ejemplo es Lua.

41
Funciones anónimas – expresiones lambda
 Una expresión lambda produce una función directamente, sin tener que declararla.
 Sintaxis:

[Var1,Var2, …](Type1 param1, Type2 param2, …) { // código del lambda; }


 [Var1,Var2, …] : lista de captura de variables. Puede estar vacía [].
 Type1 param1, … : parámetros de la expresión lambda. Type1 es el tipo del
parámetros (se puede acompañar con const, &) y param1 es el identificador del
parámetro.
 Código del lambda (cuerpo de la función): Instrucciones que explican la acción que
realiza la expresión con sus variables y parámetros.
42
Funciones anónimas – expresiones lambda

 Ejemplo C++11:
auto sum = [](int x, int y) -> int
{ return x + y;
}
Llamada: cout << sum(2, 3); // Imprime "5"
Es opcional incluir el tipo de retorno, cuando el compilador pueda deducir el tipo de
valor retornado por la expresión lambda:
auto sum = [](int x, int y) { return x + y; };

43
Funciones anónimas – expresiones lambda...
 C++11 requiere que los parámetros de la expresión lambda sean declarados con tipos
concretos, lo cual es suavizado en C++14 que permite usar auto para hacer esa inferencia
de tipos:
auto sum = [](auto a, auto b)
{ return a + b;
};

Con la ejecución de:


cout <<sum(2,5);
sale 7.

 Expresiones lambda son bastante usadas para especificar funciones sencillas que son
referenciadas solo una vez, muchas veces un objeto función que es argumento de otra
función.

44
Funciones que requieren predicados…Ejemplo
Remover de una lista de enteros L los valores pares, tres variantes:
1) L.remove_if(es_par) , donde es_par debe haberse definido como:
bool es_par(int x)
{ return x%2 == 0)
}
2) Definiendo una expresión lambda para el predicado
auto es_par = [](int x) { return x%2==0; };
L.remove_if(es_par)
3) Usando la expresión lamba directamente como parámetro
L.remove_if([ ](int x) { return x%2==0; } )
El predicado mostrado es unáreo. Puede ser también binarios.
45
Otro ejemplo con funciones anónimas (lambda)
#include <algorithm>
#include <vector>
#include <iostream>
using namespace std;
int main()
{ int v[] {25, 26, 27, 28, 29, 30, 31};
cout << "El arreglo contiene: ";
for (auto x: v)
{ cout << x << " ";
}
cout << endl << "Entre divisor (mayor que 0): ";
int divisor {2};
cin >> divisor;
// Encontrar el primer elemento que es múltiplo de divisor;
auto elemento = find_if(begin(v), end(v), [divisor](int pm){return (pm % divisor) == 0; } );
if (elemento != end(v))
{ cout << "Primer elemento en el arreglo divisible por " << divisor;
cout << ": " << *elemento << endl;
}
else
{ cout << "Ningun elemento en el arreglo es divisible por " << divisor << endl;
}
}
46
Otro ejemplo con funciones anónimas (lambda)
#include <algorithm>
#include <vector>
#include <iostream>
using namespace std;
int main()
{ int v[] {25, 26, 27, 28, 29, 30, 31};
cout << "El arreglo contiene: ";
for (auto x: v)
{ cout << x << " ";
}
cout << endl << "Entre divisor (mayor que 0): ";
int divisor = 2;
cin >> divisor;
// Encontrar el primer elemento que es múltiplo de divisor;
auto elemento = find_if(begin(v), end(v), [divisor](int pm){return (pm % divisor) == 0; } );
if (elemento != end(v))
{ cout << "Primer elemento en el arreglo divisible por " << divisor;
cout << ": " << *elemento << endl;
}
else
{ cout << "Ningun elemento en el arreglo es divisible por " << divisor << endl;
}
}
47
Variante de productoria usando expresión
lambda
int main()
{ double x[] {3, 1, 2, 5, 4};
double mult = accumulate(cbegin(x), cend(x), 1,
[](int num1, int num2){ return num1 * num2; });
cout <<"Productoria= " <<mult <<endl;
}

48
Funciones anónimas en otros lenguajes - Ejemplos
Scala: función incremento.
var inc = (x:Int) => x+1
Uso: var x = inc(7)-1

Java
(Lista_parámetros) -> {Instrucciones}
Ejemplos:
(int x, int y) -> {return x + y;}
(x, y) -> {return x + y;} // Tipos de parámetros omitidos
(x, y) -> x + y /* return omitido, pues el cuerpo es una expresión
simple */

49
Bibliografía
 Robert Sebesta. Concepts of Programming Languages, 11th Edition. Pearson
Addison-Wesley, 2016. Capítulos 5 y 9.
 Terrence Pratt and Malvin Zelkowitz. Programming Language Design and
Implementation (4th Edition). Prentice Hall, 2001. Capítulo 1, 2 y 5 (5.3.1).
 Otros libros de los LP mencionados.

50

También podría gustarte