"60programacionfuncional_1.gif"
por José Luis Gómez Muñoz       
http://www.globalcomputing.com.mx/

Listas de números

Este comando construye una lista con los cuadrados de los primeros diez enteros

"60programacionfuncional_2.gif"

"60programacionfuncional_3.gif"

El siguiente comando construye una lista con 10 números aleatorios, cada número entre 0.0 y 1.0. La lista es guardada en la variable tenNumbers

"60programacionfuncional_4.gif"

"60programacionfuncional_5.gif"

La variable tenNumbers contiene los diez números generados antes:

"60programacionfuncional_6.gif"

"60programacionfuncional_7.gif"

Podemos extraer el tercer elemento de la lista con la siguiente sintaxis:

"60programacionfuncional_8.gif"

"60programacionfuncional_9.gif"

Una lista de un millón de números aleatorios

Este comando crea una lista de un millón de números aleatorios, cada número entre 0.0 y 1.0. Es importante el punto y coma al final del comando, le indica a Mathematica que no queremos ver el resultado, sólo queremos guardarlo en la variable millionNumbers.

"60programacionfuncional_10.gif"

Podemos extraer el tercer elemento de la lista con la siguiente sintaxis:

"60programacionfuncional_11.gif"

"60programacionfuncional_12.gif"

Podemos extraer el 12345-ésimo elemento de la lista con la siguiente sintaxis:

"60programacionfuncional_13.gif"

"60programacionfuncional_14.gif"

Forma ineficiente de sumar todos los números en la lista "millionNumbers"

Muchos nuevos usuarios de Mathematica aprendieron a programar en lenguajes que trabajan con procedimientos (C, Fortran, Pascal, etc), por lo tanto están acostumbrados a usar comandos como For, los cuales pueden ser ineficientes

"60programacionfuncional_15.gif"

"60programacionfuncional_16.gif"

La representación interna de listas y sumas son muy similares

Antes de estudiar una forma más eficiente de sumar todos los números en una lista larga, debemos entender la representación interna (FullForm) de listas y sumas.
Esta es la representación interna en Mathematica de la lista {a,b,c,d}

"60programacionfuncional_17.gif"

"60programacionfuncional_18.gif"

Por otro lado, esta es la representación interna (FullForm) en Mathematica de la suma a+b+c+d

"60programacionfuncional_19.gif"

"60programacionfuncional_20.gif"

Como puedes ver, las representaciones internas de {a,b,c,d} y a+b+c+d son idénticas, excepto por la cabeza (Head) List o Plus. Este hecho será usado más adelante para construir una forma eficiente de sumar números en una lista larga.

Escribiendo List[100,20,30] y Plus[100,20,30] directamente en Mathematica

Ahora escribiremos directamente las formas internas de listas y sumas, para ver como reacciona Mathematica.
Primero escribe List[100,20,30] y oprime [SHIFT]-[ENTER]

"60programacionfuncional_21.gif"

"60programacionfuncional_22.gif"

Ahora escribe Plus[100,20,30] y oprime [SHIFT]-[ENTER]

"60programacionfuncional_23.gif"

"60programacionfuncional_24.gif"

Como puedes ver, cuando escribiste List[100,20,30], Mathematica no lo modificó, simplemente lo mostró con las llaves. Por otro lado, al escribir Plus[100,20,30] se llevó a cabo el cálculo. Podemos decir que List[100,20,30] es "estable", no "evoluciona", mientras que Plus[100,20,30] es "inestable", y "evoluciona" a 150.
La idea básica para sumar todos los números de una lista larga, es simplemente reemplazar la cabeza "List" con la cabeza "Plus", y la expresión "evolucionará" automaticamente al resultado.

Reemplazando las cabezas de las expresiones con el comando "Apply"

Aquí se muestra el comando Apply, que reemplaza las "cabezas" de las expresiones

"60programacionfuncional_25.gif"

"60programacionfuncional_26.gif"

Aquí la cabeza "goodbye" se reemplaza con la cabeza "hello". Ninguna de las dos cabezas es un comando de Mathematica.

"60programacionfuncional_27.gif"

"60programacionfuncional_28.gif"

Aquí la cabeza "List" es reemplazada con la cabeza "hello"

"60programacionfuncional_29.gif"

"60programacionfuncional_30.gif"

Exactamente como el ejemplo anterior, la cabeza "List" es reemplazada con la cabeza "hello". Abajo no se escribe la cabeza "List", pero Mathematica transformará {100,20,30} en la forma interna List[100,20,30], y después la evolución es exactamente como en el ejemplo de arriba.

"60programacionfuncional_31.gif"

"60programacionfuncional_32.gif"

Finalmente reemplaza la cabeza "List" con la cabeza "Plus"; la expresión Plus[100,20,30] es generada, pero esta expresión es "inestable" y "evoluciona" hacia el resultado numérico:

"60programacionfuncional_33.gif"

"60programacionfuncional_34.gif"

Podemos guardar la lista en una variable, y después usar esa variable en el comando Apply:

"60programacionfuncional_35.gif"

"60programacionfuncional_36.gif"

En el siguiente ejemplo el comando "Apply" se escribe en la notación infija @@

"60programacionfuncional_37.gif"

