Vous êtes sur la page 1sur 25

Programación funcional

En ciencias de la computación, la programación funcional es un paradigma de


programación declarativa basado en la utilización de funciones aritméticas que no
maneja datos mutables o de estado. Enfatiza la aplicación de funciones, en
contraste con el estilo de programación imperativa, que enfatiza los cambios de
estado. La programación funcional tiene sus raíces en el cálculo lambda, un sistema
formal desarrollado en los años 1930 para investigar la definición de función, la
aplicación de las funciones y la recursión. Muchos lenguajes de programación
funcionales pueden ser vistos como elaboraciones del cálculo lambda.

En la práctica, la diferencia entre una función matemática y la noción de una


"función" utilizada en la programación imperativa es que las funciones imperativas
pueden tener efectos secundarios, al cambiar el valor de cálculos realizados
previamente. Por esta razón carecen de transparencia referencial, es decir, la
misma expresión sintáctica puede resultar en valores diferentes en diferentes
momentos dependiendo del estado del programa siendo ejecutado. Con código
funcional, en contraste, el valor generado por una función depende exclusivamente
de los argumentos alimentados a la función. Al eliminar los efectos secundarios se
puede entender y predecir el comportamiento de un programa mucho más
fácilmente, y esta es una de las principales motivaciones para utilizar la
programación funcional.

Los lenguajes de programación funcional, especialmente los que son puramente


funcionales, han sido enfatizados en el ambiente académico principalmente y no
tanto en el desarrollo de software comercial. Sin embargo, lenguajes de
programación importantes tales como Scheme, Erlang, Rust, Objective Caml y
Haskell, han sido utilizados en aplicaciones comerciales e industriales por muchas
organizaciones. La programación funcional también es utilizada en la industria a
través de lenguajes de dominio específico como R (estadística), Mathematica
(matemáticas simbólicas), J y K (análisis financiero), F# en Microsoft.NET y XSLT
(XML). Lenguajes de uso específico usados comúnmente como SQL y Lex/Yacc,
utilizan algunos elementos de programación funcional, especialmente al procesar
valores mutables. Las hojas de cálculo también pueden ser consideradas lenguajes
de programación funcional.

La programación funcional también puede ser desarrollada en lenguajes que no


están diseñados específicamente para la programación funcional. En el caso de
Perl, por ejemplo, que es un lenguaje de programación imperativo, existe un libro
que describe como aplicar conceptos de programación funcional. JavaScript, uno de
los lenguajes más ampliamente utilizados en la actualidad, también incorpora
capacidades de programación funcional. Python también incorpora particularidades
de los lenguajes funcionales como listas de comprensión y funciones de tratamiento
de listas como matemática de conjuntos.

Características
En ciencias de la computación, la programación funcional es un paradigma de
programación declarativa basado en la utilización de funciones aritméticas que no
maneja datos mutables o de estado. Enfatiza la aplicación de funciones, en
contraste con el estilo de programación imperativa, que enfatiza los cambios de
estado. La programación funcional tiene sus raíces en el cálculo lambda, un sistema
formal desarrollado en los años 1930 para investigar la definición de función, la
aplicación de las funciones y la recursión. Muchos lenguajes de programación
funcionales pueden ser vistos como elaboraciones del cálculo lambda.

En la práctica, la diferencia entre una función matemática y la noción de una


"función" utilizada en la programación imperativa es que las funciones imperativas
pueden tener efectos secundarios, al cambiar el valor de cálculos realizados
previamente. Por esta razón carecen de transparencia referencial, es decir, la
misma expresión sintáctica puede resultar en valores diferentes en diferentes
momentos dependiendo del estado del programa siendo ejecutado. Con código
funcional, en contraste, el valor generado por una función depende exclusivamente
de los argumentos alimentados a la función. Al eliminar los efectos secundarios se
puede entender y predecir el comportamiento de un programa mucho más
fácilmente, y esta es una de las principales motivaciones para utilizar la
programación funcional.

Los lenguajes de programación funcional, especialmente los que son puramente


funcionales, han sido enfatizados en el ambiente académico principalmente y no
tanto en el desarrollo de software comercial. Sin embargo, lenguajes de
programación importantes tales como Scheme, Erlang, Rust, Objective Caml y
Haskell, han sido utilizados en aplicaciones comerciales e industriales por muchas
organizaciones. La programación funcional también es utilizada en la industria a
través de lenguajes de dominio específico como R (estadística), Mathematica
(matemáticas simbólicas), J y K (análisis financiero), F# en Microsoft.NET y XSLT
(XML). Lenguajes de uso específico usados comúnmente como SQL y Lex/Yacc,
utilizan algunos elementos de programación funcional, especialmente al procesar
valores mutables. Las hojas de cálculo también pueden ser consideradas lenguajes
de programación funcional.
La programación funcional también puede ser desarrollada en lenguajes que no
están diseñados específicamente para la programación funcional. En el caso de
Perl, por ejemplo, que es un lenguaje de programación imperativo, existe un libro
que describe como aplicar conceptos de programación funcional. JavaScript, uno de
los lenguajes más ampliamente utilizados en la actualidad, también incorpora
capacidades de programación funcional. Python también incorpora particularidades
de los lenguajes funcionales como listas de comprensión y funciones de tratamiento
de listas como matemática de conjuntos.

El Lisp y el paradigma funcional

Una vez descrito el paradigma declarativo, vamos a comentar rápidamente algunas


notas sobre la historia del Lisp. El Lisp es el lenguaje más importante del paradigma
funcional. De él nacen una enorme variedad de dialectos, de los que Scheme es
uno de los más extendidos en ámbitos académicos en la actualidad

El cálculo lambda.

La principal base teórica del paradigma funcional es el cálculo lambda (lambda


calculus en inglés) desarrollado en la década de los 30 por Alonzo Church como
modelo de computación con el mismo poder computacional que una Máquina de
Turing.

El cálculo lambda proporciona una notación muy simple (pero bastante críptica al
mismo tiempo) de definición de funciones matemáticas. Sólo son necesarias tres
reglas sintácticas para definir las expresiones del cálculo lambda

