You are on page 1of 7

,

PROGRAMACION
FUNCIONAL:
CONCEPTOS
y PERSPECTIVAS
Fabio Augusto Gonzle: Osorio
Instructor Asociado
Departamento de Ingeniera de Sistemas
Universidad Nacional de Colombia
fgonza@ ingenieria. ingsala. unaLedu.co.

Resumen
El presente artculo muestra conceptos
subyacentes a la programacin funcional, as como
caractersticas que los hacen un enfoque particular
y novedoso de la programacin que lo convierten
en una clara opcin frente al enfoque imperativo
convencional en el rea del desarrollo de software.

INTRODUCCIN
El estilo de programacin imperativa (es decir,
la programacin a travs de acciones que modifican
el estado del computador) ha dominado el panorama
de la programacin desde sus inicios; los lenguajes
de ms amplio uso estn basados en este paradigma:
Fortran, e, C++, Pascal, Basic, etc. Una razn
fundamental de este dominio reside en que los
lenguajes imperativos son ms cercanos a la forma
como realmente funciona la mquina.

---------=-~.::..:....:..:.

Existen otros paradigmas de programacin


diferentes al imperativo como la programacin
funcional y la programacin lgica, cuyo estudio,
desarrollo
y uso han estado principalmente
restringidos al mbito acadmico. La programacin
funcional, es casi tan antigua como la imperativa; el
primer lenguaje funcional, LlSP, fue desarrollado en
la misma poca en la que se desarroll FORTRAN.
Sin embargo, la programacin funcional ha estado
tradicionalmente circunscrita a reas de aplicacin
especficas como la inteligencia artificial y la
computacin simblica.
A pesar de la hegemona de la programacin
imperativa la programacin funcional cada vez toma
ms fuerza gracias a su capacidad expresiva, que
permite escribir programas ms compactos, y a su
transparencia referencial que posibilita la sencilla
verificacin matemtica de propiedades de los

INGENIERA

E INVESTIGACIN

11

programas. Igualmente, caractersticas como la


recoleccin automtica de basura, los sistemas de
inferencia de tipos, el polimorfismo, la orientacin a
objetos, el emparejamiento
de patrones, los
algoritmos eficientes de compilacin,
se han
desarrollado gracias al gran trabajo investigativo
de los ltimos aos.
Todo lo anterior permite ubicar a la
programacin
funcional como una importante
opcin para el desarrollo de software que facilite
hacer realidad los ideales de la ingeniera de software
como son: la reusabilidad, la modularidad, la
mantenibilidad y la correccin[3].
En el presente artculo se pretende mostrar
las ideas subyacentes a la programacin funcional,
as como ilustrar las caractersticas que la hacen un
enfoque particular y novedoso de la programacin.
De igual manera, se hablar brevemente de su
historia desarrollo y perspectivas.
I. QU ES LA PROGRAMACIN
FUNCIONAL?
Una definicin de programacin
generalmente aceptada es la siguiente:

funcional

"El estilo de programacin que enfatiza la


evaluacin de expresiones, antes que la ejecucin
de comandos "[6].
La definicin anterior es bastante amplia y tal
vez ambigua, pues no se precisa a qu se refiere el
nfasis del cual habla. Esto refleja la frontera difusa
que existe entre lenguajes funcionales puros y
lenguajes no funcionales; en esta frontera se ubican
lenguajes como LISP, SCHEME y ML, que nadie
dudara en catalogar como funcionales a pesar de
que tienen caractersticas
no puras como
asignaciones y efectos laterales, a diferencia de los
lenguajes funcionales puros, los cuales desarrollan
todos su cmputos exclusivamente a travs de la
aplicacin de funciones.
Una programa funcional est constituido
enteramente por funciones; el programa principal
es una funcin que toma como argumento la entrada
al programa y genera la salida del programa como
su resultado. Tpicamente, la funcin principal se

define en trminos de otras funciones, y stas, a su


vez, en trmino de ms funciones; esta cadena
finaliza en funciones predefinidas o primitivas.
A simple vista, un programa en lenguaje C se
ajustara a la definicin de programa funcional (de
hecho algunas personas consideran que el C es un
lenguaje funcional); sin embargo, la principal
diferencia de los programas funcionales puros
respecto
a los programas
convencionales
(imperativos)
es que los nicos elementos
constructores en los primeros son la definicin y la
aplicacin de funciones, mientras que en los
programas imperativos se utilizan, adems, variables,
asignaciones ciclos iterativos, etctera.
Parece muy restrictivo el hecho de no poder
utilizar variables, ni asignaciones,
ni ciclos
iterativos;
sin embargo
se ha demostrado
matemticamente que la definicin y la aplicacin
de funciones era suficiente para construir cualquier
funcin computable' .
Para ilustrar la diferencia entre el enfoque
imperativo y el funcional considrese el problema
de construir una funcin f que reciba como
argumento un natural n y retome la suma de los
naturales desde 1 hasta n, es decir:
n