"60programacionfuncional_38.gif"

Finalmente una mejor forma de sumar todos los números en una lista larga

Al principio de este documento una lista larga de números aleatorios fue generada y guardada en la variable millionNumbers.
Este es el tercer número de una lista larga:

"60programacionfuncional_39.gif"

"60programacionfuncional_40.gif"

Y esta es la suma de todos los números en esa lista: simplemente reemplazando la cabeza List con la cabeza Plus, y la expresión evoluciona por sí sola al resultado:

"60programacionfuncional_41.gif"

"60programacionfuncional_42.gif"

Exactamente lo mismo usanod la notación @@

"60programacionfuncional_43.gif"

"60programacionfuncional_44.gif"

Comparando las dos formas de sumar un millón de números

Tenemos una lista de números llamada millionNumbers que fue generada al principio de este documento, y compararemos las dos formas de sumar todos los números en la lista. Usaremos el comando Timing, que reporta el "tiempo de CPU" usado por el Kernel de Mathematica para hacer los cálculos.
Primero con el ciclo For:

"60programacionfuncional_45.gif"

"60programacionfuncional_46.gif"

Ahora con Apply:

"60programacionfuncional_47.gif"

"60programacionfuncional_48.gif"

Ahora con la notación infija @@

"60programacionfuncional_49.gif"

"60programacionfuncional_50.gif"

Como puedes ver, el enfoque funcional con el comando Apply es mas de diez veces más rápido. Las principales razones para esta diferencia es que en el enfoque funcional Mathematica no tiene que comparar, modificar y guardar la variable j del ciclo For, y tampoco tiene que acceder a los elementos de la lista uno por uno.
Sin embargo, aún no hemos visto la forma más rápida de sumar los números en esta lista.

La mejor y más rápida manera de simar todos los números en una lista: el comando especializado Total[]

La variable millionNumber contiene una lista de 1000000 números aleatorios que fueron generados al principio de este documento.
La forma más rápida de sumar todos esos números es usar el comando Total:

"60programacionfuncional_51.gif"

"60programacionfuncional_52.gif"

Como puede ver, Total es tan rápido para sumar todos los números en la lista, que el tiempo de CPU no pudo ser medido.

¿Qué podemos aprender de todos estos ejemplos?

Muchas veces la programación por procedimientos y ciclos For es la forma más lenta de implementar un cálculo en Mathematica.
La programación funcional suele ser más rápida, y los programas funcionales son usualmente muy pequeños.
Comandos especializados, como Total, pueden ser mucho más rápidos que la programación de cualquier tipo.

¿Qué sigue?

Apply es el más sencillo de una serie de comandos de programación funcional que existe en Mathematica.
Aquí tienes ejemplos de otros comandos de programación funcional:

ReplaceAll /.

"60programacionfuncional_53.gif"

"60programacionfuncional_54.gif"

Composición de funciones @

"60programacionfuncional_55.gif"

"60programacionfuncional_56.gif"

Apply @@

"60programacionfuncional_57.gif"

"60programacionfuncional_58.gif"

Apply al nivel 1 @@@

"60programacionfuncional_59.gif"

"60programacionfuncional_60.gif"

Map /@ (compara @@@ con /@)

"60programacionfuncional_61.gif"

"60programacionfuncional_62.gif"

Map a pure Function (#,&)

"60programacionfuncional_63.gif"

"60programacionfuncional_64.gif"

Map a pure Function (Function)

"60programacionfuncional_65.gif"

"60programacionfuncional_66.gif"

Distribución de operadores (cabezas) a un mismo argumento:

"60programacionfuncional_67.gif"

"60programacionfuncional_68.gif"

Aplicación repetida (anidada) de una función:

"60programacionfuncional_69.gif"

"60programacionfuncional_70.gif"

Construcción de una fracción

"60programacionfuncional_71.gif"

"60programacionfuncional_72.gif"

Aplicación repetida (anidada) del logaritmo natural mientras el resultado sea mayor que cero:

"60programacionfuncional_73.gif"

"60programacionfuncional_74.gif"

Aplicación repetida (anidada) del logaritmo natural mientras el resultado sea mayor que cero:

"60programacionfuncional_75.gif"

"60programacionfuncional_76.gif"

Aplicación repetida (anidada) del logaritmo natural mientras el resultado sea mayor que cero, juntando todos los resultados intermedios en una lista

"60programacionfuncional_77.gif"

"60programacionfuncional_78.gif"

Aplicación repetida (anidada) de la función f, en cada ocasión con un segundo argumento diferente:

"60programacionfuncional_79.gif"

"60programacionfuncional_80.gif"

Construcción de una fracción

"60programacionfuncional_81.gif"

"60programacionfuncional_82.gif"

"60programacionfuncional_83.gif"
Autor: José Luis Gómez Muñoz

     Global Computing S. A. de C. V.
Florencia 57 Piso 10-01
Col. Juárez C.P. 06600
México D.F.
México
+52-(0)55-5525-2215
Fax: +52-(0)55-5514-4225

Adriana Vadillo avadillo@mx.inter.net

Hector Vadillo  hector.vadillo@prodigy.net.mx

http://www.globalcomputing.com.mx/

Spikey Created with Wolfram Mathematica 6