erlang secuencial - ucmgpd.sip.ucm.es/jaime/pda/erlang_secuencial.pdf · 2015-04-14 · lo que...
TRANSCRIPT
Erlang Secuencial
Francisco Javier Lopez Fraguas
April 13, 2015
Parte I - Erlang secuencial
Joe Armstrong – Programming Erlang
You can’t run until you can walk. Erlang programs are made
up from lots of small sequential programs running at the same
time. Before we can write concurrent code, we need to be able
to write sequential code.
Erlang: primer contacto
Computos ≡ evaluacion de expresiones
En la shell de Erlang (interprete de comandos)
Lanzamos computos ; Evaluamos expresiones
Algunas expresiones pueden ser vistas como comandos, e.g:
> c(programa ): compilar un programa> cd(directorio ): cambiar de directorio> i(): informacion sobre procesos> help(): ayuda de la shell. . .
Algunas cosas sobre la Erlang shell
La shell ejecuta (como un proceso Erlang) un bucle eval-print
No olvidar el punto al final de las expresiones a evaluar!>1+2.
(si no se pone, se queda esperandolo y parece que el sistemase ha colgado)
Toda expresion (incluso las que ejecutan ’comandos’) devuelveun valor, salvo que la evaluacion no termine o genere un error.
Algunas soluciones cuando la shell se queda colgada
Crtl+C (Unix), Crtl+Break (Windows)Mejor, Crtl+G
Puede haber varias shells abiertas en la misma sesion
Terminos y expresiones Erlang
Enteros
>20+30.
50
>33 div 5.
6
>33 rem 5.
3
Precision arbitraria> 111111111 * 2222222222* 333333333.
82304526576131687341563786
Podemos usar otras bases distintas de 10>16#11
17
>16#ba
186
Erlang tiene tipado dinamico> 1+true.
** exception error ...
Terminos y expresiones Erlang
Reales en coma flotante
> 20+30.1.
50.1
> 33/5.
6.6
> math:pow(2,100).
1.2676506002282294e30
> trunc(math:pow(2,100)).
1267650600228229401496703205376
Terminos y expresiones Erlang
Atomos
Representan valores constantes
Formados por: caracteres alfanumericos, , @
lunes rojo ok rojo claro paco@ucm
O bien por caracteres cualesquiera encerrados entre ’.’hola hola’ ’[email protected]’ ’1+2’
Un atomo se evalua a el mismo.
Terminos y expresiones Erlang
Expresiones booleanas
true , false son dos atomos mas, pero con unainterpretacion especial: son valores booleanos y con ellos sepueden formar expresiones booleanas.
Expresiones booleanas:not e e1 and e2 e1 or e2 e1 xor e2donde ei son expresiones que se evaluan a un valor booleano.
> not true.
false
> (5>3) or (1<0).
true
> (5>3) and (1<0).
false
> (5>3) or (1<1/0).
** exception
Expresiones booleanas cortocircuitadas
e1 andalso e2 e1 orelse e2
No siguen el regimen de evaluacion impaciente:se evalua e1 y solo si hace falta se evalua e2.
> (5>3) orelse (1<0).
true
> (5>3) andalso (1<0).
false
> (5>3) orelse (1<1/0).
true
BIFs (Built In Functions) para reconocimiento de tipos
> is integer(3).
true
> is integer(3.0).
false
> is float(3).
false
> is float(3.0).
true
> is number(3).
true
> is number(3.0).
true
> is number(1+1.2).
true
> is atom(ok).
true
> is boolean(1>0).
true
Otras BIFs de ese estilo:is tuple is list is function is pid is record . . .
Variables
Formados por: caracteres alfanumericos, , @, empezandopor una mayuscula o por
X X1 X 1 Hola
Lo que nunca encontraremos: X=X+1
No hay variables asignables a un valor que va cambiando+ no hay estado mutable
Las variables aparecen para representar parametros formalesen las definiciones de funciones.
Tambien aparecen en expresiones de ajuste de patrones(pattern matching), en las que una variable puede quedarligada a un valor que ya no puede cambiar.+ variables de asignacion unica .
Expresiones de ajuste de patrones: e1 = e2
No son un test de igualdad (para eso tenemos e1 =:= e2 oe1 =:= e2)
El valor de e1 = e2 es:
El valor de e2 si e1 y e2 se evaluan al mismo valorEl valor de e2 si e1 es una variable no ligada X, que quedaentonces ligada al valor de e2
Este la situacion interesanteMas adelante veremos mas posibilidades para ligaduras devariables por ajuste de patrones
Un error en otros casos (valores no coincidentes, variables noligadas en e2, . . . )
Expresiones de ajuste de patrones: e1 = e2
> 1+1=2+0.
2
> +1=2+2.
error: no match
> X=2+2.
2
> X.
4
> Y.
error: Y unbound
> Y=1+X.
5
> Y.
5
> Y=X.
error: no match
> Y=Y+1.
error: no match
> f(Y).
ok
> X=Y.
error: Y unbound
> Y=X.
4
Expresiones secuencia: e1, e2, . . . , en
Para evaluarla se evaluan (en ese orden) e1, e2, . . . ,en, pero elvalor devuelto es el valor de en.
Tiene sentido usarlas cuando la evaluacion de e1,. . . producealgun efecto lateral.
> 1,2,3.
3.
> R=3.5,math:pi()*R*R.
38.484510006.
> R=3.5,math:pi()*R*R.
38.484510006.
> io:format("abc\n"),timer:sleep(1000),X=2*3,X+4.abc
10
Tuplas
Agrupacion de datos de tamano fijo
Sintaxis: {} Tupla vacıa{e1,e2,...,en} Tupla de n elementos
{1,3} {paco,56} dos tuplas de tamano 2
{persona, {nombre,’Paco’},{apellidos,{’Lopez’,’Fraguas’}},{edad,56}
}Una tupla de tamano 4 formada por otras tuplas
Ajuste de patrones con tuplas
> P = {punto,3,4}.{punto,3,4}
> {punto,X,Y} = P.
{punto,3,4}
> D = math:sqrt(X*X+Y*Y).
5.0
> {Tag,A,A} = {punto,3,3} , {Tag,A}.{punto,3}
> { ,B, } = P , B.
3
> {1,2} =:= {2,1}.false
Algunas BIFs sobre tuplas
> tuple size({punto,3,4}).3
> tuple size({}).0
> element(2,{punto,3,4}).3
> setelement(2,{punto,3,4},10).{punto,10,4}
Muchas BIFs devuelven tuplas como resultado
> time().
{19,22,40}> date().
{2014,10,6}
Listas
Secuencia de datos de tamano arbitrario
Sintaxis: [] Lista vacıa[e1,e2,...,en] Lista de n elementos• e1 es la cabeza de la lista• [e2,...,en] es el resto de la lista
> [1+2,true or false,{ok,3}][3,true,{ok,3}]
+ los elementos pueden ser de tipos distintos
Algunas BIFs (y funciones de librerıas) sobre listas
> hd([1,a,3]).
1
> tl([1,a,3]).
[a,3]
> tl([3]).
[]
> hd([]).
error: bad argument
> length([1,2,3]).
3
> ([1,2,3]++[4,5]).
[1,2,3,4,5]
> ([1,2,3,1]--[3,1,4]).
[2,1]
> lists:reverse([a,b,c])
[c,b,a]
> lists:nth(2,[a,b,c])
[b]
> lists:append([[1,2,3],[4,5],[a,b]]).
[1,2,3,4,5,a,b]
La constructora de listas [ | ]
[h|t] ; lista de cabeza h y resto t
[a,b,c] es lo mismo que [a|[b|[c|[]]]]
[a,b,c] ≡ [a|[b|[c|[]]]] ≡ [a|[b,c]] ≡ [a,b|[c]] ≡[a,b|[c|[]]] ≡ [a,b,c|[]]
La notacion [h|t] sera esencial para expresar el ajuste depatrones al definir funciones sobre listas.
Ajuste de patrones con listas
> X = [1,2,3].
[1,2,3]
> Y = [a|X].
[a,1,2,3]
> [A,B,2,C] = Y,{A,B+C}.{a,4}
> [U|V] = Y , {U,V}.{a,[1,2,3]}
Strings
No hay strings propiamente dichos, son listas de enteros(listas de codigos Unicode)
Pero tenemos un azucar sintactico: ”caracteres”> "Hola".
"Hola"
> "Hola"++",amigo".
"Hola,amigo"
> hd("Hola").
72
> tl("Hola").
"ola"
> [1|"Hola"].
[1,72,111,108,97]
> [72,111,108,97].
"Hola"
> [A,B|C] = "Hola",{A,B,C}.{72,111,"la"}
Convesiones entre tipos
> atom to list(hello).
"hello"
> list to atom("hello").
hello
> integer to list(77).
"77"
> list to integer("77").
77
> tuple to list({a,b,c}).[a,b,c]
> list to tuple([a,b,c]).
{a,b,c}> ...
Modulos y funciones
Modulos
Unidades basicas de codigo
Ficheros con extension .erl
Al compilarlos generan .beam
Constan de directivas y definiciones de funciones
Se pueden compilar desde el SO o desde la shell.
factorial.erl
-module(factorial).
-export([fac/1]). % /1 indica aridad 1
fac(0) -> 1; % Primera clausula de fac
fac(N) -> N * fac(N-1). % Segunda
> c(factorial).
ok,factorial
> fac(7).
** exception error: undefined shell command fac/1
> factorial:fac(7).
5040
El orden de las clausulas es importante
-module(factorial).
-export([fac/1]).
fac(N) -> N * fac(N-1); % mal asunto ...
fac(0) -> 1.
factorial.erl con recursion de cola (last call optimization)
-module(factorial).
-export([fac/1]).
fac(0) -> 1;
fac(N) -> N * fac(N-1). % No hay LCO
facc(0,Acc) -> Acc;
facc(N,Acc) -> facc(N-1,N*Acc). % Hay LCO
Programas con tuplas: paso de parametros por ajuste de patrones
-module(medidas).
-export([area/1,perimetro/1]).
area({cuadrado,L}) -> L*L;
area({rectangulo,X,Y}) -> X*Y;
area({circulo,R}) -> math:pi()*R*R.
perimetro({cuadrado,L}) -> 4*L;
perimetro({rectangulo,X,Y}) -> 2*X+2*Y;
perimetro({circulo,R}) -> 2*math:pi()*R.
% Aqui el orden de las clausulas no importa
Programas con listas: ajuste de patrones, recursion
-module(listas).
-compile(export_all).
% length(Xs)= longitud de la lista Xs
length([]) -> 0;
length([X|Xs]) -> 1+length(Xs).
% O bien, con LCO
length1(Xs) -> length1(Xs,0).
length1([],N) -> N;
length1([X|Xs],N) -> length1(Xs,N+1).
% append(Xs,Ys) = concatenacion de Xs e Ys
append([],Ys) -> Ys;
append([X|Xs],Ys) -> [X|append(Xs,Ys)].
% hd(Xs) = cabeza de Xs ; tl(Xs) = resto de Xs
hd([X|_]) -> X.
tl([_|Xs]) -> Xs.
% nth(N,Xs) = elemento N-simo de Xs, numerando desde 1
nth(1,[X|_]) -> X;
nth(N,[_|Xs]) -> nth(N-1,Xs).
length/1,tl/1,append/2,nth/2 recorren la lista (costelineal)
length/1,hd/1,tl/1 son BIF, append/2,nth/2 estan enlists
append(X,Y) se escribe mejor como X++Y
Patrones con variables repetidas: expresan igualdad
% member(X,Xs) = true si X es elemento de Xs; false e.o.c.
member(X,[]) -> false;
member(X,[X|_]) -> true;
member(X,[_|Ys]) -> member(X,Ys).
% seq(N,M) = [N,N+1,...,M]
seq(N,N) -> [N];
seq(N,M) -> [N|seq(N+1,M)]
member/2 es BIF, seq/2 en lists
¿Cual es la complejidad de esta funcion?
% revese(Xs) = la inversa de la lista Xs
reverse([]) -> []
reverse([X|Xs]) -> reverse(Xs)++[X]
Mejor sera esto. . .
reverse(Xs) -> reverse(Xs,[]).
reverse([],RevAcc) -> RevAcc;
reverse([X|Xs],RevAcc) -> reverse(Xs,[X|RevAcc]).
La funcion lists:reverse/1 esta eficientementeimplementada
Recomendaciones generales para programas que computanlistas como resultado:
Muy preferible computar [X|e] en lugar de e++[X]
Si por hacerlo ası sale el resultado al reves, usarlists:reverse/1
Otras formas de poner condiciones a los argumentos: guardas when
Recordemosfac(0) -> 1;
fac(N) -> N * fac(N-1).
Podemos poner una condicion en la segunda clausulafact(0) -> 1;
fact(N) when N > 0 -> N*fact(N-1).
Aquı sı podemos cambiar el orden de las clausulasfact(N) when N > 0 -> N*fact(N-1).
fact(0) -> 1;
Tambien podemos poner el caso 0 con una guardafact(N) when N > 0 -> N*fact(N-1);
fact(N) when N==0 -> 1.
Otras formas de poner condiciones: expresiones if
facif(N) ->
if N == 0 -> 1;
true -> N*facif(N-1)
end.
Igual preferimos esto otrofacif1(N) ->
if N == 0 -> 1;
N > 0 -> N*facif1(N-1)
end.
O incluso estofacif1(N) ->
if N == 0 -> 1;
N > 0 -> N*facif1(N-1);
true -> no_definido
end.
Otros ejemplos: member/2
% member(X,Xs) = true si X es elemento de Xs; false e.o.c.
Con patronesmember(X,[]) -> false;
member(X,[X|_]) -> true;
member(X,[_|Ys]) -> member(X,Ys).
Con (alguna) guardamember(X,[]) -> false;
member(X,[Y|_]) when X=:=Y -> true;
member(X,[_|Ys]) -> member(X,Ys).
Con ifmember(X,[]) -> false;
member(X,[Y|Ys]) ->
if X=:=Y -> true;
true -> member(X,Ys)
end.
Otras formas de poner condiciones: expresiones case
member(X,[]) -> false;
member(X,[Y|Ys]) ->
case X=:=Y of
true -> true;
false -> member(X,Ys)
end.
Tambien valdrıamember(X,[]) -> false;
member(X,[Y|Ys]) ->
case X=:=Y of
true -> true;
_ -> member(X,Ys)
end.
Expresiones secuencia en el cuerpo de una clasula
sols(A,B,C) = lista de soluciones de Ax2 +Bx+ C = 0sols(A,B,C) ->
D= B*B-4*A*C, % calculamos D como valor intermedio
if D < 0 -> [];
D == 0 -> [-B/2*A];
D > 0 -> [(-B + math:sqrt(D))/(2*A),
(-B - math:sqrt(D))/(2*A)]
end.
Formato general de una definicion de funcion f/n
f(Pat11,...,Pat1n) [when Guardas1] -> expr1;
. . . . . . . . .f(Patk1,...,Patkn) [when Guardask] -> exprk.
Donde
expri puede ser una expresion secuencia
Guardas ::= Guarda1;...;Guardam ; es como orelse
Guarda ::= GExpr1,...,GExprl , es como andalso
GExpr es una expresion booleana formada por algunas BIFs, como==,>,...,is atom,is list,...,pero no funciones de usuario.
Y esto se ejecuta ası: para evaluar f(e1,...,en). . .
Se evaluan e1,...,en, para obtener t1,...,tnAhora, para evaluar f(t1,...,tn)
Se prueban las cabezas de las causulas en su orden hastaencontrar una aplicable a f(t1,...,tn). Si esta es la i, seevalua expri.La cabeza f(Pati1,...,Patin) when Guardasi es aplicablea f(t1,...,tn) si:
Los argumentos t1,...,tn ajustan con los patronesPati1,...,PatinLa guarda Guardasi se evalua a true (recuerda, interpretando; como orelse y , como andalso).
Si ninguna clausula resulta aplicable, se produce un error.
Funciones de orden superior (HO functions)
Un lema famoso de la programacion funcional
Las funciones son ciudadanos de primera clase
Una funcion puede ser argumento o resultado de otra
Funciones de orden superior (HO functions)
Funciones con algun argumento (o el resultado) de tipofuncional.
Favorecen la abstraccion, concision y reutilizacion de codigo.
Funciones de primer orden: las ”normales”, que no son de OS
Funciones de orden superior
Un par de funciones de primer orden...
% inc_list(Xs): suma uno a todos los elementos de Xs
inc(X) -> 1+X.
inc_list([]) -> [];
inc_list([X|Xs]) -> [inc(X)|inc_list(Xs)].
% cabezas(Xss): cabezas de los elementos de Xss
cabezas([]) -> [];
cabezas([X|Xs]) -> [hd(X)|cabezas(Xs)].
Se repite la misma estructura:aplicar una funcion f a todos los elementos de la lista
Funciones de orden superior
Abstraccion de OS: map
% map(F,Xs) = resultado de aplicar F a cada elemento de Xs
% map(F,[X1,...,Xn]) = [F(X1),...,F(Xn)]
-module(ho).
map(F,[]) -> [];
map(F,[X|Xs]) -> [F(X)|map(F,Xs)].
> ho:map(fun erlang:hd/1,[[1,2,3],[2],[7,6,4]]).
[1,2,7]
> ho:map(fun ho:inc/1,[1,3,5])
[2,4,6]
Funciones de orden superior
Recordemos: un par de funciones de primer orden...
inc(X) -> 1+X.
inc_list([]) -> [];
inc_list([X|Xs]) -> [inc(X)|inc_list(Xs)].
cabezas([]) -> [];
cabezas([X|Xs]) -> [hd(X)|cabezas(Xs)].
Pero es mejor usando map/2
inc_list(Xs) -> map(fun ho:inc/1,Xs).
cabezas(Xss) -> map(fun erlang:hd/1,Xss).
Funciones de orden superior
Funciones anonimas (λ-abstracciones)
inc(X) -> 1+X.
> inc(3).
4
' > Inc=fun(X) -> 1+X end.
> Inc(3).
4
fun(X) -> 1+X end. ; funcion anonima
Podemos usarlas en map/2
inc_list(Xs) -> map(fun(X) -> 1+X end,Xs).
% hace innecesaria inc/1
cabezas(Xss) -> map(fun(X) -> hd(X) end,Xss).
% alternativa a fun erlang:hd/1
Otros ejemplos de funciones anonimas
fun(X,Y) -> math:sqrt(X*X+Y*Y) end
fun ({milla,X}) -> {km,X*1.609344};({km,X}) -> {milla,X/1.609344}
end
fun(Xs) -> (fun(X) -> lists:member(X,Xs) end) end
Otros ejemplos de funciones de HO: ¿que hacen?
filter(F,[]) -> [];
filter(F,[X|Xs]) ->
case F(X) of
true -> [X|filter(F,Xs)];
false -> filter(F,Xs)
end.
for(I,J,F) when I<=J -> [F(I)|for(I+1,J,F)];
for(I,J,F) when I>J -> [].
Listas intensionales (List comprehensions)
Notacion inspirada en las Matematicas: conjuntos por comprension
{x2 | x ∈ {1, . . . , 5}} {1, 4, 9, 16, 25}
{x+ 1 | x ∈ {1, . . . , 10}, x2 acaba en 9} {4, 8}
En programacion funcional: map, filter
map(fun(X) -> X*X end,[1,2,3,4,5])
map(fun(X) -> X+1,filter(fun(X)->X*X rem 10 =:= 9 end,seq(1,10)))
O tambien podemos usar notacion de listas intensionales
[X*X || X <- [1,2,3,4,5]]
[X+1 || X <- seq(1,10), X*X rem 10 =:= 9]
Mas ejemplos
[Y || Y <- seq(1,24), 24 rem Y =:= 0] [1,2,3,4,6,8,12,24]
divisores(X) -> [Y || Y <- seq(1,X), X rem Y =:= 0]
es primo(X) -> [Y || Y <- seq(2,X-1), X rem Y =:= 0] =:= []
[{X,Y,X and Y} || X <- [true,false], Y <- [true,false]]
[{Y,X} || X <- [true,false], Y <- [true,false] ,X and Y =:= X or Y]
Morfologıa de las listas intensionales
[ X+1 || X <- seq(1,10) , X*X rem 10 =:= 9]
expresion principal
[X+1 || X <- seq(1,10) , X*X rem 10 =:= 9]
generador
[X+1 || X <- seq(1,10) , X*X rem 10 =:= 9 ] filtro
En general, una lista intensional es: [e || c1,...,cn]
e es una expresionc1 es un generadorCada ci con i > 1 es un generador o un filtroUn generador es de la forma p <- l
l es una expresion cuyo valor es una listap es un patron
Un filtro es una expresion booleana
Generadores
Puede haber varios generadores seguidos[{X,Y} || X <- [1,2] , Y <- [a,b,c]]
[{1,a},{1,b},{1,c},{2,a},{2,b},{2,c}]El orden de los generadores influye[{X,Y} || Y <- [a,b,c] , X <- [1,2]]
[{1,a},{2,a},{1,b},{2,b},{1,c},{2,c}]Generadores multiples actuan al modo de bucles anidados
Un generador p <-l con p no variable tiene un efecto filtropor el ajuste de patrones[X+Y || {{X,Y},a} <- [{{2,1},a},{{1,3},b},{{2,4},a}]][3,6]
Filtros
Puede haber varios filtros seguidosCada filtro actua sobre el resultado de los generadores y filtrosanteriores
Un ejemplo: quicksort
qsort([]) -> [];
qsort([X|Xs]) -> qsort([U || U <- Xs, U < X])
++ [X] ++
qsort([U || U <- Xs, U > X]).
Ternas pitagoricas: (x, y, z) tales que x2 + y2 = z2
-- ternasP(N) = ternas pitagoricas con numeros =< N
ternasP(N)= [{X,Y,Z}|| X <- lists:seq(1,N),
Y <- lists:seq(1,N),
Z <- lists:seq(1,N),
Z*Z == X*X+Y*Y]
% Mejor, para evitar repeticiones
ternasP’(N)= [{X,Y,Z}|| Z <- lists:seq(1,N),
X <- lists:seq(1,Z-1),
Y <- lists:seq(1,X-1),
Z*Z == X*X+Y*Y]
Map, filter, append y listas intensionales
map(F,Xs) = [F(X) || X <- Xs]
filter(P,Xs) = [X || X <- Xs , P(X)]
append(Xss) = [X || Xs <- Xss , X <- Xs]
Recıprocamente toda lista intensional puede expresarse enterminos de map, filter y append.
+ Las listas intensionales son azucar sintactico
Manejo de errores y excepciones
Dos posibilidades en la evaluacion de una expresion
La evaluacion tiene exito y devuelve un valor > 1+2.
3
La evaluacion produce un error > 1+true.
exception error
Se genera o eleva una excepcion (raise an exception)Las excepciones rompen el flujo normal de evaluacionLas excepciones las puede generar:
el sistemael programador
Tipos de errores producidos por el sistema
Function Clause Errors
Case Clause Errors
If Clause Errors
Bad Match Errors
Bad Argument Errors
Undefined Function Errors
Bad Arithmetic Errors
Bad Function Errors
Bad Arity Errors
System Limit Errors
Captura de excepciones
Expresiones try. . . catch: version simple
try e
catch
error:PatronError -> e’
end
> try 1/0 catch error: -> ’Division por cero’.
’Division por cero’
> try 1/2 catch error: -> ’Division por cero’.
0.5
> try 1/0 catch error: -> 0.
0
> try 1/2 catch error:E -> E.
badarith
Captura de excepciones
Expresiones try. . . catch: forma general
try e of
Patron1 [when Guarda1 ] -> e1;
Patron2 [when Guarda2 ] -> e2;
...
catch
exceptionType1 :PatronError1 -> e1’
exceptionType2 :PatronError2 -> e2’
...
end
Tipos de excepciones
error: es el mas habitual.
Las produce el sistema como run-time errorsSe pueden producir mediante la BIF error(Why )
exit: mas ligada a procesos
Se pueden producir mediante la BIF exit(Why )
throw:
Se pueden producir mediante la BIF throw(Why )
Records: tuplas con nombre para las componentes
Personas, representadas como tupas
{Nombre,Apellido1,Apellido2,Edad,Tipo Documento, Num Documento,
Ciudad, Provincia }
{’Francisco’,’Lopez’,’Fraguas’,56,dni, 51334962,
Madrid, Madrid}
Records: tuplas con nombre para las componentes
Ejemplo: personas, representadas como records
. Definicion de la estructura de record para representar personas
> rd(persona, { nombre,ap1,ap2,
edad,tipo doc = dni,num doc,
ciudad = ’Madrid’,provincia=’Madrid’}).
. Creacion de un record persona concreto
> Yo = #persona{ nombre=’Francisco’,ap1=’Lopez’,
ciudad=’Getafe’,edad=56,
num doc=51344962}.
rd/2 se usa en la shell para definir records
En programas hay que usar una directiva-record(Name,{...})Se suelen recolectar definiciones de records en ficheros *.hrl
Los ficheros *.hrl se cargan en otros mediante-include(file ).
Los ficheros *.hrl se cargan la shell mediante> rr(file ).
Acceso a componentes de records
Acceso a una componente concreta:> Yo#persona.edad.
56
O mediante pattern matching de records:> #persona{edad=E,ciudad=C} = Yo.
#persona{...}
> E.
56
> C.
’Getafe’
Creacion de un record por actualizacion de otro
> Yo1 = Yo#persona{ap2=’Fraguas’}.#persona{...}
> Yo#persona.ap2.
undefined
> Yo1#persona.ap2.
’Fraguas’
> Yo1#persona.edad.
56
Los records se muestran con apariencia de records
4> Yo.
#persona{nombre=’Francisco’,ap1=’Lopez’,ap2=undefined,edad=56,tipo doc=dni,
num doc=51334962,ciudad=’Getafe’,provincia=’Madrid}
Pero es azucar sintactico: son realmente tuplas
4> io:write(Yo).
{persona,’Francisco’,’Lopez’,undefined,56,dni,51334962,’Getafe’,’Madrid}ok
Tuplas: manejo de componentes por posicion
Records: manejo de componentes por nombre
Todo el procesado de los records es en tiempo de compilacion
misrecords.hrl
-record(persona,{nombre,ap1,ap2,edad,tipo_doc=dni,num_doc,
ciudad=’Madrid’,provincia=’Madrid’}).
personas.erl
-module(personas).
-include("misrecords.hrl").
nombre_largo(Per) ->
{Per#persona.nombre,
Per#persona.ap1,
Per#persona.ap2}.
% Mejor con ajuste de patrones de record
nombre_largo1(#persona{nombre=N,ap1=Ap1,ap2=Ap2}) ->
{N,Ap1,Ap2}.
% Peor, usando tuplas
nombre_largo2(Per) ->
{element(2,Per),element(3,Per),element(4,Per)}.
Macros: expansiones en tiempo de compilacion
-define(Constante,Valor ).
-define(Func(V1,...,Vn) -> Valor ).
Ejemplos
-define(ESCALA,1000).
-define(Doble(X) -> 2*X).
Una macro MACRO se usa como ?MACRO
-module(mapas).
-define(ESCALA,1000).
escala(X) -> X/?ESCALA.
Las macros se suelen recolectar en ficheros *.hrl
Existen macros condicionales: ver libro o manual
Existen macros predefinidas: ?MODULE,?FILE,?LINE