You are on page 1of 62

Estructuras de Datos.

Grados en Ingeniera Informtica, del Software y de Computadores


ETSI Informtica
Universidad de Mlaga

Jos E. Gallardo, Francisco Gutirrez, Pablo Lpez


Dpto. Lenguajes y Ciencias de la Computacin
Universidad de Mlaga

Programacin Funcional

Introduccin a Haskell

Programacin Imperativa vs Programacin Funcional


Funciones puras e impuras
Ventajas de la Programacin Funcional

Identificadores
Tipos bsicos
Definiciones de funciones. Aplicaciones
Operadores, precedencia y asociatividad
Evaluacin de expresiones
Tuplas
Polimorfismo y sobrecarga
Ecuaciones condicionales y expresiones
Funciones definidas parcialmente
Definiciones locales
Operadores vs Funciones
Introduccin a QuickCheck

Los cmputos manipulan variables mutables

http://en.wikipedia.org/wiki/Imperative_programming

Estas variables mutables representan la memoria o el


estado del computador
Los algoritmos modifican las variables hasta obtener el
resultado deseado

Las variables i y p son


alteradas durante la
ejecucin

Un estilo de programacin basado en cmputos a travs


de funciones matemticas (o puras) :

http://en.wikipedia.org/wiki/Functional_programming

Un programa es una funcin

Toma datos a travs de sus argumentos


Realiza clculos con estos datos a travs de expresiones
Devuelve nuevos datos (resultados del cmputo)
datos
argumentos

funcin
(programa)

nuevos datos
resultado

Nada cambia !

No existe el concepto de variable mutable tpico de la programacin


imperativa
4

Funcin para calcular factorial en Haskell:

Evaluacin paso a paso:

No hay variables
mutables. Tan solo
funciones y expresiones

Una funcin matemtica siempre devuelve el mismo


resultado para los mismos valores de sus
argumentos:
x = y f (x) = f (y)

(Regla de Leibniz)

http://en.wikipedia.org/wiki/Pure_function

Esto conduce a la propiedad de transparencia


referencial:

Una misma expresin denota siempre el mismo valor, sea


cual sea el punto del programa o el contexto en que
aparezca.

Simplifica el razonamiento sobre las propiedades de


los programas (en particular, la correccin)
Podemos calcular con programas al igual que en
matemticas calculamos con expresiones

Un ejemplo de funcin pura:

siempre devuelve
Si = entonces

La siguiente no es una funcin pura:

La primera llamada
devuelve
La segunda llamada
devuelve
Para el mismo valor del argumento
devuelve diferentes resultados

La siguiente tampoco es una funcin pura (no es


matemtica):
Cada llamada puede devolver un valor distinto

La programacin funcional consiste en escribir


programas (funciones) combinando otras
funciones
En los lenguajes funcionales puros:

Solamente podemos definir funciones puras


Se satisface la transparencia referencial

Miranda, Clean, Haskell,

En los lenguajes funcionales impuros:


Se permite definir funciones impuras

ML, F#, Scheme,

10

Optimizacin: el compilador puede realizar


transformaciones sofisticadas con objeto de optimizar el
comportamiento

Paralelismo: partes de una expresin pueden evaluarse en


cualquier orden sin alterar el resultado; incluso varios
procesadores pueden intervenir en la evaluacin de la
misma expresin.
La Programacin Funcional Pura es intrnsecamente paralela
La Programacin Imperativa es intrnsecamente secuencial

Memoization: los resultados producidos por las llamadas a


una funcin pueden ser reutilizados (recordados) en
sucesivas llamadas con los mismos valores de los
argumentos
11

En un LFP (lenguaje funcional puro), la definicin:


puede reemplazarse por :

sin modificar el significado del programa.

Esta sencilla transformacin es una optimizacin:


solamente se computa (evala) una vez

Adems, la expresin
puede evaluarse va paralelismo

Lo anterior no es vlido en lenguajes impuros

12

Un Lenguaje Funcional Puro estndar


www.haskell.org

Principales caractersticas:
Pureza funcional

Tipificacin esttica
Perezoso (Lazy)

13

