Programación Funcional
Programación Funcional
• El tipo de datos.
• Funciones.
• Intervalos.
• Operadores.
• Árboles.
• Evaluación perezosa
Evaluación de expresiones
Declarativo Imperativo
• Programación funcional.
• Liga www.haskell.org
• Las lambdas son funciones anónimas que suelen ser usadas cuando
se necesitan una sola vez, ejemplo: (\x -> x + x) 2. \parámetros
-> el cuerpo de la función entre paréntesis. Pueden recibir
más de un parámetro.
(\x y z -> x * 2 - y + 10 * z)
• Fibo 0 = 0.
• Fibo 1 = 1.
• Fibo n = (fibo(n-1) + fibo(n-2))
Fibo 2 = 1 + 0 = 1
Fibo 3 = 1 + 1 = 2
Fibo 4 = 2 + 1 = 3
Fibo 5 = 3 + 2 = 5
Asignación no destructiva
• masuno x = x + 1
• masuno (3*2) da el mismo resultado (2*3)
• Divisores de un número
• divisores :: Integer -> [Integer]
• divisores n = [d | d <- [1..n], n ‘mod‘ d == 0]
• Función de ruffini
• ruffini :: Float -> [Float] -> [Float]
• ruffini a = scanl1 (\r x -> r * a + x)
• ruffini 3 [2,4,3] resultado [2,10,33]
+ +AB
A B
Recorridos del árbol
10 22 15 12 35 52 33
15 22 12 10 35 33 52 +
35 33 52 12 15 22 10
A B
+AB
B A+
A+B
10,22,15,12,35,52,33
15,12,22,35,33,52,10
Programar en funcional es pensar en funciones. Sin embargo, no
sólo es lo anterior, cualquier lenguaje de programación dentro de
este paradigma se caracteriza por un comportamiento acerca de
como evalúa las construcciones.
• Lógica de predicados
• Inferencia en lógica
Modus ponens
El modo que, al afirmar, afirma. Si A implica B, y A es cierto, entonces B es cierto
La aridad de un operador matemático o de una función es el número de
argumentos necesarios para que dicho operador o función se pueda
calcular.
-
(A + B) - C
C
+
-+ABC
AB+C- A B
Análisis Lexicográfico
Funciones del analizador lexicográfico
Token y Lexema
Token y Lexema: Ejemplo
Palabras reservadas
Por ejemplo: int valor = 100;
+ a
3 5
Esquema de un compilador
Análisis: Se lee el programa fuente y se estudia la estructura y el significado del
mismo
Análisis sintáctico
Análisis semántico
Fases de análisis
Análisis léxico
Identificar símbolos
Eliminar separadores
Eliminar comentarios
Crear símbolos de entrada al análisis sintáctico (tokens)
Determinar errores
Análisis sintáctico
Análisis semántico
Fases de análisis
Análisis léxico
Análisis sintáctico
Comprobar que las sentencias que componen el texto fuente
son correctas en el lenguaje, creando una representación
interna que corresponde a la sentencia analizada.
Análisis semántico
Fases de análisis
Análisis léxico
Análisis sintáctico
Análisis semántico
Se ocupa de analizar si la sentencia tiene algún significado.
Incluye el análisis de tipos, y determina sentencias que
carecen de sentido.
Análisis léxico en Haskell
Reconocer expresiones regulares, que pueden ser reconocidas
por un autómata finito determinista (AFD).
infixl7 &><
(&><) :: ReadS a -> ReadS b -> ReadS (a,b)
p1 &>< p2 = \s -> [ ((x1,x2),s2) | (x1,s1) <- p1
s,
(x2,s2) <- p2
s1 ]
exp = term <*> many (token addOp <*> term <@ f4) <@ f5
Análisis sintáctico en Haskell
Atributos heredados.
Su valor ya está calculado, arriba o al mismo
nivel en el árbol.
Se corresponden a un recorrido de arriba a
abajo.
Se puede representar mediante una función
recursiva (posiblemente de cola), acumulando
los atributos.
Veamos en el árbol anterior cuáles serían
atributos heredados.
Análisis semántico en Haskell
Analizadores monádicos
Ejemplo: secuencia
• Como se ha visto en clase, algo bueno de las mónadas es que permiten
simular secuenciación al estilo imperativo:
Otros filtros
(!>) ::Analiz a -> (a -> Bool) -> Analiz a
k !> p = do
a <- k
if p a then return a else mzero
Analizadores monádicos
Reconocimiento de una letra, o bien de un
número:
letra::AnalizChar
letra=elemento !> isAlpha
digito::AnalizChar
digito=elemento !> isDigit
anaConst::AnalizTerm anaDiv::AnalizTerm
anaConst=do anaDiv=do
a <- número _ <- literal ’(’
return(Const a) u <- term
_ <- literal ’/’
anaSum::AnalizTerm v <- term
anaSum=do _ <- literal ’)’
_ <- literal ’(’ return(u:/:v)
u <- term
_ <- literal ’+’ term::AnalizTerm
v <- term term=anaConst !+ anaSum !+ anaDiv
_ <- literal ’)’
return(u:+:v)
Software específico
Alex
Happy
Frown
Parsec
Alex y Happy
Son descendientes de los programas de Unix LEX y YACC ( Yet
Another Compiler Compiler), los programas generados por Alex
y Happy son en Haskell y como parte de un programa más largo
en Haskell.
Analisis lexicográfico
Analisis ok
lexicográfico
Analizador Básico
Se procede con la instrucción Código final
alex wordcount.x {
main :: IO()
Código inicial main do
{ s <- getContents
module Main(main) where let toks = alexScanTokens s
} mapM _putStrLn toks
}
La siguiente línea es
%wrapper “basic”
En este caso Alex proporciona la función
alexScanTokens : : String -> [Token]
Macro definiciones
$letter = [a-zA-Z]
$noletter = [~ $letter \n]
Reglas
token :-
$noletter+ ;
$letter+ {id}
Tipos de parsers en un compilador
Los analizadores de sintaxis siguen reglas de producción definidas a través de
gramáticas libres de contexto. La forma en que las reglas de producción son
implementadas (derivadas) se dividen en dos tipos de parsers: Top-Down y Bottom-Up
Top-down
Ejemplo:
cadena de entrada: a + b * c
Reglas de producción.
9 5 4 20 10 3
9 5 4
45
45 9 3 10 20
lex “ABC”
“ABC”
| ? - likes(mary,food).
yes
| ? – likes(john,mary)
Yes
| ? – likes(mary,john)
No
| ? – likes (john,food)
No
male(james1).
male(charles1).
male(charles2).
male(james2).
male(george1).
female(catherine).
female(elizabeth).
female(sophia).
parent(charles1,
james1).
parent(elizabeth,
Es George I el pariente de Charles I? Query: pariente(charles1,
james1). george1).
parent(charles2,
charles1). De quién es Charles pariente? Query: pariente(charles1,X).
parent(catherine,
charles1). Quien son los hijos de Charles I? Query: pariente(X,charles1).
parent(james2,
charles1). Periente (Sophia, Charles1)
parent(sophia,
elizabeth).
parent(george1,
sophia).
Los tres constructores básicos en Prolog
Los hechos son las sentencias más sencillas. Un hecho es una fórmula atómica o
átomo: p(t1, ..., tn) e indica que se verifica la relación (predicado) p sobre los
objetos (términos) t1, ..., tn.
Una regla es una sola conclusión seguida por el signo :- el cual hace la vez de SI
condicional, seguida por una o mas relaciones de condición.
Los tres constructores básicos en Prolog
Regla recursiva
Los tres constructores básicos en Prolog
Ejemplo de reglas:
sucesor(1,2).
sucesor(2,3).
sucesor(3,4).
sucesor(4,5).
sucesor(5,6).
sucesor(6,7).
suma(1,X,R):-sucesor(X,R).
suma(N,X,R):-sucesor(M,N),suma(M,X,R1),sucesor(R1,R).
Aquí podemos apreciar como suma es una regla que depende en gran medida
de la condición sucesor. En la segunda regla de suma se observa que existe mas
de una condición, por tanto estas van separadas por coma; podemos observar
también que se realiza una operación recursiva.
Los tres constructores básicos en Prolog
Un átomo es:
• Una cadena de caracteres formada por letras mayúsculas,
minúsculas, dígitos y el carácter de guion bajo. Aquí hay algunos
ejemplos: letramin, gran_kahuna_burger, lsita2Musicas y
gutarristaAcustico.
• Una secuencia arbitraria de caracteres entre comillas simples. Por
ejemplo, “Paty", “El lobo", “Cinco_Pesos_Cambio", "& ^% & # @ $ & *"
y "". La secuencia de caracteres entre las comillas simples se
denomina nombre del átomo. Tener en cuenta que se permite utilizar
espacios en dichos átomos; de hecho, una razón común para usar
comillas simples es para que podamos hacer precisamente eso.
• Una cadena de caracteres especiales. Aquí hay algunos ejemplos: @
= y ====> y; y: - son todos átomos. Como se vera, algunos de estos
átomos, como; y: - tienen un significado predefinido.
Los tres constructores básicos en Prolog
Un número es:
• Los números reales no son particularmente importantes en las
aplicaciones típicas de Prolog. Entonces, aunque la mayoría de las
implementaciones de Prolog admiten números de punto flotante o
flotantes (es decir, representaciones de números reales como
1657.3087 o π).
• Los números enteros (es decir:…, -2, -1, 0, 1, 2, 3,…) son útiles para
tareas como contar los elementos de una lista, su sintaxis de Prolog
es como en otros lenguajes de programación: 23, 1001, 0, -365, etc.
La base de conocimiento se expresa mediante hechos y reglas, que no son otra
cosa que una representación sintáctica concreta de cláusulas de Horn de primer
orden. Por lo tanto el conocimiento queda expresado en lógica de primer orden.
?-
?- 5 is 2+3.
Yes
?- 1 is 1+1.
No
Para responder a las preguntas formuladas, Prolog consulta una base de
conocimiento, al iniciar la sesión, esta base de conocimiento almacena un
conocimiento básico
¿Cuáles de la siguiente lista son átomos, variables y cuales no son ni uno ni otro.
1.- Vincent
2.- MasajedePies
3.- variable23
4.- Variable2000
5.- big_kahuna_Burger.
6.-’big kahuna Burger’
7.- big kahuna Burger
8.- ‘Julio’
9.- _Julio
10.- ‘_Julio’
Ejercicios:
1.wizard(ron).
2.witch(ron).
3.wizard(hermione).
4.witch(hermione).
5.wizard(harry).
6.wizard(Y).
7.witch(Y).
Predicados sobre directorios y archivos
?- pwd.
c:/prolog/mauricio
Predicados sobre directorios y archivos
?- cd(‘../paty’).
?- cd('c:/prolog/mauricio’).
?- likes(sam, X).
X = dahl ;
X = tandoori ;
X = kurma ;
X = chow_mein ;
X = chop_suey ;
X = sweet_and_sour ;
X = pizza ;
X = spaghetti ;
X = chips.
?- likes(sam,papas).
false.
?-
? –listing(mild).
mild(dahl).
mild(tandoori).
mild(kurma).
true.
?- listing(mexicana).
ERROR: procedure `mexicana' does not exist (DWIM could not correct goal)
^ Exception: (13) setup_call_catcher_cleanup(system:true,
prolog_listing:listing_(user:mexicana, []), _6604, prolog_listing:close_sources)
?- listing(italian).
italian(pizza).
italian(spaghetti).
?italian(X).
?- italian(X).
X = pizza ;
X = spaghetti.
?- italian(tacos).
false.
Ruta para ver el archivo DEMO. Archivos de programa > swipl > demo>likes.pl
?- halt.
?-
progenitor(clara,jose). %Hecho 1
progenitor(tomas, jose). %Hecho 2
progenitor(tomas,isabel). %Hecho 3
progenitor(jose, ana). %Hecho 4
progenitor(jose, patricia). %Hecho 5
progenitor(patricia,jaime). %Hecho 6
?- progenitor(patricia,jaime).
true
?- progenitor(jaime,X).
false
?- progenitor(X,jaime)
patricia
?- progenitor(X,jose),progenitor(X,isabel)
Objetivo 1 Objetivo 2
?-progenitor(tomas,X);
progenitor(X,Y);progenitor(Y,Z).
?-progenitor(clara,X),
progenitor(X,Y),progenitor(Y,jaime)
X = jose
Y = patricia
Z= jaime
?- padre(X,Y)
Ejemplo: Factorial
Funcion factorial(X)
SI (X==0) regresa 1
OTRO
regresa X * factorial(X-1)
FIN Funcion.
Ejemplo: Fibonacci
Funcion fibonacci(N)
SI (N < 2) regresa N
OTRO
regresa fibonacci(N-1) + fibonacci(N-2)
FIN Funcion.
En Prolog la palabra Functor es usado para referirse al átomo al comienzo de una estructura,
junto con su aridad, es decir, el número de argumentos que toma.
?- 2 <4. ?- <(2,4).
true true
[a,1, [b.2.0]]
?- append([a],[b],X).
X= [a,b].
?- append(X,[b,c,d],[a,b,c,d]).
X= [a]
?- append([a],[1,2,3],[a,1,2,3]).
true
?- append([a],[1,2,3],[hola,vida,mal]).
false
?- append([a],[b],X).
?- append(X,[b,c,d],[a,b,c,d]).
?- append([a],[1,2,3],[a,1,2,3]).
?- append([a],[1,2,3],[hola,vida,mal]).
append([],L,L).
append([X|L1],L2,[X|L3]) :- append(L1,L2,L3).
Se tiene el siguiente programa:
En Prolog (y en Haskell) es muy habitual aplicar una operaci´on a cada uno de los
elementos de una lista y obtener una nueva lista resultado.
Por ejemplo, incrementar en 1 cada uno de los elementos de la lista [5,4,7,8,9]. O más
en general, incrementar en 1 los elementos de una lista L dada:
incLst([],[]).
incLst([X|Xs],[Y|Ys]):- Y is X+1, incLst(Xs,Ys).
incLst([],[]).
incLst([X|Xs],[Y|Ys]):- inc(X,Y), incLst(Xs,Ys).
inc(X,Y):- Y is X+1.
Expresiones aritméticas
? X is Y, Y is 4.
F
C
Resumen
pares([],[]).
pares([X|Xs], [X,Ys]):- par(X), pares(Xs,Ys).
pares([X|Xs],Ys):- impar(X), pares(Xs,Ys).
ordena([]).
ordena([_]).
ordena([X,Y|Ys]):- X<Y, ordena([Y|Ys]).
%Burbuja
bubbleSort(L,S):- swap(L,L1),!, write(L1), nl , bubbleSort(L1 ,S).
bubbleSort(S,S).
%QuickSort
quickSort([] ,[]).
quickSort([X|Xs], Res) :-
split(X,Xs , MasPeques , MasGrandes),
quickSort(MasPeques , PequesOrd),
quickSort(MasGrandes , GrandesOrd),
append(PequesOrd ,[X| GrandesOrd ], Res).
? - write ([ a ,b ,c ,d ,[ e ,f , g ]]) , nl .
? - read ( X ).
? - read ( p ( X )).
? - put (97) , nl .
? - get0 ( X ).
? - get ( X ).
Qué hace el siguiente programa:
readin :-
get0(X),
process(X).
process(42).
process(X) :-
X =\= 42 ,
write(X), nl ,
readin .
writelist([]).
writelist([H|T]) :-write(H), nl,writelist(T).
par(X):- 0 is X mod 2.
impar(X):- 1 is X mod 2.
9, 3,1,0
i=5
j=2
Lista[0] = 999999 Lista[2] = 0
Para i desde 2 Hasta Tamaño(Lista) Haz Lista[1] = 1
j=i
Mientras Lista[j] < Lista[j-1] Haz 3,9,1,0
intercambia(Lista[j],Lista[j-1])
j = j -1 3,1,9,0
FinMientras
FinPara 1,3,9,0
1,3,0,9
1,0,3,9
0,1,3,9