f (n)=L i
;=1

En un lenguaje imperativo como C, se podra


definir la funcin de la siguiente forma:
int f(int n)
{
int i;
intsuma=O;
for (i=l; i<=n; i++)
suma=suma+ i;
retum suma;

1. Elfundamento de los lenguajes funcionales es el clculo


lambda, desarrollado por Haskell Curry en la dcada del
30. Es un clculo de funciones basado en la abstraccin y
la aplicacin. Curry demostr que las funciones definibles
dentro de este clculo corresponden a las computables por
una mquina de Turing[lJ.

-~______;__;______;__;----

INGENIERA

E INVESTIGACIN

La implementacin de esta funcin en un


lenguaje funcional definitivamente exigira otra
estrategia, pues en estos lenguajes no se cuenta
con variables, ni asignaciones, ni ciclos. Por tanto,
se recurrir a una definicin recursiva- equivalente
def
O
sin=O
f(n)= { f(n - 1)+ n
en otro caso
Que en el lenguaje como CAML se vera de la
siguiente forma:
let rec f= fun

comporta asintticamente como fib (n) lo cual se


nota como t(n) = O(fib (n))). Una mejor opcin sera
calcular fib (n) de manera iterativa, es decir,
generando fib {J), fib (2), fib (3), etc, hasta llegar
al fib (n) (en cada paso se utilizan los dos ltimos
valores para generar el siguiente valor); el tiempo
de ejecucin de este algoritmo t' (n) se comporta
asintticamente como n (t'(n)=O(n)), es decir el
tiempo es una funcin lineal del argumento de la
funcin, el cual es claramente mejor que el tiempo
del algoritmo recursivo.
A continuacin se muestra 1a implementacin
del algortmo iterativo (realmente iterativo recursivo)
enCAML:

0-> O
I n-> f(n -1)+ n;;

EnSCHEME
(define f(lambda (n)(if(n=O)O (+(j(-n ln
En HASKELL (esta es una versin
recursiva, pero bastante elegante!):

no

letrec fibaux (n, cont,pen,ult) =


if (cont>=n ) then ult
else fibaux (n, cont+ 1, ult, pen+ult);;
let rec fib n = fibaux (n, 2,1,1 );;
II. DNDE RESIDE LA POTENCIA
DELA PROGRAMACIN FUNCIONAL?

n= sum [l..n]

La ineficiencia de la recursin para resolver


ciertos problemas es conocida; esto podra verse
como un grave inconveniente para la programacin
funcional la cual hace uso extensivo de la misma,
sin embargo, algoritmos iterativos pueden similarse
a travs de la recursin. Para mostrar esto,
analicemos el tpico algoritmo que calcula el n-simo
trmino de la sucesin de Fibonnaci, la cual se define
como:

La potencia de la programacin funcional


depende de varias caractersticas que poseen los
lenguajes funcionales; entre ellas: el manejo de
funciones de alto orden, la declaracin de tipos
algebraicos, la inferencia de tipos, el emparejamiento
de patrones y el manejo automtico de la memoria
dinmica.

let rec fib = fun 1 -> 1


I 2 -> 1
I n -> fib (n - 1)+ fib (n - 2);;

Estas caractersticas no son exclusivas de los


lenguajes
funcionales;
en el caso del
emparejamiento
de patrones esta facilidad fu
tomada de Prolog. El manejo automtico de la
memoria dinmica, aunque tiene su origen en un
lenguaje funcional,LISP, hoy en da lo poseen
lenguajes imperativos como JAVA; sin embargo
todas estas caractersticas
han estado ligadas
estrechamente al desarrollo de la programacin
funcional.

Este programa, aunque bastante fiel a la


definicin matemtica de la funcin, es demasiado
ineficiente, pues su tiempo de ejecucin t (n) se

A continuacin se describirn los elementos


caractersticos ms relevantes de la programacin
funcional.

fib(n) =~b(n

- 1) ~ fib(n - 2)

si n=lvn=2
en otro caso

Un programa en CAML calcularfib (n) seria:

2. Valga la pena aclarar que existe una solucin mucho


ms sencilla: emplear lafrmulaf(n)=n(n+l)/2. La frmtda
recursiva se presenta con fines puramente ilustrativos.

INGENIERA

E INVESTIGACIN

A. Funciones

de alto orden

en CAML que nos permita obtener la versin


'currificada' de una funcin con dos argumentos:

El concepto "alto orden" se refiere a funciones


que reciben como argumento o retoman funciones,
es decir, las funciones pueden manipulase como
datos; esta caracterstica tambin es referida como
"funciones como objetos de primera clase."
Por ejemplo, podramos utilizar la siguiente
definicin de la derivada de una funcin!
f'(x)=

Lim
h~oo

f(x+h)-f(x)
h

(fun x -> ([uny-> f(x,y)));;

Utilicemos la funcin curry aplicada sobre


deriva para construir
una funcin g' que
corresponda a la derivada de g (x )=x"2-1:
letgx =x *. x-l.O;;
let g' = (curry deriva) g ;;
El proceso de evaluacin de g' 3. O sera:

para construir una funcin deriva que nos


aproxime la derivada de cualquier funcin
fjloat ~ float
let deriva (f,x)

let curryf=

g' 3.0= => ((curry deriva)g) 3.0


==> (tfun x -> (fun y ->deriva(x,y))) g) 3.0
==> (fun y -> deriva (g,y)) 3. O
==> deriva (g, 3.0)

([(x +. 0.00 l) -. f(x) ) /. 0.00 It;'

En este caso, f sera una funcin que es


recibida como argumento por deriva; por lo tanto,
deriva sera una funcin de alto orden. En el
siguiente ejemplo:
let gx = x*. x -. 1 . O in deriva (g, 3. O);;
Est calculndose una aproximacin
derivada de g(x) =x2-l calculada en x= 3.

B. Tipos algebraicos
Los lenguajes funcionales con tipos como
ML y Haskell dan la posibilidad de declarar tipos
adicionales a los tipos primitivos (int, char, float,
etc.). Los tipos declarados por el usuaro se definen
mediante constructores como la enumeracin:

de la
let direccin = norte

Un concepto asociado a las funciones de alto


orden es el de currying, el cual tiene su origen en el
estudio matemtico de funciones. En pocas palabras,
este concepto sugiere que es suficiente estudiar
funciones de un solo argumento. Por ejemplo,
considere la funcinf(x,y) =x+y, la cual puede ser
expresada como una funcin g tal que g (x) es una
funcin que al ser aplicada sobre y nos retoma x+y,
es decir (g(x))(y)= x+y; implementado en CAML
quedara:
let g x

= fun

y -> x+y ;;

E 1 proceso de evaluacin para g 3 4 es:


g 34 ==> (funy

sur

oriente

occidente;;

...el producto cartesiano de tipos ya definidos


o primitivos:
let racional = fraccion of int *int;;
y definiciones recursivas:
let lista = vacia

cons ofint *lista ;;

En el primer caso, se define un tipo que solo


posee cuatro valores posibles; en el segundo
ejemplo, el tipo racional se construye como el
producto cartesiano del tipo primitivo int; valores
como fraccin (3, 4) r fraccin (-4, 2), etc.,

-> 3+y) 4 ==> 3+4 ==> 7

En general, dada una funcinf(x,y), el proceso


de currying consiste en construir una funcin g tal
que g (x)(y) =j{x, y). Podemos construir una funcin

1IIII~~fN~G~E_~_E_Rl_'~A~E~~
__E~S~T~IG~A~C_IO~'N

3. En CAML, los operadores aritmticos seguidos de un


punto (+. -. *. 1. ) se refieren a operadores sobre reales; el
punto los distingue de los operadores respectivos sobre
enteros[IOj.

___

pertenecen a este tipo. Fraccin es un constructor


que no se ha declarado previamente.
En el ltimo ejemplo se emplea el tipo lista
dentro de su propia definicin; concretamente se
dice que una lista puede ser vacia o el 'cons' de un
entero con una lista ya existente; en este caso 'cons'
se puede entender como la operacin de adicionar
un entero la cabeza de la lista. Ejemplos de elementos
del tipo lista son:
vaca
cons (5, vaca)
cons ( 3, cons (9, cons ( 1, vaca)))
Como puede observarse,
el nmero de
elementos pertenecientes al tipo lista es infinito;
esto es, efecto directo del carcter recursivo de su
definicin. Precisamente esta caracterstica, la
recursividad es la que le da el nombre de algebraico
al sistema de tipos y le permite al programador definir
y manejar estructuras bastante complejas, sin
necesidad de manipular apuntadores; esto elimina
la gestin directa de la memoria dinmica y, por tanto
obvia, una gran fuente de errores.
Otro ejemplo de tipo recursivo es el de rbol
type arbolbi = vado

nodo ofint*arbo1bi*arbolbi;;

En este caso estn representndose el tipo


de rboles binarios con etiquetas enteras en sus
nodos. El siguiente rbol:

1O

let rec Suma

= fun

vaca
-> O
cons (cabeza, resto) -> cabeza
+ Suma (resto);;

Aqu estn definindose


dos patrones
posibles C'vacia" y "cons (cabeza, resto)") que
pueden tomar el argumento enviado a suma; el
compilador trata de emparejarlo con cada uno. En
caso de conseguirlo,
ejecuta el cdigo a
continuacin de la flecha (- .
Por ejemplo, en caso de evaluar Suma
cons(5, cons(2, cons(8, vacia))) , el compilador
empareja el argumento con el segundo patrn
("cons (cabeza, resto)'') haciendo cabeza=5 y
resto=cons(2, cons(8, vacia)); la evaluacin de la
expresin continuara as:
Suma
=> 5
=> 5
=> 5

cons (5, cons (2, cons (8, vacia) ) )

+ Suma cons (2, cons (8, vacia) )


+ 2 + Suma cons (8,vacia)
+ 2 + 8 + Suma vacia (en este caso se empareja

el

patrn)

=> 5 + 2 + 8 + O
D.Inferencia

Se representa mediante la siguiente expresin


de tipo arbolbi:
nodo (10, nodo (2, vacio, nodo (1, vacio, vacioi),
nodo (5, vacio, vacio))
de patrones

El emparejamiento de patrones (en ingls


Pattern Matching), se refiere a la posibilidad que
brindan algunos lenguajes funcionales de definir

Un ejemplo de definicin de una funcin


utilizando emparejamiento de patrones es la funcin
fib recursiva del numeral 1. Otro ejemplo es la
siguiente definicin de la funcin Suma que calcula
el tamao de una lista de enteros segn la
definicin del tipo lista dada en el apartado B. del
numeral 11.

primer

/ \
2 5
\

C. Emparejamiento

funciones por casos; esto le da mayor capacidad


expresiva al lenguaje permitiendo escribir el cdigo
ms claro, sencillo y conciso.

de tipos

Tradicionalmente, los sistemas de tipos de


los lenguajes de programacin se han dividido en
dos: estrictos y no estrictos. En el primer caso, el
programador debe declarar el tipo de cada una de
las variables y de los argumentos de las funciones
y procedimientos, y ceirse de manera estricta a
estas declaraciones;
en el segundo caso, el
programador no debe ceirse necesariamente a las
declaraciones' y eventualmente las puede obviar,
como cuando a una funcin declarada en C que
recibe un entero, se le enva como argumento un
nmero de punto flotante.

~:.:....:....=..~II
INGENIERA

E INVESTIGACIN

La experiencia ha demostrado que los sistemas


de tipos estrictos son preferibles a los no estrictos,
pues favorecen la depuracin sencilla del cdigo al
eliminar en tiempo de compilacin muchos errores
potenciales; sin embargo pueden resultar muy
engorrosos para el programador por su falta de
flexibilidad.
Los sistemas
de inferencia
de tipos
representan un punto intermedio entre los dos
esquemas mencionados anteriormente. Por un lado,
conservan el carcter estricto del sistema de tipos y
por otro liberan al programador de declaraciones
explcitas de los tipos de los argumentos de las
funciones y de sus valores de retomo. Esto puede
parecer contradictorio, pero la clave est en que el
compilador hace el trabajo de asignacin de tipos
por el programador y, lo que es mejor, lo hace de la
manera ms general posible, es decir, evidenciando
la genericidad y el polimorfismo cuando stos tienen
cabida dentro de una funcin.
Por ejemplo, al introducir la funcin Suma
definida en el apartado e del numeral Il.C, el intrprete
de eAML responde con el siguiente mensaje:
Suma: lista -> int = <fun>
Lo cual est indicndonos que la funcin
Suma recibe como argumento un dato del tipo lista
y retoma como resultado un entero; esto es inferido
por el intrprete de manera automtica.
En el caso de una funcin como la siguiente:
lel primero (x, y) = x;;
La cual de una pareja de datos nos retoma el
primero, puede ser aplicada a parejas de diferentes
tipos de datos; por tanto, el sistema de tipos debe
inferir el tipo ms general posible y ste es:
primero:

a'

* b ' -> a'

Donde a' y b ' se refieren a cualquier tipo, es


decir, son variables de tipo que nos indican el
carcter general de la funcin. El tipo inferido por el
4. En lenguajes como LISP ni siquiera existe el concepto
de tipo, todos los datos son compatibles entre s; ste es el
caso extremo.

1I__

IN_G_EN_I_E_Rl_'A_E_IN_V_E_ST_I_G_A_C_IO_'N

intrprete para la funcin curry definida


apartado A del numeral 11.es:

en el

curry :(a' *b' -> c') -> (a' -> (b' -> c'))
el cual evidencia el alto orden de la funcin, pues
sta recibe como parmetro una funcin de tipo (a'
*b' -> c') y retoma una funcin (tambin de alto
orden) de tipo (a' -> (b' -> c')).
PERSPECTIVAS Y CONCLUSIONES
Las caractersticas que hemos ilustrado de
hasta ahora evidencian el gran potencial de los
lenguajes funcionales como herramientas que les
facilite a los programadores enfrentar la complejidad
creciente del desarrollo de software; esto nos
permite afirmar que en los prximos aos los
lenguajes funcionales tomarn un lugar en el rea
de desarrollo de software a gran escala, aliado de
lenguajes tan tradicionaies como e, e++,ADA [3,4].
La afirmacin anterior se sustenta con los siguientes
puntos:
Transparencia referencial. Este concepto
se refiere a la propiedad de los lenguajes
funcionales que hace que la misma expresin
siempre represente el mismo valor; esto
permite probar matemticamente la correccin
de un programa. La posibilidad de escribir
programas cuya correccin es probable en
vez de gastar el tiempo pescando errores
puede
revolucionar
el proceso
de
produccin de software.
Fundamentacin matemtica. Desde sus
inicios, la programacin funcional ha tenido
un gran componente matemtico, el clculo
Lambda, la lgica combinatoria, las teoras
de tipos, los sistemas de reescritura, la teora
de dominios y la teora de categoras son
algunas de las reas de la matemtica que la
fundamentan.
Esto le da pilares suficientemente slidos que le permiten ser la
base del desarrollo de una verdadera ciencia
de la programacin.
Eficiencia de compiladores e intrpretes.
Uno de los inconvenientes
que tradicionalmente se le ha achacado a los lenguajes
funcionales
es la ineficiencia
de sus

intrpretes y compiladores. Hoy da, esto no


representa un problema pues los avances
investigativos han permitido la construccin
de compiladores que generan cdigo nativo
que iguala en eficiencia el cdigo generado
por compiladores
convencionales
(C,
Fortran, etctera.).
Paralelismo Implcito. El hecho que los
lenguajes funcionales (puros) no permitan
efectos laterales ni el uso de variables
globales,
hace que la evaluacin
de
diferentes expresiones constituyan procesos
independientes y, por tanto, que pueden ser
ejecutados de manera simultnea. Esta
caracterstica
puede ser explotada para
programar computadores
paralelos de
manera natural algo que no se ha logrado de
manera satisfactoria
a travs de la
programacin convencional.

BIBLIOGRAFA

l. CURRY H., FEYS R. Combinatory Logic,- NorthHolland , 1958.


2. DYBVIG K. The Scheme programming
language. Addisson- Wesley 1996.
3. HUGHES J.Why functional
programming
matters.The computer Journal, vol. 32 N 2. Abril
1989.
4.

POUNTAIN.
D. "Functional
programming
comesof
age ": BYTE, Agosto de 1994

5. SETHI R. Programming
Wesley 2 Ed ., 1996.
Pginas

languages,

Addisson-

en internet

Preguntas

frecuentes

de comp. lang functional

6. http://www.cs.nott.ac.uk/Department/Staff/
gmb/faq. html
Programacin

funcional

7. http://cm-bell-Iabs.com/cm/cs/who/wad
guide.html
8. http://www.lpac.ac.uklSELFuncArchive.html

ler/

HPC/Articles/

9. http://carol.fwi.uva.nl/-:jon/func.html
Lenguajes
10. CAML:
html

http://pauillac.inria.fr/camllindex-eng.

11. Haskell: http://www-i2


informatik.rwthaachen.de/Forschung/FP/Haskell/
12. Scheme:

________

http://ai.mit.edu

INGENIERA

E INVESTIGACIN

11
1

You might also like