Lenguaje
El lenguaje LISP

“LISP is an easy language to learn” (Henry et al 1984) (Henry et.al., 1984)

Introducción

z Origen: 1958 z John McCarthy, pionero en IA, empezó t b j l ia trabajar con la


primera implementación de Lisp en 1958. » McCarthy, Recursive functions of
symbolic i d th i t ti bexpress ions and their computation by machine,
Communications of the ACM, Vol 3, No 4, 1960.

Introducción
z Uso habitual en Inteligencia Artificial z LISt Processing z Características básicas »
Lenguaje Interpretado – También posible compilado » Todas las variables son
punteros » Liberación automática de memoria (automatic garbage collection) Efi i i l
j» Eficiencia menor que otros lenguajes (causas: es interpretado, liberación
automática de memoria, ...). » Adecuado para prototipados y cálculo » Adecuado
para prototipados y cálculo simbólico. z Nuevo paradigma de programación:
programación funcional

programación funcional

Datos

z Expresiones LISP: » Átomos Símbolos:– Símbolos: z simbolo, simbolo3,ejemplo-


de-simbolo z Especiales: nil, t – Keywords (étiquetas): z :ejemplo, :keyword – Strings
(distinción minúsculas-mayúsculas) z “abc”, “ABC”, “string” Números:– Números: z
enteros: 33, 4, -5 z racionales: -3/5, 4/8 z reales: 3.23, -4.78, 3.33E45 » Listas –
Colecciones de expresiones – (a b (c (d)) e), (), (3 “abc”)

Listas: Grupo de átomos. Las listas también se pueden agrupar en niveles


superiores.

Evaluación

z Forma LISP: cualquier expresión evaluable (expresión LISP) z Evaluación » Una


expresión es evaluable cuando devuelve un valor » Una expresión es evaluable
cuando devuelve un valor z Distinción entre operadores » Funciones: evalúan todos
sus argumentos » Macros: no evalúan todos los argumentos – QUOTE QUO z
Macro: no evalúa su argumento (quote (a b c)) >>> (A B C) z ‘(a b c) equivale a
(quote (a b c)) z Ejemplos de evaluaciones Á» Átomos – Símbolos: z Su evaluación
es su valor como variable z T y NIL se evalúan a sí mismos – Números, Strings y
Keywords z Se evalúan a sí mismos » Listas – () se evalúa a NIL – Una lista no
vacía evaluable debe tener como primer elemento un símbolo

z (+ 3 (+ 2 5)) z (quote (a b c)) z (setf variable (+ 3 4))

Notación prefijo. El primer elemento de una lista indica qué se desea hacer

6
Operadores de manipulación de listas, I

z El macro SETF admite como primer argumento: U í b l» Un símbolo: – (setf dias


‘(lunes martes miercoles)) » Una posición de memoria: – (setf (second dias)
‘jueves)) – (setf (second dias) jueves)) – dias >>> (LUNES JUEVES MIERCOLES)

– (setf (rest dias) ‘(viernes domingo)) Atención! Lista modificada! – dias >>> (LUNES
VIERNES DOMINGO) – (setf (rest dias) dias) >>> (LUNES LUNES ....) z ¡Cuidado!,
listas circulares

(setf [<var1> <valor1>] ... [<varn> <valorn>]) Sirve para: • Asignar valores a
variables

• Modificar valores de componentes de listas, variables, etc.

Operadores de manipulación de listas, II

z Características comunes: » Al evaluarlos, se obtiene error cuando se aplican sobre


datos que no siguen su aplican sobre datos que no siguen su patrón sintáctico. » La
mayoría son funciones (no macros). z FIRST o CAR » Devuelve el primer elemento
de la lista » (first <lista>) » (first ‘(a b c)) >> A S COz SECOND, THIRD, ..., NTH »
(second <lista>) – (second ‘(a b c)) >>> B » (nth <expresion> <lista>) » (nth
<expresion> <lista>) – (nth 1 ‘(a b c)) >>> B – Devuelve el elemento en la posición
<expresion> de la <lista> Posición inicial: 0

– Posición inicial: 0 – Si <expresion> excede la dimensión de la lista se devuelve


NIL

Operadores de manipulación de listas, III

z REST o CDR » Devuelve la lista sin el primer elemento ( t li t )» (rest <lista>) »


(rest ‘(a b c)) >> (B C) z NTHCDR » (nthcdr <expresion> <lista>) » (nthcdr (+ 1 1)
‘(a b c)) >> (C) z (car (cdr (car ‘((a b c) d)))) >> B » Es equivalente (cadar ‘((a b c) d))
» C_ _ _ R _ = A (first) o D (rest) z Cómo crear listas? Có o c ea s as » cons »
append » list

» list

9
Operadores de manipulación de listas, IV