Haskell distingue maysculas de minsculas (case sensitive) !


Los identificadores (nombres) de funciones y argumentos:

Deben empezar con una letra minscula o el carcter _ (underscore) y ste

puede ir seguido de letras (maysculas o minsculas), dgitos, tildes (') o _


Ejemplos vlidos de identificadores:
Ejemplos no vlidos:

Los nombres de tipos deben empezar con una letra mayscula


,

Los nombres de operadores:

Pueden contener uno o varios smbolos


El primero no puede ser dos-puntos (:)
Ejemplos vlidos:

, etc.

14

un subconjunto acotado de los nmeros enteros


operaciones rpidas; posibilidad de overflow o
underflow

15

el conjunto completo de los enteros

subconjunto de los reales en simple precisin

subconjunto de los reales en doble precisin

16

tiene solamente dos valores:

conjuncin lgica (and):


disyuncin lgica (or):
negacin lgica:

http://en.wikipedia.org/wiki/George_Boole

x y
not primo y
Hay evaluacin en cortocircuito

17

,
,

conjunto de caracteres Unicode :


, ,
, ,

,
,

, ,
,

Muchas funciones sobre caracteres aparecen


definidas en el mdulo o librera
:

18

Haskell usa notacin parcializada (curried)

Introducida por
Moses Schnfinkel (1889-1942)
y popularizada por
Haskell Curry (1900-1982)

http://en.wikipedia.org/wiki/Currying

Para definir una aplicacin:

Escribimos el identificador de la funcin y a

continuacin los argumentos separados por espacios


El uso de parntesis slo ser necesario para agrupar
trminos compuestos y modificar el efecto de las
prioridades de las operaciones

19

toma un
entero

nombre de
la funcin

argumento

devuelve un
entero

resultado

toma dos enteros


y devuelve un
entero

20

square solo se aplica


una vez al 5

square se aplica a la suma


5 + 1.
Los parntesis son
necesarios

phytagoras se aplica
a los dos argumentos
El segundo argumento es
compuesto y necesita
parntesis

21

Una expresin condicional, como cualquier otra


expresin, puede formar parte del cuerpo de una
funcin:

22

El cuerpo de una funcin puede contener a la funcin que define

El uso del tipo

(subconjunto finito) causar problemas:

El problema se resuelve tomando Integer (una abstraccin del

conjunto completo de los enteros)

23

GHC es el Glasgow Haskell Compiler, un compilador


de alta calidad para Haskell
GHCi es el Glasgow Haskell Compiler Interpreter:

Con el uso del bucle Read-Eval-Print podemos ejecutar

programas Haskell

GHC y GHCi estn disponibles para las plataformas


ms populares: Windows, Linux y OSX
En la pgina web de la asignatura aparecen
instrucciones de instalacin

24

Dos entornos para GHCi

25

El operador unario
simblico prefijo:

es el nico operador unario

El resto de operadores simblicos son binarios y se


usan directamente en forma infija:

Precedence parsing error

26

Mxima precedencia
La aplicacin de una
funcin tiene prioridad
mxima

Nivel Operador predefinido


10
9
8
7
6
5

Aplicacin de una funcin


La multiplicacin tiene
mayor nivel de
precedencia que la suma

4
3
2
Mnima precedencia

27

Esta propiedad permite resolver la ambigedad


en ausencia de parntesis:
Si

asocia a la izquierda:

Si

asocia a la derecha:

Si

no es asociativo:

ERROR: los parntesis


son necesarios
28

Asociatividad
Derecha

Operador

Izquierda

No asociativo

Ejemplos:

Use parntesis si
desconoce la
asociatividad

Expresin errnea

29

Son diferentes conceptos que no deben ser


confundidos

La asociatividad es un atributo sintctico de un


operador en un lenguaje de programacin

El operador
verifica la propiedad asociativa en
sentido matemtico si satisface:
x, y, z . (x y) z = x (y z)

La propiedad asociativa tambin es interesante


computacionalmente:

Para evaluar x y z se parentizar de acuerdo con el

menor coste computacional.

30

infix = no asociativo.
infixl = asociativo a izda
infixr = asociativo a dcha

Nivel de precedencia

El identificador del
operador debe
aparecer entre
parntesis en una
declaracin de tipo

31

Toda funcin de dos argumentos cuyo identificador sea literal


puede ser utilizada en forma infija encerrndolo entre acentos
graves (`)
notacin prefija

forma infija
Error

Si la funcin es asociativa
no son necesarios los
parntesis

32

Recprocamente, cualquier operador simblico puede utilizarse en


forma prefija encerrndolo entre parntesis
forma infija
forma prefija
Error

33

34

Redex (reducible expression): parte de una expresin que puede


ser simplificada

Reduccin: proceso de reescritura de un redex. Cada reduccin es


un paso de cmputo
Forma Normal : expresin sin redexes
redex
reduccin

es una forma
normal

35

Orden Aplicativo

Se reduce el redex ms interno y ms


a la izquierda.
Los argumentos son evaluados antes
que la funcin
Pros
Los argumentos compuestos se
evalan una sola vez

Contras
Pueden realizarse reducciones
innecesarias.
Puede no conducir a la forma normal
(no es normalizante)

36

Orden Aplicativo

Se reduce el redex ms interno y ms


a la izquierda.
Los argumentos son evaluados antes
que la funcin
Pros
Los argumentos compuestos se
evaluan una sola vez

Contras
Pueden realizarse reducciones
innecesarias.
Puede no conducir a la forma normal
(no es normalizante)

37

Orden Normal

Se reduce el redex ms externo y


ms a la izquierda.

La funcin es aplicada antes de


evaluar sus argumentos

Pros
Slo se evalan las expresiones
necesarias.
Siempre conduce a la forma normal si
sta existe (normalizante)
Contras
Puede repetirse la evaluacin de un
argumento compuesto

38

Orden Normal

Se reduce el redex ms externo y


ms a la izquierda.
La funcin es aplicada antes de
evaluar sus argumentos

Pros
Slo se evalan las expresiones
necesarias.
Siempre conduce a la forma normal si
sta existe (normalizante)
Contras
Puede repetirse la evaluacin de un
argumento compuesto

39

Haskell usa evaluacin perezosa (lazy) :

Combina las ventajas del orden normal y del aplicativo


Es similar al orden normal pero evita la reevaluacin:
Los argumentos son evaluados una sola vez y su valor comn
es compartido (sharing)
Esta optimizacin es posible en lenguajes puros

valor
compartido

40

Son estructuras de datos heterogneas:


Es una coleccin de valores (componentes)

Cada componente puede tener un tipo distinto

Sintaxis:

Los valores se separan por comas y se colocan entre

parntesis
Los tipos de cada componente se separan por comas y
se colocan entre parntesis
41

42

Funciones predefinidas que extraen las componentes de una tupla:


Debe leerse como:
.

Prelude

Prelude

Patrn de una
2-tupla

Indica una
funcin
predefinida

y son variables de tipo;


toma
una 2-tupla con componentes de tipos
arbitrarios
y . Se dice que
es
polimrfica.

43

Una clase de tipos es un conjunto de tipos que comparten alguna operacin

http://en.wikipedia.org/wiki/Type_class

es la clase predefinida para los tipos numricos (enteros, flotantes,


racionales, ...)

Algunos operadores y funciones solamente tienen significado para tipos


numricos:
debe leerse como:

Prelude

tipo sobrecargado
debe ser una
instancia de
; es
decir, debe ser un
tipo numrico

Los operandos y el resultado


tienen que ser del mismo tipo

44

suma sobre
Integer

producto sobre
Floating
2 est sobrecargado
Char no es de la clase Num
Type error

45

es la clase que agrupa los tipos de nmeros enteros


Tiene funciones especficas para la divisin entera:

Prelude

Tipo sobrecargado:
debe ser de la clase
Integral

debe leerse como:

cociente y resto de la
divisin entera

Los nmeros Floating no


son Integral.
Type error

46

es la clase que agrupa los tipos de nmeros fraccionarios:


flotantes y racionales (cocientes de enteros , ...)
La funcin esencial es la divisin fraccionaria:
Esto debe leerse como:

Prelude

El tipo debe ser


de la clase
Fractional

Divisin
fraccionaria

10 y 3 estn
sobrecargados

47

Esta funcin usa el operador


sobrecargado
Solo puede ser aplicada a tipos
numricos; la funcin hereda el
contexto

48

es la clase de los tipos para los cuales existe una relacin de orden total;
entre stos aparecen Integer, Double, Char, Rational, Bool,
Ciertos operadores (<, max, ) solo tienen sentido para las instancias de
Debe leerse como:

Prelude

Prelude

debe ser un tipo


instancia de

Prelude

mximo y mnimo de dos


valores del mismo tipo,
instancia de

Solo podemos comparar valores


del mismo tipo, y el resultado
siempre ser un booleano

Tipo
enumerado
predefinido

49

es la clase de los tipos para los cuales existe una relacin de igualdad; entre
stos aparecen Integer, Double, Char, Rational, Bool,
La clase incluye dos operadores:
Debe leerse como:

Prelude

debe ser un tipo


instancia de

Solo podemos comparar


valores del mismo tipo, y
el resultado siempre ser
un booleano

50

1 es menor que 2
1 no es igual a 2
1 es distinto de 2
1 es Less Than 2
10 es Greater Than 2
1 es EQual

a 1

El mayor de 3.5 y 7.8 es 7.8


El menor de 3.5 y 2.0 es 2.0
51

52

A menudo es ms sencillo describir una


funcin por partes:

Su valor es 1, si el
argumento es positivo

Atencin al
sangrado . Los
separadores
en la misma
columna

Su valor es -1, si el
argumento es negativo

Su valor es 0, si el
argumento es nulo

Guardas booleanas

http://en.wikipedia.org/wiki/Guard_(computing)

53

La definicin anterior:
puede escribirse de forma ms corta (estilo preferente):
otherwise: esta condicin
siempre es cierta. Ser
seleccionada si fallan las
previas
Prelude

54

Las expresiones condicionales proporcionan una


alternativa a las formas guardadas:
Prelude

55

Hay funciones definidas solo parcialmente:


Esto se consigue va la funcin error:

Error es una funcin polimrfica:


Prelude

error ::

el valor de tipo String


describe la
excepcin

-> a

56

La palabra reservada
permite definir funciones o variables
locales, y debe aparecer al final de la definicin

where: debe
sangrarse con
respecto a la funcin

Las definiciones locales deben


sangrarse al mismo nivel

57

Una alternativa para introducir definiciones locales es va la


construccin

Las definiciones locales


deben estar sangrarse
al mismo nivel
resultado de la

expresin

58

Es una buena prctica probar los


programas
Las pruebas ayudan a encontrar
errores

QuickCheck es una librera de Haskell que ayuda a


probar los programas
Definimos propiedades que nuestros programas deben

cumplir
QuickCheck genera casos de prueba y verifica las
propiedades para esos casos

59

Propiedades en QuickCheck:
antecedente

consecuente

antecedente y consecuente deben ser expresiones

booleanas

Debe leerse como una implicacin lgica: si el antecedente

es cierto entonces el consecuente tambin debe serlo

QuickCheck solo realiza las verificaciones para propiedades

en las que el antecedente es cierto. Las pruebas con


antecedente falso son descartadas

Se debe usar

si la propiedad es el propio consecuente


consecuente
60

Algunas propiedades:
.

0.

.|

|
0 . |

| |

| |
|

| |

| |

Hacemos que
QuickCheck pruebe
nuestra propiedad
con enteros
aleatorios

Fallo en la prueba:
contraejemplo
61

Edsger W. Dijkstra

(1930-2002, Premio Turing 1972)

Las pruebas de un programa


pueden usarse para mostrar la
existencia de errores, pero nunca
para demostrar su ausencia!

http://en.wikipedia.org/wiki/Edsger_W._Dijkstra

Para establecer la correccin de un algoritmo se debe realizar una


demostracin
Algunas veces es difcil y lleva mucho tiempo

Realizar pruebas es mejor que no hacer nada


62

You might also like