z CONS » (cons <expresion> <lista>) » Crea una lista cuyo primer elemento es »
Crea una lista cuyo primer elemento es <expresion> y cuyo resto es <lista> – (cons
‘(a b) ‘(c d e)) >>> ((A B) C D E) (cons ‘a (cons ‘b nil)) : construir una lista, t d l t li t í
z APPEND » (append <lista>*) » (append ‘(a b) ‘(c d)) >>> (A B C D) ( d '( b) '( (d)) '(
f)) (A B C (D) E F) concatenando elementos a una lista vacía » (append '(a b) '(c (d))
'(e f)) >>> (A B C (D) E F) » No destructivo. Crea copia (a primer nivel) de todos los
argumentos menos el último » (append ‘a ‘b ‘c) >>> ? ERROR z LIST » (list
<expresion>*) » (list ‘(a b) ‘(c d)) >>> ((A B) (C D))

» (list '(a b) '(c (d)) '(e f)) >>> ((A B) (C (D)) (E F)) » (list ‘a ‘b ‘c) >>> ? (A B C)

10

Operadores de manipulación de listas, V

z Operadores destructivos: » Suelen ser macros ( tf ‘( b)) ( tf b ‘( d)) ( tf ‘( f))» (setf a


‘(a b)); (setf b ‘(c d)); (setf c ‘(e f)) – NCONC (append). Función. z (nconc a b) >>> (A
B C D) z a >> (A B C D) ; b >>> (C D) ( ) ; ( )

– PUSH (cons). Macro z (push ‘r b) >>> (R C D) b (R C D) Modifica la primera lista z


b >>> (R C D)

– POP. Macro z (pop c) >>> E Introduce elemento. Modifica la lista z c >>> (F) Saca
elemento. Modifica la lista

10

11

Operadores de manipulación de listas, VI

z Otras funciones: – LAST z (last <lista>) z (last <lista>) z (last ‘(a b c)) >>> (C) z
(last ‘((A B) (C D))) >>> ((C D)) Devuelve el último elemento – REVERSE z (reverse
<lista>) z (reverse ‘(a b c)) >>> (C B A) z (reverse '((A B) (C D))) >>> ((C D) (A B))
(del primer nivel de anidamiento) (reverse ((A B) (C D))) ((C D) (A B))

– LENGTH z (lenght <lista>) (l ht ‘( b )) 3 Da la vuelta al primer nivel de la lista z


(lenght ‘(a b c)) >>> 3

– SUBST z (subst <nuevo> <viejo> <lista>) Longitud de la lista, del primer nivel

11

( j ) z (subst ‘a ‘b ‘(a b c)) >>> (A A C)

Sustituir con <nuevo> todas las apariciones de <viejo> en <lista>


12

Otras funciones LISP, I

z PROGN, PROG1 » Permiten escribir instrucciones compuestas (como “{“ y “}” en


el lenguaje C) (como “{“ y “}” en el lenguaje C) » Evalúan todas las sentencias que
contienen y devuelven la última o primera sentencia. » (progn (+ 3 4) (+ 4 5)) >>> 9
» (progn (+ 3 4) (+ 4 5)) >>> 9 » (prog1 (+ 3 4) (+ 4 5)) >>> 7

(progn [<sentencia1>] [<sentenciaN>]) (progn [<sentencia1>]… [<sentenciaN>])

(prog1 <sentencia1> [<sentencia2>]… [<sentenciaN>]) [<sentenciaN>])

progn puede no recibir ningun argumento, entoces devuelve NIL

12

devuelve NIL prog1 tiene que recibir al menos una sentencia

13

Otras funciones LISP, II z PRINT » (PRINT <forma>) » Mostrar información al


usuario » Mostrar información al usuario. » Si el valor de “<forma>” lo llamamos “A”,
el valor es A. Adicionalmente al ejecutarse, también se imprime A p » > (progn (setf
x (print ‘A)) (+ 3 4)) A >>> 7 » >x » > x >>> A z READ » (SETF variable (READ)) »
(SETF variable (READ)) » Leer información del usuario – CL-USER(1): (setf variable
(read)) – HOLA! (lo introduce usuario y pulsa intro)

13

– HOLA! – CL-USER(2): variable – HOLA! – CL-USER(3):

14

Otras funciones LISP, III

z EVAL (en desuso) » Evalúa dos veces una expresión » (eval ‘(+ 3 4)) >> 7 » (eval
(+ 3 4)) >> 7 » (setf a 'b) » (setf b ‘c) » a >> b » b >> c » (eval a) >> c z Operadores
matemáticos p » +, -, *, /, ABS » EXPT – (expt 2 4) >>> 16 MAX MIN» MAX, MIN –
(max 2 3 4 5) >>> 5 » FLOAT – (float 1/2) >>> 0.5

14

() » ROUND – (round 3.2) >> 3

15

Condicionales, I

z El valor lógico de una forma LISP se considera “falso” si su valor LISP es NIL En
caso contrario el valor lógico NIL. En caso contrario, el valor lógico es “verdadero”.
Condicionales: * if * when z IF (macro) » Sintaxis: – (if <expresion> <forma1>
[forma2]) * unless *cond – Si el valor lógico de <expresión> es “verdadero”,
devuelve el valor de <forma1>. Si es “falso”, devuelve el valor de <forma2>. » (if (> 5
(+ 2 2)) (+ 3 3) (+ 3 4)) >>> 6

15

Si se desea que se evalúen varias formas cuando sea cierta o falsa la condición,
qué hacemos?

Usamos progn o prog1

16

Condicionales, II

z WHEN (macro) » Sintaxis: (when <expresion>– (when <expresion> <forma-1>


<forma-2> ...<forma-n>) – Si el valor lógico de <expresión> es “verdadero”, ejecuta
las formas <forma-1>, <forma-2>, ... f d l l fi l l l< forma-n> y devuelve como valor
final el valor de <forma-n>. Si es “falso”, devuelve NIL. » (when (> 5 (+ 2 2)) (+ 3 3)
S j t t d h f lt ( 3 3) (+ 3 4)) >>> 7 Se ejecuta todo, no hace falta poner progn o prog1
No hay parte else! yp

(when <exp> <forma>+) Ù (if <exp> (progn <forma>+))

16

(when <exp> <forma>+) Ù (if <exp> (progn <forma>+))

17

Condicionales, III

z UNLESS (macro) » Sintaxis: (unless <expresion>– (unless <expresion> <forma-1>


<forma-2> ...<forma-n>) – Si el valor lógico de <expresión> es “falso”, ejecuta las
formas <forma-1>, <forma-2>, ... f d l l fi l l l< forma-n> y devuelve como valor final el
valor de <forma-n>. Si es “verdadero”, devuelve NIL. » (unless (> 5 (+ 2 2)) (+ 3 3) (
3 3) (+ 3 4)) >>> NIL unless es el contrario a when Cuando se devuelve NIL, no se
ha ejecutado nada en este caso

17

18

Condicionales, IV

z COND (macro) » Sintaxis: (cond (<condición 1>– (cond (<condición-1> <forma-


11> <forma-12> ...<forma-1-a1>) (<condición-2> <forma-21> <forma-22> ...<forma-
2-a2>) ... (<condición-n> <forma-n1> <forma n2> <forma n an>)) <forma-n2>
...<forma-n-an>)) – Cuando encuentra una <condicion-i> cuyo valor lógico de es
“verdadero”, ejecuta las formas <forma-i1>, <forma-i2>, ... <forma-i-ai> y devuelve
como valor final el valor de devuelve como valor final el valor de <forma-i-ai>. »
(cond ((> 5 7) (+ 3 4) (+ 4 5)) ((> 5 3) (+ 5 6) (+ 6 7))

18

(t (+ 7 8) (+ 8 9))) >>> 13

19

Predicados

z Procedimientos que devuelven T o NIL z Usual calcular el valor lógico de i LISP t


id llexpres iones LISP construidos con ellos. z Tipos de datos: » (<predicado>
<expresion>) » ATOM, STRINGP, NUMBERP, SYMBOLP, LISTP » (atom ‘a) >>> T
; (atom NIL) >>> T Para saber de qué tipo es un dato » (listp ‘a) >>> NIL ; (listp NIL)
>>> T z Numéricos: » Los operandos deben ser números Hoja 1, ejercicio 3 » >, <,
<=, >=, ZEROP, PLUSP, MINUSP, EVENP, ODDP z Identificador listas vacías:

19

» NULL – ¿Es la lista vacía? .¿Es su valor lógico “falso”? – (null (rest ‘(a))) >>> T
Hoja 1, ejercicio 5

20

Predicados de igualdad, I

z EQ, EQL, EQUAL, = z = » (= <numero> <numero>) » (= <numero> <numero>) » (=


3 (+ 2 1)) >>> T; (= 3 3.0) >>> T z EQ » Comprueba igualdad a nivel de punteros
Determina si dos variables ocupan la misma posición de memoria » Ejemplos: –
(setf x ‘(a b 2)) ; (setf y ‘(a b 2)); (setf z x) – (eq x y) >>> NIL ; – (eq (first x) (first y))
>>> T ( q ( ) ( y)) – (eq z x) >>> T z EQL » (eql <exp1> <exp2>) E T d Comprueba
igualdad de átomos – Es T cuando: i. Cuando <exp1> y <exp2> son átomos y ii. (eq
<exp1> <exp2>) se evalúa a T » Ejemplos:

20

1) (eql (cons ‘a nil) (cons ‘a nil)) >>> NIL (falla i) 2) (setf x (cons ‘a nil)) >>> (A) (eql x
x) >>> T

21

Predicados de igualdad, II

z EQUAL » Comprueba a nivel simbólico si dos expresiones son iguales (al


imprimirlas) expresiones son iguales (al imprimirlas) » (equal x y) >>> T » (equal
(first x) (first y)) >>> T » (equal z x) >>> T » (equal z x) >>> T » (equal 3 3.0) >>>
NIL
21

22

Operadores lógicos, I

z AND (macro) » (and <exp1> <exp2> ... <expn>) Si l l ló i d t d l i» Si el valor lógico


de todas las <expi> es “verdadero”, devuelve el valor de la última (<expn>). En caso
contrario, devuelve NIL. » Cuando encuentra alguna <expi> con valor » Cuando
encuentra alguna <expi> con valor lógico “falso”, ya no sigue evaluando el resto de
las <exp>. » (and (evenp 2) (plusp -3) (print 3)) >>> NIL z OR (macro) » (or <exp1>
<exp2> ... <expn>) » Si el valor lógico de alguna de las <expi> Si el valor lógico de
alguna de las expi es “verdadero”, devuelve su valor. En caso contrario, devuelve
NIL. » Cuando encuentra alguna <expi> con valor

22

lógico “verdadero”, ya no sigue evaluando el resto de las <exp>. » (or (evenp 2)


(plusp -3) (print 3)) >>> T

23

Operadores lógicos, II

z NOT » (not <exp>) Si l l ló i d 1 “ d d ”» Si el valor lógico de <exp1> es “verdadero”,


devuelve NIL. En caso contrario devuelve T. » (not (oddp 2)) >>> T » (not (oddp 2))
>>> T » (not (list 2 3)) >>> NIL » (not (oddp 3) >>> NIL

Hoja 1, ejercicio 6

23

24

Variables locales y globales, I

z (setf dias ‘(lunes martes miercoles)) » Es una variable global (puede ser llamada
por el resto de instrucciones) por el resto de instrucciones) z Las variables globales
en LISP se suelen denominar con “*”: *di d l *» *dias-de-la-semana*

24

25

Variables locales y globales, II

z Variables locales » LET (macro) Ejemplo:– Ejemplo: >(prog1 (let ((x ‘a) (y ‘b) z)
(setf z (list x y)) (list z z)) (list 'final 'evaluacion)) >>> ((A B) (A B)) Sintaxis:–
Sintaxis: (let ((<var-1> <valor-inicial-1>) (<var-2> <valor-inicial-2>) ... (<var-n>
<valor-inicial-n>)) <forma-1> <forma-2>
25

.... <forma-m>) LET: asignación de valores en paralelo LET*: asignación de valores


de forma secuencial Se puede: (let* ( (x ‘a) (z x)) …

26

Definición de funciones, I

z Ejemplo: >(defun factorial (numero) (cond ((= numero 0) 1) ( (( ) ) (t (* numero


(factorial (- numero 1)))))) >>> FACTORIAL > (factorial 3) >>> 6 z Sintaxis: Si la
sintaxis está bien, LISP devuelve el nombre de la función. z Sintaxis: (defun
<nombre-funcion> (<lista-argumentos>)

<forma-1> f 2 [(let/let* …] para definir variables locales <forma-2> ... <forma-n>) z


Comentarios: – El valor de la función es el de la última forma (<forma-n>). No se
puede utilizar “return” para devolver el valor de retorno (como en el lenguaje C).

26

– Los argumentos son también variables locales. – Valor de un símbolo como


variable y como función (una variable y una función pueden tener el mismo nombre).

27

Definición de funciones, II

z Argumentos » Número fijo de argumentos: (defun f (x y) (list x y))– (defun f (x y)


(list x y)) – (f ‘a ‘b ‘c) >>> error » Número variable de argumentos (&rest): – Función
LIST (ejemplo de función que tiene ( j p q &rest en su implementación) – (defun f (x
y &rest z) (list x y z)) – (f ‘a ‘b ‘c ‘d) >>> (A B (C D)) (f ‘a ‘b) >>> ? (AB NIL) z tiene
NIL– (f a b) >>> ? » Argumentos opcionales con nombre y valor por defecto (&key):
– (defun f (x y &key (z ‘a) u (v ‘b)) (list x y z u v)) (A B NIL) z tiene NIL ( ( y y ( )
( )) ( y )) – (f ‘a ‘b) >>> (A B A NIL B) – (f ‘a ‘b :z ‘c :v ‘d) >>> (A B C NIL D)

27

&key (<arg1>[<valor1>]) … [(<argN>[<valorN>])]

28

Definición de funciones, III

z Un mismo símbolo se puede utilizar para definir una variable y una función. ( tf f ‘
)» (setf f ‘a) » (defun f (x y) (list x y)) z LISP permite referirse a las funciones o bi b bi
l bien por su nombre o bien por la expresión que las define (caso lambda) z LISP
manipula las funciones como un tipo más de datos. » Las funciones pueden recibir
funciones como argumento » Las funciones pueden devolver como valor de retorno
funciones.
28

Hoja 1, ejercicio 7, 8, 10-13

29

Definición de funciones, IV

z Operadores de iteración » DOTIMES (dotimes (i 3 (list 'final)) (list i i)) >>>


(FINAL)– (dotimes (i 3 (list 'final)) (list i i)) >>> (FINAL) – Sintaxis: (dotimes (<var>
<num-iter> [<valor-retorno]) <forma-1> ... <forma-n>) » DOLIST – (dolist (i (list ‘a ‘b)
(list 'final)) (list i i)) >> (FINAL) – Sintaxis: (d li t ( li t [ l t ]) (dolist (<var> <lista>
[<valor-retorno]) <forma-1> ... <forma-n>) » WHILE – Sintaxis: Sintaxis: (while
<condicion> <forma-1> ... <forma-n>) » LOOP – Sintaxis (la más sencilla):

29

(loop <forma-1> ... <forma-n>) » En todos: (return <expresion>), abandona la


iteración devolviendo <expresion>.

30

Definición de funciones, V

z Ejercicios de iteración >> (dotimes (i 3 (list 'final)) (print i)) 0 0 1 2 (FINAL) » Cómo
sería con while?: (progn (let ((i 0)) (while (< i 3) (while (< i 3) (print i) (setf i (+ i 1)))
(list 'final)))

» Cómo sería con loop? (progn (let ((i 0)) (loop (print i) (setf i (+ i 1))

30

(loop (print i) (setf i (+ i 1)) (if (= i 3) (return))) (list 'final) ))

31

Definición de funciones, VI

z Funciones lambda (anónimas o sin nombre) U b d á t t ili» Un subprograma de


carácter tan auxiliar que no es necesario darle nombre: lambda. (lambda ( <lista-
argumentos> ) <forma-1> <forma-2> ... <forma-n>) T d l t i i ifi d» Todos los
componentes mismo significado que en defun. (count-if Contar los elementos de una
lista que cumplan #'(lambda (x) (eql (first x) 'pantalon) ) '( (medias 20) (falda 10)
(pantalon 40) (medias 1) Valores entre los que contar

31

(pantalon 2) (total 73 )) ) >>> 2

que contar
32

Operadores sobre funciones, I

z FUNCALL » (funcall <funcion> <arg1> ... <argn>) » Son equivalentes: » Son


equivalentes: (f ‘a ‘b) >>> (A B) (funcall #’f ‘a ‘b) Con funcall necesario #’ function
<expresion> Ù #’ <expresion> » (progn (setf funcíon-f #’f) (funcall funcíon-f ‘a ‘b)) »
(funcall #’(lambda (x y) (list x y)) ‘a ‘b) z APPLY » (apply <funcion> (<arg1> ...
<argn>)) » Son equivalentes: (f ‘a ‘b) >>> (A B) (apply #’f ‘(a b)) Diferencia entre
funcall y apply?

Lfdót

32

La forma de cómo se presentan los datos sobre los que se aplica la función, con
apply los datos van dentro de ( y )

33

Operadores sobre funciones, II

z MAPCAR » (mapcar <funcion> <lista1> ... <listan>) Aplicación de funciones a


elementos de listas» Aplicación de funciones a elementos de listas > (mapcar
#’(lambda (x y) (list x x y y)) ‘(a b c) ‘(d e f)) ( )) >>> ((A A D D) (B B E E) (C C F F))

z REMOVE

Qué ocurre si las listas son de distintos tamaños?

Hace lo común

» (remove <elemento> <lista> [:test <funcion-igualdad>]) » Obtener lista a partir de


otra, borrando los elementos que cumplan una condición » (remove ‘b ‘(a b c)) >>>
(A C) – Equivale a (remove ‘b ‘(a b c) :test #’eql) » (remove ‘(a b) ‘(a (a b) c)) >>> (A
(A B) C)

33

» (remove (a b) (a (a b) c)) >>> (A (A B) C) – (remove ‘(a b) ‘(a (a b) c) :test #’equal)


>>> (A C)

Hoja 1, ejercicio 9

Necesario :test para borrar cuando hay sublistas

34

Operadores sobre funciones, III


z DELETE » Versión destructiva de REMOVE (setf lista ‘(a b c)) QUÉ OCURRE»
(setf lista ‘(a b c)) » (remove ‘b lista) >>> (A C) » lista >>> (A B C) » (delete ‘b lista)
>>> (A C) QUÉ OCURRE: (setf l '(a (a b) c) ) (delete '(a b) l) (delete '(a b) l :test »
lista >>> (A C) z MEMBER » Sintaxis: (delete (a b) l :test #'equal) (member
<elemento> <lista> [:test <funcion-gualdad>]) » (member ‘b ‘(a b c)) >>> (B C) –
Equivale a (member ‘b ‘(a b c) :test #’eql) » (member ‘(a b) ‘(a (a b) c)) >>> NIL
>(member ‘(a b) ‘(a (a b) c) :test #’equal) ((A B) C)

34

>>> ((A B) C)

35

Operadores sobre funciones, IV

z Otros operadores cuyos argumentos son funciones: COUNT IF FIND IF REMOVE


IF» COUNT-IF, FIND-IF, REMOVE-IF, REMOVE-IF-NOT, DELETE-IF, DELETE-
IF-NOT z Observación: z Observación: » Al utilizar #’<f>, si <f> es un macro se
tienen resultados inesperados. No usarlos, por tanto. p

35

36

Funciones sobre strings

z Más corriente el uso de símbolos z Funciones: » LENGTH, REVERSE » STRING=


(sensible a mayúsculas), STRING-EQUAL » (read-from-string <string>) >>>
<simbolo> » (string <simbolo>) >>> <string> Devuelve el string y su nº de
caracteres hasta el primer blanco

» (prin1-to-string <numero>) >>> <string> Convierte número a string

Convierte simbolo a string

sg » (search <string1> <string2>)

» (subseq <string><posicion>) >>>

Busca parte de un string

36

» (subseq string posicion ) substring a partir de <posicion> » (concatenate <string>+)

37

Arrays
z Colección n dimensional de elementos. Se puede recorrer con un índice. A i l l tz
Acceso no secuencial a elementos » En listas, el acceso a los elementos es
secuencial Má fi i t l l t» Más eficiente el acceso a elementos en arrays que en listas
z Operadores: MAKE-ARRAY, AREF > ( tf i (k '(2 3)))» > (setf mi-array (make-array
'(2 3))) >>> #2A((NIL NIL NIL) (NIL NIL NIL)) » > (setf (aref mi-array 0 1) 'a) >>> A »
> mi-array >>> #2A((NIL A NIL) (NIL NIL NIL))

Crear array: (k li di i )

37

(make-array <lista-dimensiones>) Acceso a los elementos: (aref <array> <indice1>


… <indiceN>)

38

Estructuras, I

z Se asocia un nombre a un conjunto de propiedades o componentes (de distintos


tipos) a los que se les puede asignar valores. p ) q p g z Ejemplo: > (defstruct
nombre-persona nombre ( li ' i li ) (defstruct <nombre-estructura> <nombre-
componentei>( alias 'sin-alias) apellido)

>>> NOMBRE-PERSONA > ( tf 1

<nombre-componentei> (<nombre-componentej> <valorj>)

make-nombreestructura :

> (setf persona1 (make-nombre-persona :nombre 'juan)) >>> #S(NOMBRE-


PERSONA NOMBRE JUAN ALIAS SIN-ALIAS APELLIDO NIL) Crear instancia y dar
valores a las partes APELLIDO NIL) > (setf persona2 (make-nombre-persona
:nombre 'pedro :alias 'perico)) #S(NOMBRE PERSONA

38

>>> #S(NOMBRE-PERSONA NOMBRE PEDRO ALIAS PERICO APELLIDO NIL)

39

Estructuras, II

> (setf (nombre-persona-alias persona1) 'juanito)

nombreestructura-campoestructura : Acceder a un campo de la estructura

juanito) >>> JUANITO > persona1 #S(NOMBRE-PERSONA NOMBRE JUAN ALIAS


JUANITO APELLIDO NIL) z Funciones definidas automáticamente LISPpor LISP: »
MAKE-NOMBRE-PERSONA » NOMBRE-PERSONA -NOMBRE, NOMBRE-
PERSONA -ALIAS, NOMBRE-PERSONA - APELLIDO make-nombreestructura :
Crear instancia y dar valores a las partes (setf <instancia> (<make-
nombreestructura> t i l i ))

39

<nomcomponentei><valori> …))

nombreestructura-campoestructura : Acceder a un campo de la estructura (setf


(<nombreestructuracompontei><instancia>)<valori>)

40

Alternativa a estructuras

z Las listas son una alternativa al uso de estructuras: > ( tf 1 '(( NOMBRE JUAN) >
(setf persona1 '((:NOMBRE JUAN) (:ALIAS JUANITO) (:APELLIDO NIL))) ((
NOMBRE JUAN)>>> ((:NOMBRE JUAN) (:ALIAS JUANITO) (:APELLIDO NIL)) ( li
1)> (assoc :alias persona1) >>> (:ALIAS JUANITO) > (first ( b li 1 (member :alias
persona1 :test #'(lambda (x y) (eql x (first y)))))

40

>>> (:ALIAS JUANITO) z ASSOC utiliza por defecto EQL

41

DEBUGGING

z TRACE » Función recursiva: (defun factorial (n)– (defun factorial (n) (if (= n 0) 1 (*
n (factorial (- n 1))))) » (trace factorial) > (factorial 2) () FACTORIAL [call 5 depth 1]
with arg: 2 FACTORIAL [call 6 depth 2] with arg: 1 FACTORIAL [call 7 depth 3] with
arg: 0 FACTORIAL [ ll 7 d th 3] t l 1 FACTORIAL [call 7 depth 3] returns value: 1
FACTORIAL [call 6 depth 2] returns value: 1 FACTORIAL [call 5 depth 1] returns
value: 2 z UNTRACE z UNTRACE » (untrace), (untrace factorial) z Uso de PRINT,
DESCRIBE, etc (d ib ‘f t i l)

41

» (describe ‘factorial) z No es posible uso de “breakpoints”, “steps”, etc

42

Otros temas en LISP, I

z Comentarios » Después de “;” y hasta final de línea z Macros » Permiten definir


operadores que no evalúan sus argumentos: COND SETF DEFUN– COND, SETF,
DEFUN son macros – (defmacro defun (nombre-funcion lista-argumentos &rest
formas) ......) » Uso de backquote (`) y de arroba (@) – Operadores adicionales al
quote (‘) Hoja 1, ejercicio 14, 15 z Muchas funciones ya implementadas en LISP: »
SORT, LOOP generalizado, etc

42

z CLOS (programación orientada a objetos) Hoja 2, ejercicios 1,2, 3, 8, 11, 12

43

Otros temas en LISP, II

z Dotted-pairs (en desuso) > (cons 'a 'b) >>> (A . B) óóz Edición, carga compilación:
» COMPILE-FILE, LOAD-FILE z Entrada-salida: » PRINT, READ, FORMAT, READ-
LINE, READ-CHAR z Otros operadores de iteración: » DO, DO* (su diferencia es
equivalente a la de LET y LET*) z (declare (special <variable>)) z Argumentos
opcionales (&optional) z “Property-names” de símbolos z Copias de listas: COPY
TREE

43

z Copias de listas: COPY-TREE z Funciones sobre conjuntos: UNION,


INTERSECTION, etc. Paquetes

Lenguaje de Programación Camel.


CamelCase es un estilo de escritura que se aplica a frases o palabras compuestas.
El nombre se debe a que las mayúsculas a lo largo de una palabra en CamelCase
se asemejan a las jorobas de un camello. El nombre CamelCase se podría traducir
como mayúsculas/minúsculas Camello. El término Case se traduce como "Caja
tipográfica", que a su vez implica si una letra es mayúscula o minúscula y tiene su
origen en la disposición de los tipos móviles en casilleros o cajas.

Lenguaje de Programación Hope


El primer lenguaje funcional desarrollado fue LISP (1958), que se aplicó en el área
de inteligencia artificial. Otros de los lenguajes funcionales son:

*Standard ML

*Hope

*Maskell

El lenguaje funcional Hope puede considerarse como una notación para escribir
programas en forma de expresiones funcionales. Una expresión puede estar
constituida por un conjunto de símbolos básicos como; "-,+, >, (, 2", etc.

Los símbolos pueden ser:

*Operadores "{+, -, >,...}"


Operandos "{x, 1, 2,...}"

*Nombres de funciones (con sus argumentos)

*Separadores "{;}"

• Ejemplo:

(11 + 10) – (20 + 5)+ Maximo (pi, 20);

Prioridades.

2+3*5;

• Si hay varios operadores…

• ¿Cómo se calcula el valor?

• Asignar prioridades a operadores.

• La operaciones con operador de más prioridad se hacen antes.

Tabla de Prioridades:

1.- *, div : Prioridad 6

2.- +,- : Prioridad 5

• Si hay varios operadores con igual precedencia "2 + 3 - 5;"

• Se da prioridad al operador que se encuentra más a la izquierda.

• HOPE tiene asociatividad por la izquierda.

Asociatividad.

Shop winter

• Ejemplos:

Expresión(E): 2 + 3 * 4;

Resultado(R): 14

(E): (2 + 3) * 4;

(R): 20

(E): (113 + 20) – (20 + 34);

(R): 69 : num
Tipos.

• Un tipo de datos es una forma clasificar un valor de acuerdo a sus propiedades.

• Un tipo representa una clase de dominio de los datos

• Todo componente de un programa Hope tiene un tipo de datos. En particular, las


operaciones y los operandos de las expresiones tienen tipos.

• Hope comprueba los tipos de una expresión

antes de evaluarla.

• Se asegura que los tipos de las operaciones y los operandos son los esperados al
evaluar una expresión funcional.

• En Hope existen tres tipos de datos básicos:

*Num: Números enteros (representados en expresiones como secuencia de dígitos).

*Truval: Valores booleanos (solamente puede tomar el valor true o false).

*Char: Caracteres imprimibles (tienen que estar encerrados entre comillas simples)

En Hope+ se añade el tipo real (números reales)

Funciones.

• Una función en Hope (regla de transformación) establece una correspondencia


entre dos dominios (colecciones de datos).

• Esta regla hace corresponder a todo elemento del (de los) dominio(s) origen un
elemento del dominio destino.

• Ejemplo: El tipo de transformación

num → truval

indica que la función transforma un valor de tipo num (entero) en otro de tipo truval
(booleano).

• En Hope todas las funciones tienen dos partes; su declaración y su definición.


Ejemplo:

Función que transforme una temperatura en grados Celsius a Fahrenheit:

Beck Fahrenheit : num. -> num.; (declaración).

Fahrenheit f <= (f - 32)*5 Dib. 9; (definición)


• Una vez definida, la función se incorpora a la máquina HOPE, usándose con
distintos argumentos:

*(E): Fahrenheit 40;

*(R) 4: num.

Erlang
Es un lenguaje funcional y de programación concurrente, fue diseñado por la
compañía Ericsson con el propósito de hacer aplicaciones que puedan soportar
fallos, funcionamiento ininterrumpido, aplicaciones distribuidas, entre otras cosas.

Tiene una característica muy importante "el cambio de código en caliente" el cual se
refiere a poder modificar el código aun cuando la aplicación esta corriendo. Erlang
no seguía la filosofía de código abierto hasta 1998 cuando Ericsson lo cedió como
tal.

Erlang es un lenguaje interpretado, aunque también se puede compila usando el


compilador HiPE, aunque este compilador solo es para algunas plataformas es muy
bueno porque pude soportar la concurrencia característica muy distintiva del
lenguaje. Esta es la pagina oficial de HiPE.

Es posible que pensemos que entender este proceso de concurrencia es


complicado y más aun aplicarlo en algún programa pero en Erlang la concurrencia
es explicita y no implícita con en otros lenguajes.

El nombre de Erlang viene de las palabras Ericsson y Language.

Erlang lenguaje funcional

Los programa en Erlang están compuestos de bloques "funciones" y las


identificamos por su nombre y el numero de argumentos de entrada también
llamado "aridad". Por ejemplo las funciones multiplicacion/2, multiplicacion/3,
multipicacion/4 pueden existir perfectamente juntas y llamándose a cada una según
el numero de datos que se introduzca por el usuario, los resultados que devuelven
las funcione son puede ser de cualquier elemento soportado por Erlang flotante,
tupla, entero, lista, etc.

mi_funcion(dato1, dato2, ...) ->

instrucción,

instrucción,

resultado_a_devolver
También podemos escribir alguna condición antes de ">" podemos poner que si se
cumple algo entonces se lleve acabo determinada instrucción esto lo hacemos con
"when" una forma de implementarlo seria seria:

mi_funcion(dato1, dato2) when dato1 > 0 ->

y algo muy importante en Erlang aprender a escribir el ".".

Hice un programa en Erlang que muestra su característica como lenguaje funcional,


bueno primero que nada abro el terminal y escribo:

cecy@cecy-desktop:~$ emacs -nw geom.erl

Notemos los programas escritos en Erlang tienen la extensión .erl y lo estoy


llamando geom, ahora escribo mi programa que obtiene el perímetro de diferentes
figuras geométricas el circulo, rectángulo, triángulo y cuadrado, podemos ver que
para calcular el perímetro de cada figura se necesitan determinados números de
datos de entrada por ejemplo para calcular el área del circulo solo ocupamos la
medida del radio es por eso que se declara -export([circulo/1])., pero para calcular el
perímetro de un rectángulo se necesitan dos por consiguiente se declara así: -
export([rectangulo/2])., vemos que antes de declarar las funciones se escribe
module(algo), ese "algo" no es cualquier cualquier cosa siempre debe ser el mismo
nombre que el del programa en mi caso "geom" y otra cosa muy importante las
variables se escriben en mayúsculas :D que no se te olvide.

Código:

-module(geom).

-export([circulo/1]).

-export([cuadrado/1]).

-export([rectangulo/2]).

-export([triangulo/3]).

circulo(R) ->

2*R*3.1416.

cuadrado(L) ->

L*4.
rectangulo(A,B) ->

2*A+2*B.

triangulo(A,B,C) ->

A+B+C.

Ahora que ya escribí mi programa tengo que compilar el modulo desde Erlang para
ver si no marca ningún error, la manera de hacerlo es escribimos erl en el terminal y
luego c(geom)., esta es la captura de pantalla:

Como todo esta bien en el código podemos ver "{ok, geom}", ahora si podemos
obtener el perímetro de las figuras de esta manera escribimos el
nombre_del_modulo:nombre_funcion(dato1, dato2...datox). en mi caso escribo:

y cuando escribimos más datos de entrada a alguna función de los que acepta nos
marca error por ejemplo:

Las características mas destacadas de Erlang son:

Lenguaje funcional

Soporte de concurrencia

Tolerancia a fallas

Cambio de código en caliente

Posibilidad de conectar con código C, Java y otros lenguajes


La concurrencia es una característica importantísima del lenguaje fue creada
especialmente para las aplicaciones de telecomunicaciones: gran disponibilidad,
cambiar código sin detener la aplicación, etc.

El lenguaje F#
Hace dos años, tuve el gusto de dar una charla con Martín Salías, en Microsoft de
Argentina, sobre lenguajes de programación en .NET. Uno de los que presentamos
(además de Lisp, Prolog y cosas así, Martín expuso sobre LINQ que estaba
entonces apareciendo), fue el lenguaje F#.

Siendo un proyecto de investigación de Microsoft, pueden ver más información


sobre el lenguaje en:

F# site

Don Syme's WebLog on F# and Other Research Projects

F# - A Functional Programming Language

Robert Pickering's F# Resources

F# es un lenguaje mixto, es imperativo y es funcional, basado en lenguajes


funcionales como Caml, y con sintaxis C#.

Tiene seguridad de tipos, rendimiento, soporte de scripting. Algunas características


mencionadas en el sitio de F#:

Scripting interactivo como en Python

Inferencia de tipo y seguridad de tipos como en ML

Un perfil de rendimiento como en C#

Acceso a todo el framework .NET


Simplicidad en sus fundamentos, como en Scheme

La rapidez de ejecución de código nativo, usando el soporte de concurrencia y


distribución del framework .NET

Algunos artículos iniciales, tomados del sitio de Microsoft:

About F# and comparison with OCaml, talks, performance and the FAQ.

Getting started is a guide to installation and running your first program.

The F# Downloads page contains release and download information for the
Microsoft Research implementation of F#.

The F# Manual focuses on F#-specific features.

The F# Library Reference Documentation for F# specific library reference.

The F# Community page lists key F# sites and projects.

Y ahora, en estos días, se anunció el inicio de un proyecto esperado por la


comunidad F#: la inclusión del editor del lenguaje en el Visual Studio. Más detalle
en:

F# makes its way to VS.NET

Algunos comentarios de Soma Somasegar, en el post mencionado:

F# - A Functional Programming Language


sobre la iniciativa de Microsoft de tener F# ahora en el Visual Studio, como
ciudadano de primera clase en el mundo .NET (Somasegar es vicepresidente en
Microsoft encargado de las herramientas de desarrollo):

Nuestro interés en F# es motivado por varios factores.... Queremos continuar con el


flujo de buenas ideas desde la programación funcional hacia la corriente principal de
desarrollo. Además, la notación algo matemática de F# parece naturalmente
atractiva para aquellos profesionales cuyo domino principal es descripto en notación
matemática, dominios como el financiero, científico y la computación técnica. Sobre
el atractivo de la sintaxis, el sistema de tipos fuerte provoca la clase de garantías
que es frecuentemente crucial en esos dominios, y permite una experiencia de la
herramienta superior con Visual Studio.

Otra motivación es continuar invirtiendo en hacer del framework .NET una gran
alternativa para uso académico. Muchos departamentos de ciencia de la
computación en el mundo enseñan programación funcional. Creemos que a través
de F# y lenguajes como IronPython y IronRuby nosotros podemos ofrecer a los
estudiantes y educadores alternativas más allá de la actual corriente principal, y
habilitar el uso de estos lenguajes en la enseñanza. Esto ayuda a los educadores a
tener una opción a usar el Visual Studio como una herramienta de curso a curso.

Esperemos ver qué sucede. Es simpático el F#, aunque hay que habituarse a sus
sintaxis e ideas (siento algún escalofrío recordando mis días con el APL, A
Programming Language), pero veamos como la comunidad académica lo toma. Me
parece más difícil verlo adoptado en entornos de desarrollo, pero si prende en la
academia, seguramente podrá tener su nicho en la industria. Es interesante leer en
los comentarios del post de Somasegar, la opinión de James Plamondon: "esto es
un preludio al día en que los programadores podrán elegir el mejor lenguaje para
escribir cada parte de su tarea de codificación, así como un carpintero usa un
martillo para una y una sierra para otra".

Vous aimerez peut-être aussi