Вы находитесь на странице: 1из 48

Universidad de Buenos Aires

Faciltad de Ingenier

a
Teor

a del Lenguaje
Erlang
Mirian Quinteros
Luis Arancibia
Patricia Dimasi
1er cuatrimestre
29 de junio de 2013
Erlang

INDICE

Indice
1. Introduccion 3
1.1. Filosofa . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
1.1.1. Let it crash . . . . . . . . . . . . . . . . . . . . . . . . . . 4
1.2. Historia . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
1.2.1. Prehistoria . . . . . . . . . . . . . . . . . . . . . . . . . . 5
1.2.2. Primeros pasos a Erlang . . . . . . . . . . . . . . . . . . . 8
1.3. Sistemas reales que usan Erlang . . . . . . . . . . . . . . . . . . . 9
2. Estructura y sintaxis del lenguaje 9
2.1. Consola o Shell . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
2.2. Variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
2.3. Atoms . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
2.4.

Algebra Booleana y operadores de comparacion . . . . . . . . . . 11
2.5. Tipos de datos . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
2.5.1. Tipos numericos . . . . . . . . . . . . . . . . . . . . . . . 13
2.5.2. Tuplas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
2.5.3. Listas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
2.5.4. Listas de comprension . . . . . . . . . . . . . . . . . . . . 16
2.5.5. Strings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
2.5.6. Otros tipos . . . . . . . . . . . . . . . . . . . . . . . . . . 17
2.5.7. Bit Syntax . . . . . . . . . . . . . . . . . . . . . . . . . . 18
2.5.8. Comprension de binarios . . . . . . . . . . . . . . . . . . . 20
2.5.9. Representacion interna . . . . . . . . . . . . . . . . . . . . 21
2.6. Modulos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
2.7. Estructuras de control . . . . . . . . . . . . . . . . . . . . . . . . 22
2.7.1. Pattern Matching . . . . . . . . . . . . . . . . . . . . . . . 22
2.7.2. Guards . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
2.7.3. If y Case . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
2.7.4. Conversion de tipos . . . . . . . . . . . . . . . . . . . . . 24
2.8. Recurrencia . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
2.8.1. Tail Recursion . . . . . . . . . . . . . . . . . . . . . . . . 25
2.9. Funciones . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
2.9.1. Funciones de alto orden . . . . . . . . . . . . . . . . . . . 27
3. Aspectos de orientacion a Objetos y TADs 27
4. La maquina virtual de Erlang 28
5. Recolector de basura 28
6. Concurrencia 29
6.1. Concurrencia en Erlang . . . . . . . . . . . . . . . . . . . . . . . 29
6.2. Manejo de procesos . . . . . . . . . . . . . . . . . . . . . . . . . . 29
6.2.1. Cliente-Servidor . . . . . . . . . . . . . . . . . . . . . . . 31
1
Erlang

INDICE
7. Manejo de errores 32
7.1. Excepciones . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
7.2. Manejo de errores en programas concurrentes . . . . . . . . . . . 33
7.3. Mecanismos para el manejo de errores . . . . . . . . . . . . . . . 33
7.4. Tolerancia de fallas . . . . . . . . . . . . . . . . . . . . . . . . . . 34
8. Programacion distribuida 34
8.0.1. Creacion de un Nodo . . . . . . . . . . . . . . . . . . . . . 35
8.0.2. Distribucion en Erlang . . . . . . . . . . . . . . . . . . . . 35
8.0.3. Sockets . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
9. Conclusiones 37
A. Aplicaciones de ejemplo 38
A.1. Un algoritmo de Backtracing . . . . . . . . . . . . . . . . . . . . 38
A.2. Chat . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
Referencias 47
2
Erlang
1. Introducci on
Primero que todo, Erlang es un lenguaje de programacion funcional. De
seguro alguna vez todos han trabajado con lenguajes imperativos, y las sen-
tencias como i++ nos resultan normales; en la programacion funcional esto no
esta permitido. De hecho, cambiar el valor de cualquier variable esta estricta-
mente prohibido! Esto podra resultar extra no a la primera impresion, pero si
recordamos las clases de matematicas, es de hecho lo que all aprendimos!
En Erlang tambien hay un gran enfasis en la concurrencia y alta conabili-
dad. Para ser capaz de tener decenas de tareas ejecutandose al mismo tiempo,
Erlang usa el modelo actor, y cada actor es un proceso separado en la maquina
virtual. En otras palabras, si una persona fuera un actor en el mundo de Erlang,
sera una persona solitaria, sentada en una habitacion a oscuras sin ventanas,
esperando que su buzon reciba un mensaje. Una vez que recibe un mensaje,
reacciona a el de una forma especca: pagar la factura de los servicios cuando
los recibe, responder cartas de feliz cumplea nos e ignorar las cartas que no puede
interpretar.
En Erlang todos se comunican estrictamente a traves de cartas. Suena
a una vida muy aburrida, pero esto signica que uno puede pedir a muchas
personas que realicen varias tareas especcas por el, y ninguno de ellos hara algo
mal o cometera un error que tenga repercusiones en el trabajo del resto; inclusive
no sabran de la existencia del resto de la gente.
Saliendo de esta analoga, Erlang fuerza a escribir actores (procesos) que no
compartan informacion con otros bits de codigo a menos que se pasen mensajes
uno a otro. Cada comunicacion es explcita, trazable y segura.
Este lenguaje nace a partir de necesidades del mercado, para cubrir cierto
tipo de problemas que necesitaban modelizarse de determinada forma.
La eciencia para el manejo de concurrencia, la transparencia para la pro-
gramacion distribuida y la madurez de sus bibliotecas de extension, lo hacen
particularmente apto para desarrollos vinculados a sistemas que necesitan cor-
rer indenidamente y que deben ser tolerantes a fallas. Mas a un si sumamos
el aprovechamiento de los multiprocesadores, que hicieron que el interes en el
lenguaje se renueve en los ultimos a nos.
Cuando denimos a Erlang, lo hicimos a nivel lenguaje, pero en un sentido
mas amplio, no es solo eso: Erlang es tambie n un ambiente de desarrollo en su
totalidad. El codigo es compilado a bytecode y corre dentro de una maquina
virtual. Entonces Erlang, al igual que Java, puede correr en cualquier lado.
La distribucion estandar incluye (entre otras cosas) herramientas de desarrol-
lo (compilador, debugger, proler, test framework), el Open Telecom Platform
(OTP) Framework, un web server, un generador de parser, y la base de datos
mnesia, un sistema de almacenamiento por key-value capaz de replicarse en var-
ios servidores, que soporta transacciones embebidas y permite guardar cualquier
tipo de datos Erlang.
La VM y las libreras tambien permiten actualizar el codigo de un sistema en
ejecucion sin interrumpir cualquier programa, distribuir el codigo con facilidad
en muchas computadoras y manejar errores y fallas de una forma simple pero
3
Erlang 1.1 Filosofa
poderosa.
Actualmente hay gran disponibilidad de libros tecnicos y teoricos, papers,
tutoriales y tesis referentes a Erlang y sus caractersticas. Nos ha llamado par-
ticularmente la atencion como muchos desarrolladores experimentados que han
pasado por diversos paradigmas, en especial el de la orientacion a objetos, se
han volcado hacia estos lenguajes hbridos cuya area de cubrimiento es especca
(en este caso, la concurrencia y la distribucion).
1.1. Filosofa
Citando a Mike Williams, uno de los tres creadores de Erlang, losofa de
Erlang se resume en tres items:
Encontrar los metodos correctos Dise no por prototipos
No es bueno solamente tener ideas, debes tambien ser capaz de implemen-
tarlas y saber que funcionan.
Cometer errores en peque na escala, no en un proyecto de produccion.
Lo primero en lo que tenemos que pensar cuando escuchamos el nombre
Erlang es en concurrencia. La concurrencia es el objetivo de Erlang.
Si analizamos la estructuracion del lenguaje distinguimos sus estructuras
funcional y concurrente, pero la primera no es sino una decision de dise no para
facilitar la segunda: la memoria compartida y la concurrencia no se llevan bien.
La programacion declarativa evita efectos secundarios; imponiendo un modelo
funcional, Erlang elimina el uso de locks, sincronizacion, semaforos, etc., simpli-
cando dramaticamente la cantidad de codigo y analisis usualmente asociados
a la programacion concurrente.
Erlang esta pensado para programar sistemas de tiempo real, preparados
para funcionar por largos perodos (eternamente, seg un indica su creador),
en presencia de fallas, a partir de procesos livianos, independientes, que se co-
munican exclusivamente por pasaje de mensajes asncronos. El lugar fsico en
que tales procesos se ejecutan, sea en una maquina o en varias, o el sistema
operativo sobre el que lo hacen, no afecta al codigo.
1.1.1. Let it crash
Dise nar sistemas tolerantes a fallas es extremadamente difcil. Uno puede
intentar anticiparse y razonar acerca de todas las cosas que pueden ir mal en
determinado software y codicar defensivamente para estas situaciones, pero
en un sistema complejo es muy probable que una combinacion de eventos o
entradas conspiren contra el sistema a causa de una falla o bug.
Hay una losofa que en vez de tratar de manejar y recuperar de todos
los estados excepcionales o fallidos, incita a que simplemente el software falle
tempranamente y deje que los procesos se rompan, pero luego los recicla para
atender al proximo request. Esto le da al sistema una especie de autocuracion
4
Erlang 1.2 Historia
en donde este se recupera de una falla sin ceremonias, mientras que libera al
programador del manejo defensivo y excesivo de los errores.
Implementar la semantica let it crash y trabajar con esta mentalidad mejo-
rara casi cualquier aplicacion (no solo los sistemas de telecomunicaciones de
tiempo real). Al adoptar let it crash, la redundancia y la defensa contra los
errores estaran respaldados en la arquitectura en vez de tratar de anticipar
escenarios en el medio del codigo. Esto tambien hace que se implemente mas
redundacia a traves del sistema.
Let it crash se trata de desacoplar la aplicacion e introducir el reconocimiento
asincronico de las cosas que pueden ir mal de manera sorpresiva.
1.2. Historia
Es necesario poner en contexto el desarrollo de este lenguaje. El problema al
que se afrontaba en aquel entonces era de un tema muy especco: la telefona.
1.2.1. Prehistoria
Erlang se gesto en el Computer Science Laboratory en Ericsson Telecom AB
en 1986. Ericsson junto con Televerket habian desarrollado la central telef onica
AXE. AXE, la cual fue desarrollada en 1974 y programada en PLEX, era la
segunda generacion de centrales SPC (store program control) con la que a me-
diados de los 80 genero grandes ganancias a Ericsson.
Joe Armstrong comienza a trabajar en Ericsson y se le encarga la tarea de
desarrollar un nuevo sistema de telefona. La primera motivacion para desarrol-
lar Erlang fue: hacer algo como PLEX, que corra en hardware ordinario, solo
que mejor.
Erlang heredo muchas caractersticas de AXE/PLEX. Entre ellas, la posibil-
idad de cambiar el codigo on the y y el hecho de que los procesos son inde-
pendientes del sistema operativo. Tambien fue importante considerar el pasaje
de mensajes entre procesos para compartir informacion y no usar memoria com-
partida a la que todos los procesos pudieran acceder.
Era primordial tener en cuenta los tiempos que tomaba crear un proceso, el
tiempo que tarda realizar el context switching entre procesos y el tiempo que se
tarda en copiar un mensaje de un proceso a otro.
5
Erlang 1.2 Historia
Figura 1: Ejemplo de modelo en Plex
Los requerimientos que hereda Erlang de Plex/AXE fueron:
Manejar un gran n umero de actividades concurrentes
Las acciones son ejecutadas en algun momento y dentro una cierta canti-
dad de tiempo
Sistemas distribuidos en varias computadoras
Interaccion con el hardware
Software muy grande
Funcionalidad compleja como la interaccion caracterstica
Operacion continua durante muchos a nos
6
Erlang 1.2 Historia
Mantenimiento de software (reconguracion, etc.) sin detener el sistema
Calidad rigurosa y requerimientos de conabilidad
Tolerancia a fallas tanto para errores de hardware y software
La primera forma de encarar el proyecto fue programar POTS (Plain Ordi-
nary Telephone Service) en diferentes lenguajes. Por suerte Ericsson era propi-
etario del hardware necesario para jugar con Unix y de una central telefonica
modicada que permita ser manejada por un VAX11/750.
Figura 2: Vax-11/750, llamada Comet. La CPU tena un tiempo de ciclo de 320
ns (3.125 MHz).
Se programaron SPOTS en Ada, Concurrent Euclid, PFL, LPL0, Frames y
CLU. Joe Armstrong contibuyo al proyecto programando POTS en Smalltalk.
Los POTS en Smalltalk eran excesivamente lentos. Sin embargo, Armstrong
habia desarrollado una notacion que permita modelar el proceso de llamada.

Esta fue bautizada como el algebra telefonica. La misma permita reducir el


ujo de una llamada telefonica a 15 reglas aproximadamente. Un ejemplo de
modelizacion era el siguiente:
7
Erlang 1.2 Historia
- idle(N) abonado N esta idle.
- on(N) abonado N esta on hook. ...
- +t(N, dial tone) agregar tono de dial a A.
- process(A, f) :- on(A), idle(A), +t(A,dial tone),+d(A, []), -idle(A),
+of(A).
Este modelo fue presentado a Roger Skagervall y este armo: este es un
programa Prolog. De esta forma, se introdujo a Armstrong a la programacion
en Prolog. Pero este modelo solo serva para una llamada telefonica, como
hacer con miles de llamadas?
A partir de all, Armstrong perdio el interes en Smalltalk y se concentro en
desarrollar un meta-interprete en Prolog. Este interprete fue creciendo y mu-
tando, pero a un quedaban muchas cosas por pulir.
1.2.2. Primeros pasos a Erlang
Armstrong quera poder manipular no solo procesos concurrentes simples,
sino tambien mecanismos para envo de mensajes entre procesos, y mecanismos
para manejar errores, etc.
Su interprete crecio y algunos de los miembros del laboratorio se interesaron
en lo que Joe estaba haciendo. Lo que comenzo como agregar concurrencia a
Prolog se convirtio mas en un lenguaje por s mismo y lo llamaron Erlang.
Que signica Erlang? Algunos dicen que signica Ericsson Language, mien-
tras que otros dicen que se reere al matematico Agner Krarup Erlang (1878
1929).
Mientras desarrollaban el lenguaje, Armstrong y sus colegas desarrollaron
una losofa alredor del lenguaje, formas de pensar acerca del mundo y formas de
explicar a otros colegas lo que estaban haciendo. Hoy la llaman Programacion
Orientada a la Concurrencia.
En 1987 Erlang ya era considerado un nuevo lenguaje de programacion. Y
era el momento de buscar gente que lo probara.
Fue Mike Williams el que se encargo de conseguir gente que probara el
lenguaje. Esta peque na comunidad de usuarios (solo 3) ira probando todos los
cambios que se incluan dia a da en Erlang.
En 1989 Erlang tiene la oportunidad de salir de las ocinas de Ericsson y es
presentado en una conferencia en Bellcore.
Al mismo tiempo, en 1989 se busca desarrollar una nueva version de Er-
lang, 40 veces mas rapida que el prototipo en Prolog. Para ello, comienza la
investigacion y el desarrollo de una maquina virtual.
En 1991 se a nade distribucion a Erlang.
En 1993 se lanzo la primera version comercial. Ericsson realizo algunos in-
tentos de marketing del lenguaje, que registraron poco exito. Finalmente, en
1998 se separa de Ericsson y se libero como Open Source.
8
Erlang 1.3 Sistemas reales que usan Erlang
1.3. Sistemas reales que usan Erlang
Algunos sistemas desarrollados en Erlang:
El chat de Facebook fue desarrollado casi enteramente en Erlang, aprovechan-
do la capacidad de crear procesos ecientemente por cada usuario conec-
tado.
AXD301, un switch de alta performance para el protocolo ATM, desarrol-
lado por Ericsson. Uno de los primeros y mayores desarrollos en Erlang,
instalado en hardware redundate, permite el reemplazo del hardware y el
software, as como la recuperacion de fallas, sin interrumpir su servicio [3].
Wings 3D, que es un programa de modelizacion 3D. Es un ejemplo de
aplicacion de escritorio en Erlang.
ejabberd, Un servidor de mensajera instantanea Jabber/XMMP.
RabbitMQ, el cual es un framework para manejo de colas de mensajes.
2. Estructura y sintaxis del lenguaje
2.1. Consola o Shell
Erlang posee una shell (Consola), donde se pueden evaluar expresiones, estas
pueden ser desde simples operaciones aritmeticas hasta funciones.
Para abrir el shell de Erlang, uno tiene que dirigirse a la consola de su respec-
tivo sistema operativo e ingresar el comando: erl. Para Windows se recomienda
usar werl.exe que es una implementacion para Windows del shell de Erlang que
posee scrollbars y posee edicion en la lnea de comandos (como el copy-paste). El
prompt del shell espera una expresion Erlang, la eval ua e imprime el resultado.
Toda expresion ingresada en el shell debe terminar con punto (al igual que en
el lenguaje).
A continuacion se muestra un ejemplo donde se multiplican dos n umeros en
base hexadecimal:
Figura 3: Shell
9
Erlang 2.2 Variables
La consola tiene autocompletado al presionar la tecla Tab y tiene combi-
nacion de teclas mediante las cuales podemos listar los procesos corriendo, in-
terrumpir, reanudar o matar procesos, etc.
2.2. Variables
Erlang es un lenguaje con variables de asignacion unica, esto quiere decir
que una vez que le fue asignado un valor a una variable, este no puede cambiar
en el transcurso del programa. Esto implica que una variable sea indistinguible
del valor que almacena. Esto como se vera mas adelante, es la base de la pro-
gramacion concurrente distribuida.
A diferencia de lenguajes de programacion como Oz, las variables no son
dataow, y por lo tanto no pueden ser usadas antes de estar ligadas a un valor.
Erlang utiliza tipado din amico, lo cual signica que no es necesario declarar
el tipo de dato que va a contener una variable, sino que es determinado con la
primera y unica asignacion.
El pasaje de variables a funciones se hace por valor, esto se debe a que el
valor de una variable no puede cambiar en el transcurso de la ejecucion del
programa.
Los nombres de las variables comienzan con una letra may uscula.
El operador = (no las variables) tiene el rol de comparar valores y quejarse
si ellos son diferentes. Lo que hace el operador = cuando mezclamos variables
es que si el lado izquierdo de una expresion es una variable y no esta ligada,
Erlang automaticamente ligara el valor del lado derecho a la variable del lado
izquierdo de la expresion. La comparacion consecuentemente sera verdadera y
la variable mantendra el valor en memoria.
Si se ha guardado un valor erroneo en una variable cuando se trabaja en el
shell se puede borrar la variable ejecutando el comando f(variable). Y si se
desea borrar todos las variables se usa f().
2.3. Atoms
La razon por la cual las variables no pueden tener su primera letra en
min uscula es debido a los Atoms. Los atoms son literales, constantes con su
mismo nombre como valor.
10
Erlang 2.4

Algebra Booleana y operadores de comparacion
Figura 4: Ejemplo de atoms en el shell de Erlang.
Un atom debe ir encerrado en comillas simples si no comienza con una letra
min uscula o si contiene otros caracteres alfanumericos, guion bajo ( ), o arroba.
La expresion 5 en la Figura de arriba muestra que un atom con comillas simples
es exactamente igual a un atom sin ellas.
Los atoms no son iguales a los enumerados de otros lenguajes. Hemos traba-
jado con estructuras que asocian una constante con un valor, como por ejemplo:
GREEN ->1 , BLUE ->2 , BROWN ->3 y para realizar la comparacion debe
coincidir el valor subyacente. Los atoms no son eso. Los atoms permiten olvi-
darse de los valores subyacentes y agregar simplicidad: el color de ojos puede
ser verde, azul o marron y solo esos colores, con esos nombres.
Los atoms son realmente agradables y son una gran forma de enviar mensajes
o representar constantes. Sin embargo, hay un inconveniente al usar atoms para
muchas cosas: un atom se aloja en una tabla de atoms la cual consume memoria
(4 bytes/atom en un sistema de 32-bits, 8 bytes/atom en uno de 64-bits). La
tabla de atoms no es revisada por el recolector de basura, por lo que todos los
atoms utilizados se acumularan all ocupando espacio.
2.4.

Algebra Booleana y operadores de comparacion
En Erlang, el algebra booleana es muy sencilla:
11
Erlang 2.4

Algebra Booleana y operadores de comparacion
Figura 5: Operaciones booleanas en Erlang.
Los operadores and y or siempre evaluaran argumentos a ambos lados del
operador. Si se quiere tener los operadores que eval uan el argumento del lado
derecho si es necesario debe usarse andalso y orelse.
Erlang utiliza algunos simbolos distintos a otros lenguajes para comparar.
Se muestran a continuacion:
Figura 6: Comparacion en Erlang.
En primer lugar, si los lenguajes usualmente usan == y != para comprobar la
igualdad/desigualdad, en Erlang se usa =:= y =/=. Pero hay algo mas: Erlang
no se preocupara si ponemos un oat o un integer en una operacion aritmetica,
pero si lo hara al momento de comparar. Pero no hay que preocuparse, existen
los operadores == y /= que permiten la comparacion entre diferentes tipos de
valores.
Otros operadores de comparacion son <(menor que), >(mayor que), >=
(mayor o igual) and =<(menor o igual). Hay que prestar gran atencion al ultimo
operador, que para el uso com un estara al reves.
Ahora, que pasara si intentaramos sumar un numero y un atom?
12
Erlang 2.5 Tipos de datos
Figura 7: Suma de dos tipos distintos.
Vemos que Erlang nos arroja una excepcion. A Erlang no le gusta el mal
uso de los tipos fundamentales. Sin embargo, si realizamos una comparacion con
diferentes tipos, Erlang nos dejara. Esto se debe a que los creadores de Erlang
pensaron en que sera util poder desarrollar algoritmos que ordenaran cualquier
tipo de terminos.
Figura 8: Comparacion entre tipos.
Seguramente se ve extra no que la ultima comparacion resulte como falsa.
Esto se debe a que en Erlang no existen los valores booleanos true o false.

Estos
en realidad son atoms.
El orden correcto de cada elemento en una comparacion es la siguiente:
number <atom <reference <fun <port <pid <tuple <list <bit string.
2.5. Tipos de datos
2.5.1. Tipos numericos
Los tipos numericos en Erlang son enteros (integer) y punto otante (oat).
Los enteros son de precision arbitraria, esto es, el n umero de dgitos repre-
sentables esta solo limitado por la memoria disponible. Se los puede escribir de
la manera clasica (125, 3, -832), en una base K, seg un la notacion K#Digitos
(2# 01100101, 16# 12ABF1) o a partir del caracter ASCII que representan, con
la notacion $C ($a equivale a 97 y $1 a 49).
Los oat tienen cinco partes: un signo (opcional), una parte entera, un punto,
una parte decimal y un exponente (opcional). Por ejemplo: 1.0 3.14159 -2.3e+6.
Se representan internamente en el formato IEEE 754 de 64 bits.
2.5.2. Tuplas
Las tuplas permiten agrupar varios valores de distintos tipos. Guardan cierta
similitud con los struct de C, con la diferencia de que sus miembros son anoni-
mos. Como ejemplo, supongamos que queremos denir un punto, consistente de
coordenadas X e Y; usando tuplas, podra realizarse como sigue:
13
Erlang 2.5 Tipos de datos
P = {5.0, 0.0}.
Lo que crea una tupla de valor {5.0, 0.0}, cuyos elementos son dos oats.
Para obtener los valores de la tupla, se hace uso de pattern matching (vease
2.7.1):
{X, Y} = P.
De esta forma, las variables X e Y quedan ligadas a los valores 5.0 y 0.0,
respectivamente. Si nos interesa obtener un valor en particular de la tupla e
ignorar el resto, hacemos uso del smbolo como identicador anonimo de vari-
able:
{ , V} = P.
Lo que asigna a V el valor 0.0 e ignora el primer elemento de la tupla.
Una practica com un es la de identicar a la tupla, con un atom en su primer
elemento; as, el ejemplo anterior pasara a ser:
P1 = {point, 5.0, 0.0}.
P2 = {point, -1.0, 2.0}.
Esto facilita escribir funciones que esperan un determinado tipo de tupla,
por ejemplo:
distancia({point, X, Y})-> math:sqrt(X*X + Y*Y).
2.5.3. Listas
Las listas se denen como una serie de valores entre corchetes, separados por
coma; algunos ejemplos son:
[1,2,3,4,5].
[hola, 5, -3.5, juan, {asdasd, 150}].
[1, 2, [3,4,5]].
[].
Como se ve, los elementos dentro de una lista pueden ser de distintos tipos,
incluyendo otras listas. La lista vaca se identica como [].
El primer elemento de la la lista es su cabeza (head), el resto de los elementos
son su cola (tail ).
14
Erlang 2.5 Tipos de datos
Se puede denir una lista en terminos de su cabeza y su cola como L =[H|T],
donde H sera el primer elemento y la lista T sera su cola (Erlang permite que
T no sea una lista, formandose en ese caso una lista impropia, pero este uso no
es sugerido, puesto que la mayora de las funciones asumen que las listas estan
propiamente formadas). Usando esta notacion, pueden tambien incluirse varios
elementos en la cabeza:
T = [4,5,6].
L = [3|T].
L1 = [0,1,2|L].
En este ejemplo, L quedara ligado a [3,4,5,6] y L1 a [0,1,2,3,4,5,6].
La misma tecnica se puede usar para extraer valores de la lista:
L = [1,2,3,4,5].
[L1|L2]=L.
[1,2,3,4|L3]=L.
[1,A,3,4,5]=L.
Luego de esas sentencias, L1 queda ligada a 1, L2 a [2,3,4,5], L3 a [5] y A a
2.
Los operadores injos ++ y permiten la concatenacion y sustraccion de
listas; su funcionamiento se ilustra en el siguiente ejemplo:
L = [1,2,3,4] ++ [5,6,7,8].
L1 = L -- [3,4,5].
Que resultan en el valor [1,2,3,4,5,6,7,8] para L y [1,2,6,7,8] para L1.
15
Erlang 2.5 Tipos de datos
Si se deseara acceder a un elemento de una lista, tenemos varias formas:
usando pattern matching o utilizando las funciones que nos provee el modulo
de listas.
Supongamos que queremos acceder al segundo elemento de una lista. Con
pattern matching deniriamos una funcion como la que sigue:
second ([ _ , X | _ ]) -> X.
Pero tambien podemos aprovechar las funcionalidades que nos provee el
modulo de listas list.
Resultado = list::nth(2, MiLista).
2.5.4. Listas de comprension
Una de las herramientas mas poderosas de Erlang, es la construccion de
listas mediante comprensiones (list comprehensions). La notacion [F(X)||X<
L] signica la lista cuyos elementos son F(X), donde los X se toman de la
lista L. Por ejemplo:
L=[1,2,3,4,5].
L2 = [X*X ||X <- L].
Se puede traducir como L2 es la lista cuyos elementos son el cuadrado de
los elementos de L. Consecuentemente, el valor de L2 sera [1,4,9,16,25].
La forma general de las list comprehensions es: [X || Calicador1, Cali-
cador2, ...], donde X es una expresion arbitraria, y cada calicador es un gen-
erador o un ltro. Un generador tiene la forma Pattern < ListExpr, donde
ListExpr debe evaluar a una lista. Un ltro es una expresion que eval ua a ver-
dadero o falso.
Como ejemplo mas avanzado, consideremos los tros pitagoricos [4]. Los tros
pitagoricos son conjuntos de tres enteros (A, B, C) tales que A
2
+ B
2
= C
2
.
Supongamos que se desean obtener los tros tales que A+B+C <= 20; podemos
hacerlo con la siguiente comprension:
[{A,B,C} ||
A <- lists:seq(1,20),
B <- lists:seq(1,20),
C <- lists:seq(1,20),
A + B + C =< 20,
A*A +B*B =:= C*C].
16
Erlang 2.5 Tipos de datos
Que devuelve la lista [{3,4,5},{4,3,5}]. La funcion list:seq(N0,N1) devuelve
una lista de los enteros comprendidos entre N0 y N1. La comprension puede
leerse como Tomar todos los valores de A, B y C entre 0 y 20, tales que A +
B + C es menor o igual a 20 y que A
2
+B
2
= C
2
.
Las comprensiones de listas permiten obtener listas de manera elegante y
legible, y muchas veces simplican dramaticamente la obtencion de listas que
tomaran decenas de sentencias en programacion estructurada clasica.
Ademas de las herramientas nativas, Erlang provee una poderosa biblioteca
para el procesamiento de listas, con operaciones como sort, map, lter, reverse,
etc.
2.5.5. Strings
Los Strings se expresan entre comillas dobles; estrictamente hablando, no se
trata de un tipo, sino de listas de enteros, que representan el codigo de alg un
caracter. Al ingresar en el shell de Erlang la lista: [72, 111, 108, 97, 33], el
resultado devuelto es Hola!.
2.5.6. Otros tipos
Otros tipos de datos disponibles en Erlang son el binary (paquetes de
n umeros enteros para guardar la informacion mas ecientemente), record (tu-
plas en las que los elementos tienen un atom asociado para referirseles), pid
(identicadores de procesos, vease 6.1), funs (funciones anonimas, vease 2.9).
Entre otros tipos encontramos los records:
Figura 9: Creacion de un record.
Figura 10: Ejemplo de uso de un record.
Tambien Erlang nos provee los proplist para manejar estructuras key-value.
Queues, sets y arrays son otras estructuras disponibles.
17
Erlang 2.5 Tipos de datos
2.5.7. Bit Syntax
Erlang provee abstracciones muy utiles cuando se trata de valores binarios
llevando el pattern matching a otro nivel. Hace que tratar con datos binarios
crudos sea divertido y facil, lo que era necesario para las aplicaciones de teleco-
municaciones para el que fue creado. La manipulacion de bits tiene sintaxis y
modismos que pueden lucir algo raras al principio, pero si se tiene conocimientos
generales de como funcionan los bits y los bytes, tiene mas sentido.
El Bit syntax encierra los datos binarios entre << y >>, los separa en
segmentos legibles, y cada segmento esta separado por comas. Un segmento es
una secuencia de bits de un binario. Supongamos que queremos guardar un
pixel naranja de color real (24 bits). Sabemos que la notacion hexadecimal del
naranja es #F09A29. En Erlang se tratara as:
Figura 11: Uso del bit syntax para un pixel.
Aqu basicamente le decimos poner los valores binarios de #F09A29 en 24
bits de espacio (Red en 8 bits, Green en 8 bits y Blue en 8 bits) en la variable
Pixel. El valor luego puede ser tomado para ser escrito en un archivo. Si abrimos
el archivo veremos muchos caracteres sin sentido, pero si leemos desde el archivo,
Erlang interpretara el binario en un formato agradable: ((240,151,41)).
A continuacion veremos como usar pattern matching con datos binarios:
Figura 12: Pattern matching con bit syntax.
Lo que hicimos en el comando 3 es declarar lo que seran exactamente 4
pixeles RGB en binario. En la expresion 4 intentamos desempaquetar 4 valores
de un contenido binario. Vemos que arroja una excepcion, porque tenemos mas
de 4 segmentos, de hecho tenemos 12! As que lo que hacemos es decirle a Erlang
que cada variable del lado izquierdo contendra 24 bits de datos.
Que pasara si queremos obtener el primer elemento del paquete completo?
18
Erlang 2.5 Tipos de datos
Figura 13: Ejemplo de como ignorar el resto de un paquete.
Vemos que fue muy facil, ya que Erlang acepta mas de una forma de describir
los segmentos binarios. Los formatos validos son los siguientes:
Value
Value:Size
Value/TypeSpecierList
Value:Size/TypeSpecierList
Size esta en bits y TypeSpecierList puede ser uno de los siguientes tipos:
Type: donde los valores posibles pueden ser integer | oat | binary | bytes
| bitstring | bits | utf8 | utf16 | utf32. Representa el tipo de dato binario
usado. Cuando no se especica el tipo, Erlang asume que es integer
Signedness : los valores posibles son signed | unsigned. Solo se tiene en
cuenta si el tipo es integer. El default es unsigned
Endianness: los valores posibles son big | little | native. Solo se toma
en cuenta si el tipo indicado es integer, utf16, utf32, o oat. La opcion
native elegira en tiempo de ejecucion si la CPU usa little-endianness o
big-endianness nativamente. Por defecto, se toma big.
Unit: se escribe como unit:Integer. Es el tama no de cada segmento, en
bits. El rango admitido es de 1 a 256. La multiplicacion de Size por Unit
es igual al n umero de bits que el segmento tomara y debe ser divisible por
8. Se utiliza por lo general para asegurar el alignment.
Los siguientes ejemplos podran ser claricadores:
19
Erlang 2.5 Tipos de datos
Figura 14: Ejemplos de TypeSpecierList.
Erlang es lento en comparacion con lenguajes como C o C++ para calculos
numericos. Sera una mala idea hacer cosas como convertir videos o imagenes
con Erlang, aunque la sintaxis binaria sea tan comoda e interesante.
Hay otro gran aspecto respecto de la notacion binaria: bit strings. Los strings
binarios son otra estructura clave del lenguaje como las listas, pero son mucho
mas ecientes en terminos de espacio. Son mas parecidas a los arrays de C y la
sintaxis es <<this is a bit string!>>. La contra de los strings binarios com-
parados con las listas es la perdida de simplicidad en la manipulacion mediante
pattern matching.
2.5.8. Comprension de binarios
Es el analogo a la comprension de listas, pero en este caso es de binarios.
[ X || <<X>> <= <<1,2,3,4,5>>, X rem 2 == 0].
Donde el resultado es [2,4]. El unico cambio en la sintaxis de las listas de
comprension es que < ahora es <= y se usa <<>> en vez de [].
20
Erlang 2.6 Modulos
2.5.9. Representacion interna
Como se explico, el codigo Erlang se traduce a codigo C al compilarse; al
hacerlo, cada termino se representa mediante un unsigned word de 32 bits,
compuesto de un valor y un tag. El tag, de 4 bits, distingue el tipo del termino.
El valor de un atom es un ndice a una tabla global de atoms, donde este
es representado. Para un entero, el valor es el propio entero. El valor de una
lista es un puntero a dos espacios consecutivos en el heap, correspondientes a la
cabeza y la cola de la lista. El valor de una tupla es un puntero a un espacio en
el heap con el n umero de elementos de la tupla, seguido por los elementos. El
valor de un oat es un puntero a un espacio en heap que contiene un oat de
dos words. El valor de un identicador de procesos, es el propio identicador.
2.6. Modulos
Toda funcion debe pertenecer a un modulo, siendo esta la unidad basica de
Erlang. Los modulos son los encargados de delimitar la visibilidad de las fun-
ciones que contienen y a su vez permiten dividir grandes programas en unidades
menores.
Cada modulo tiene atributos, estos denen sus caractersticas. Los atributos
siempre deben estar al principio del archivo a compilar, pueden ser predenidos
o denidos por el usuario. Los atributos predenidos mas usuales son:
-module(nombreModulo)
Indica el nombre del modulo, debe coincidir con el nombre del archivo a
compilar. Es obligatorio.
-import(Modulo, [Nombrefuncion/CantidadParametros])
Importa una funcion de otro modulo, lo que nos permite llamar a esa
funcion sin tener que indicarle el modulo de donde fue importada.
-export([Nombrefunci on/CantidadParametros])
Nos permite exportar funciones para que estas sean visibles y puedan ser
evaluadas.
A continuacion se muestra un ejemplo:
-module(ejemploModulo).
-export([ejemploFuncion/0]).
-import(lists, [foreach/2]).
En este caso, el nombre del modulo es ejemploModulo, exporta la funcion
ejemplofuncion (cero parametros) e importa la funcion foreach (dos parametros)
del modulo lists.
21
Erlang 2.7 Estructuras de control
2.7. Estructuras de control
2.7.1. Pattern Matching
Pattern matching (reconocimiento de patrones) es la herramienta elemental
para la programacion secuencial en Erlang.
En terminos simples, la operacion de Pattern Matching eval ua la coinciden-
cia entre una expresion y un patron. Esta coincidencia se realizara si ambos
tienen el mismo valor, o si se puede lograr que lo tengan a partir del ligado
de identicadores en la expresion. La forma mas com un de esta tecnica, es la
correspondiente al operador =, por ejemplo:
X = 2 + 4.
X = 6.
Y = X.
Y=6.
En este caso para que la expresion X coincida con el valor 6, se asigna tal
valor a la variable; luego el patron coincide pues el valor de X es el mismo al
que se lo iguala. Lo mismo sucede con Y.
La utilidad del reconocimiento de patrones se aprecia mejor al usarlo con
tuplas y listas:
{X, ,abc} = {123,0.1,abc}.
[H|T]=[1,2,3,4,5].
[A,B,C|D] = [a,b,c,d,e,f].
Aqui se realizan las asignaciones X 123, H 1, T [2, 3, 4, 5], A a,
B b, C c, D [d, e, f].
Cuando se intenta usar el operador = con un patron que no coincide, el
sistema lanza una excepcion, por ejemplo en el caso:
{X,Y}={a, abc, 3}.
{A,B,A}={true, 0.0, 122}.
Ambas sentencias fallaran, en el primer caso, por que las tuplas tienen difer-
ente forma, y en el segundo por que se intenta asignar a A dos valores distintos.
Ademas de sus usos para realizar asignaciones y desempaquetar valores, el
pattern matching es esencial para controlar el ujo de los programas. Se vio su
utilidad para elegir la clausula con la que se ejecuta una funcion (2.9); asimismo,
las sentencias de control case e if que se describen a continuacion, la sentencia
catch para la recuperacion de errores (7), y la sentencia receive para la recepcion
de mensajes entre procesos (6.1), entre otras, se construyen en terminos de
reconocimiento de patrones.
22
Erlang 2.7 Estructuras de control
2.7.2. Guards
Las guards son construcciones sintacticas que permiten renar el pattern
matching.
Una de sus formas de uso es a traves de la palabra when, en el encabezado de
funciones (o en la sentencia case, como se vera). La funcion max puede denirse
usando guards como:
max(X, Y) when X > Y -> X;
max(X, Y) -> Y.
El patron de la primera clausula se realizara solamente si se cumple que
X > Y .
Las guards tambien pueden ser usadas como secuencias de expresiones logi-
cas. Las expresiones separadas por punto y coma eval uan a true si alguna de
ellas lo hace (funciona como un or); las separadas por comas eval uan a true si
todas lo hacen (funciona como and). Por ejemplo:
is integer(X), X > Y ; abs(Y) < 23
Se puede leer como X es un entero y es mayor que Y, o el valor absoluto
de Y es menor que 23.
Debe notarse que en general, no se pueden usar funciones dentro de las
guards (excepto ciertas funciones de chequeo de tipo provistas por el lenguaje).
Esto se soluciona asignando el resultado de la funcion requerida a una variable,
y luego usandola en la guard; sin embargo, esto puede resultar poco eciente
(si provoca la ejecucion de funciones costosas cuyos resultados no se llegan a
evaluar) y reduce la legibilidad del codigo.
2.7.3. If y Case
Tecnicamente un programa se puede controlar por completo mediante lla-
madas a funciones y reconocimiento de patrones en sus clausulas; por conve-
niencia sin embargo, Erlang introduce sentencias if y case.
La forma general del if es:
if
Guard1 ->
Expr seq1;
Guard2 ->
Expr seq2;
...
end
Si se quiere que una accion se ejecute cuando ning un guard es verdadero
(lo que permite la palabra else en muchos lenguajes), simplemente se agrega un
23
Erlang 2.7 Estructuras de control
guard con la palabra true, que evaluara siempre a verdadero, y se ejecutara si
ning un guard anterior lo hace. Como ejemplo:
if
X > 100 ->
X es mayor que 100;
X =:=100 ->
X es 100;
true ->
X es menor que 100
end
La forma general del case es:
case Expression of
Pattern1 [when Guard1] -> Expr seq1;
Pattern2 [when Guard2] -> Expr seq2;
...
end
El mismo ejemplo anterior se puede reescribir en un case como:
case X of
X when X > 100 -> X es mayor que 100;
100 -> X es 100;
X -> X es menor que 100;
end
2.7.4. Conversion de tipos
Erlang, como muchos lenguajes, cambian el tipo de un termino casteandolo
a otro tipo. Esto se hace gracias a algunas funciones predenidas en el modulo
erlang:
24
Erlang 2.8 Recurrencia
Figura 15: Casteo de tipos en Erlang.
2.8. Recurrencia
Erlang no soporta nativamente bucles como while y for; en cambio, las it-
eraciones se manejan siempre por recurrencia. En este aspecto, vale mencionar
que Erlang realiza tail recursion [7].
Figura 16: Recurrencia
2.8.1. Tail Recursion
Tail recursion es una forma de transformar un proceso lineal (que crece
proporcional a la cantidad de elementos) a un proceso iterativo ( donde no hay
realmente un crecimiento). Esto evita el apilamiento de funciones reduciendola
mientras se ejecuta.
25
Erlang 2.9 Funciones
Para lograr estas funciones, es necesario contar con una variable extra que
funcione como acumulador. Veamos un ejemplo:
tail_fac(N) -> tail_fac(N,1).
tail_fac(0,Acc) -> Acc;
tail_fac(N,Acc) when N > 0 -> tail_fac(N-1,N*Acc)
2.9. Funciones
Las funciones tienen un encabezado y un cuerpo. El encabezado consiste en
el nombre de la funcion y un patron (entre parentesis), mientras que el cuerpo
consiste en una serie de sentencias que nalizan con coma, excepto la ultima
que lo hace con un punto. A continuacion se muestra un ejemplo de una funcion
basica:
-module(cuadrado).
-export([area/1]).
%Calcula el area de un cuadrado
area(Lado) -> Lado * Lado.
En este caso la funcion se llama area, y acepta solo un argumento. Cuando
alguien llame a esta funcion, lo que se va a ejecutar es el cuerpo de esta, que
se encuentra a la derecha de la echa. Para documentacion interna se utiliza el
caracter %, que permite agregar comentarios hasta el n de la lnea.
Algo para destacar es el orden de evaluacion de las funciones, supongamos
que tenemos una funcion:
funcion(funcionUno(), funcionDos(), funcionTres())
En Erlang no hay forma de determinar cual va a ser el orden de evaluacion.
26
Erlang
2.9.1. Funciones de alto orden
Las funciones de alto orden son llamadas fun en Erlang, y se utilizan como
funciones anonimas. No tienen nombre y su utilidad se basa en que pueden ser
ligadas a variables, y a su vez estas variables pueden ser evaluadas en otras fun-
ciones. Esto permite el pasaje de funciones como argumento de otras funciones,
y permite crear funciones que devuelvan funs lo que nos habilita una amplia
gama de posibilidades a la hora de programar.
El modulo lists, nos provee la funcion map(Fun, List), la cual se encarga de
aplicarle a cada elemento de una lista, la funcion Fun.
Figura 17: ejemplo funcion alto orden
En el ejemplo anterior primero se crea una lista L, y a continuacion se crea
una funcion anonima la cual se asigna a la variable ElevarCuadrado. Con estas
dos variables ya ligadas, se llama a la funcion lists:map que se encarga de mapear
la funcion elevarCuadrado a cada miembro de la lista L.
3. Aspectos de orientaci on a Objetos y TADs
Al no haber estado mutable, Erlang no soporta el concepto de ADT u objeto
(puesto que no hay un estado que empaquetar junto con el comportamiento), y
desde ya tampoco el de herencia.
La forma mas cercana a los tipos denidos por el usuario es la de usar tuplas
con atoms de indenticacion, o records, como se mostro previamente.
Sin embargo, esto no implica una desventaja; a un ignorando los benecios
relacionados a la simplicidad de la concurrencia cuando no hay estado compar-
tido, Erlang se trata de un lenguaje funcional (paradigma de utilidad largamente
probada), en el que importan los valores y como estos se eval uan a traves de
funciones, mas que las entidades.
Para ilustrar esta idea, usamos un ejemplo propuesto por Joe Armstrong [4].
Supongamos que queremos calcular el area de diferentes guras geometricas:
crculos, cuadrados, rectangulos. La solucion en Erlang tendra la forma:
area({rectangulo, B, H})-> B * H;
area({cuadrado, L})-> L * L;
area({circulo, R})-> 3.14159 * R * R.
27
Erlang
Si pensamos en otros lenguajes como C++, tendriamos que declarar clases
que hereden de otras y reescribir los metodos de calcular el area para cada forma.
Y de solo pensarlo, ya sabemos que sera mucho mas largo el codigo C++ que
el de Erlang.
Gracias a que el lenguaje es de tipados dinamico, el polimorsmo se obtiene
gratuitamente; esto es, una funcion puede ser aplicada a cualquier tipo de
argumentos para el que su denicion tenga sentido. Por ejemplo:
sumar(X, Y)-> X + Y.
Puede aplicarse tanto a enteros como a oats, puesto que ambas pueden usar
el operador +. Si ahora queremos que la funcion sumar tambien pueda aplicarse
para concatenar listas (no vacas), podemos lograrlo simplemente agregando una
clausula que contemple este caso:
sumar(X=[ | ],Y=[ | ])->X++Y;
sumar(X, Y)->X+Y.
(La clausula agregada se podra reescribir en forma mas elegante usando
guards (vease 2.7.2) y la funcion is list(L)).
Los ejemplos anteriores nos permiten contrastar las losofas de los paradig-
mas orientado a objetos y funcional: mientras que el primero propone que la
misma rutina se dena seg un corresponda en cada entidad a la que se puede
aplicar, el segundo propone que las distintas deniciones de una misma rutina
se hagan juntas.
4. La maquina virtual de Erlang
La primer maquina virtual de Erlang, implementada en Prolog, se llamaba
JAM (Joes abstract machine). Aqu cada proceso tena su propio heap y stack,
y era una maquina de pila (stack machine). Fue reemplazada por BEAM
(Bogdanss Erlang Abstract machine). BEAM transforma el codigo de Erlang
a C, logrando que el resultante pueda ser compilado por cualquier compilador
convencional de C.
Compilar a C mejora la portabilidad del programa y permite que otros
lenguajes trabajen con el codigo de Erlang, ya que la mayora poseen interfaces
para C.
5. Recolector de basura
A diferencia de lenguajes de programacion como C y C++, Erlang posee
un recolector de basura. El recolector de basura es el encargado de liberar la
memoria que no es mas usada, esto permite al programador abstraerse de la
administracion de memoria y los problemas inherentes a esta.
28
Erlang
El recolector de basura usa el algoritmo de detener y copiar, que consiste
en dividir el heap en dos regiones, una ocupada por todas las variables activas
y una region inactiva desocupada. Cuando la memoria de la region activa se
acaba, el algoritmo copia todas las variables vivas a la region inactiva, y as las
regiones cambian sus roles. Despues de cada recoleccion, el tama no de heap se
ajusta, seg un lo requiera la ejecucion. Este proceso se repite indenidamente
hasta el n de la ejecucion del programa.
Cada proceso de Erlang tiene su propio heap, y realiza su recoleccion de
basura; de esta forma, el tiempo de recoleccion corresponde al del mayor proceso
Erlang activo.
6. Concurrencia
6.1. Concurrencia en Erlang
Erlang es un lenguaje donde la concurrencia pertenece al lenguaje de pro-
gramacion y no al sistema operativo. Erlang hace facil la programacion paralela
modelando el mundo como un conjunto de procesos paralelos que unicamente
pueden interactuar entre si mediante intercambio de mensajes. En el mundo de
Erlang, hay procesos paralelos, pero no bloqueos ni metodos de sincronizacion
y tampoco posibilidad de corrupcion de memoria compartida, ya que no hay
memoria compartida.
Los programas en Erlang pueden estar formados por miles de procesos ex-
tremadamente ligeros que pueden ejecutarse en un solo procesador, en uno de
varios n ucleos o en una red de procesadores.
Muchos lenguajes de programacion de uso masivo(C, C++ y Java) no so-
portan concurrencia de forma nativa, y convierten la concurrencia en algo ex-
tremadamente difcil de lograr y mantener. Con Erlang, muchos de esos proble-
mas se ven resueltos.
Erlang tiene un modelo de concurrencia basado en procesos (equivalentes a
los threads de otros lenguajes) con envos de mensajes asincronicos, esto signica
que una vez envan un mensaje no esperan a que este sea a recibido; siguen con
lo que estaban haciendo. Incluso si el proceso al que le fue enviado un mensaje
hubiera nalizado, el que lo envio no se enterara.
Los procesos son independientes del sistema operativo, son extremadamente
livianos, requieren poca memoria, y crearlos o destruirlos requiere poco esfuerzo.
Todo esto permite que un programa pueda estar compuesto de miles de procesos
interactuando a la vez. Otra caracterstica fundamental es que son autonomos,
esto quiere decir que cada uno se puede ver como una unidad computacional
separada, con su respectiva memoria y recolector de basura.
6.2. Manejo de procesos
Cada proceso tiene una casilla de mensajes y todos los mensajes que le son
enviados son guardados en esta en el mismo orden en que llegan.
29
Erlang 6.2 Manejo de procesos
Para el control de estos procesos, Erlang posee tres primitivas basicas:
spawn(funcionAnonima)
Crea un nuevo proceso concurrente que eval ua la funcion anonima que se
le pasa como parametro. Spawn devuelve el ID del proceso (PID), el cual
nos permite luego mandarle mensajes.
Pid ! Mensaje
El operador ! permite enviar mensajes de forma sencilla si se conoce el PID
del proceso destino. El mensaje consiste en una variable de cualquiera de
los tipos antes vistos.
Este operador, ademas de enviar el mensaje lo devuelve, por lo tanto se
pueden concatenar envos de la siguiente forma:
Pid1 ! Pid 2 ! Pid3 ! ... ! Pid N ! Mensaje
receive - end
La primitiva receive permite que un proceso reciba mensajes. Cuando se
ejecuta un receive, se comparan los mensajes de la casilla del proceso con
los patrones listados (de forma similar a un case, y se ejecuta la expresion
correspondiente en caso de una coincidencia. Si ninguno de los mensajes
coincide, se suspende la ejecucion hasta que un mensaje que lo haga arribe
al proceso.
Una opcion muy interesante que se le puede agregar a la primitiva receive
es un timeout (tiempo maximo de espera), Que permite que en caso de
que el receive no haya recibido ning un mensaje en el tiempo indicado (en
milisegundos) despues de la palabra after se ejecute automaticamente la
expresion que le responde al after. Un timeout de 0 simplemente chequea
la casilla y si no hay mensajes que coincidan con los patrones listados,
contin ua la ejecucion.
La forma generica del receive es:
receive
Patron1 [when Guard1] ->
Expresion1;
Patron2 [when Guard2] ->
Expresion2;
...
after TiempoEnMilisegundos ->
Expresion
end
El siguiente codigo ejemplica el uso de estas primitivas:
30
Erlang 6.2 Manejo de procesos
-module(saludador).
-export([loop/0]).
loop() ->
receive
{nombre,Nombre} ->
io:format(Hola pn,[Nombre]),
loop();
Other ->
io:format(No entendi: pn,[Other]),
loop()
end.
El codigo del ejemplo se trata de un bucle innito que, mediante el receive,
espera que se le enven datos. Este proceso durara toda la ejecucion del programa
ya que el bucle que contiene nunca termina de ejecutarse dado que se llama a
si mismo al nalizar cada expresion.
A continuacion se muestra el codigo en ejecucion:
Primero se crea el proceso mediante la funcion spawn que nos devuelve el
PID del proceso que se creo. En la lnea siguiente, se le enva al proceso el tuple
nombre, juan, y mediante pattern matching, el receive de la funcion loop/0 lo
asigna al patron nombre, Nombre, y por lo tanto imprime : Hola Juan.
El problema que surge del modelo anterior, es que es necesario conocer el PID
del proceso para enviarle un mensaje. Esto se soluciona mediante las siguientes
funciones, que permiten asociar atoms como seudonimos para los identicadores
del proceso:
register(Atom, PID): Registra el PID con el nombre Atom.
unregister(Atom): Desregistra el proceso asociado a Atom.
registered(): Muestra todos los procesos registrados.
6.2.1. Cliente-Servidor
La arquitectura cliente-servidor es una patron fundamental en Erlang; se
reere a los roles que toman los procesos. El proceso cliente es el que realiza
las peticiones, mientras que el proceso servidor es el que se encarga de procesar
31
Erlang
estas peticiones y enviar una respuesta. Estos procesos pueden corren en una o
varias computadoras.
Un ejemplo de la arquitectura cliente-servidor es la forma en que trabaja
un servidor web. Un servidor web permanece pasivo en espera de las peticiones
de los navegadores (los clientes) y al recibir una se encarga de procesarlas y
enviarles la pagina web que buscan.
7. Manejo de errores
7.1. Excepciones
El manejo elemental de errores en Erlang no se aleja mucho del de la mayora
de los lenguajes que hacen uso de excepciones.
Existen tres alternativas para lanzar una excepcion: exit(Razon), para ter-
minar un proceso (vease 7.3); erlang:error(Razon), para errores crticos (equiv-
alentes a los errores generados inernamente por Erlang), y la forma mas usual:
throw(Razon).
Para atrapar esos errores se utiliza una sentencia try...catch; su forma generi-
ca es:
try FuncOrExpressionSequence of
Pattern1 [when Guard1] -> Expressions1;
Pattern2 [when Guard2] -> Expressions2;
...
catch
ExceptionType: ExPattern1 [when ExGuard1] -> ExExpressions1;
ExceptionType: ExPattern2 [when ExGuard2] -> ExExpressions2;
...
after
AfterExpressions
end
Primero, se eval ua FuncOrExpressionSequence; si tal evaluacion no arroja
excepciones, se procede a comparar el resultado con los patrones siguientes. Este
funcionamiento es identico al de una sentencia case.
En caso de que una excepcion sea lanzada, se realiza pattern matching de
ella con la expresiones luego del catch: ExceptionType es el tipo de error (exit,
error o throw), ExPattern es el patron con el que se eval ua la razon con que se
arrojo la excepcion.
Las expresiones entre el after y el end se ejecutaran siempre, haya errores o
no; su uso es identico al nally de Java. El valor que devuelven estas expresiones
se pierde.
El siguiente programa explora las distintas alternativas:
32
Erlang 7.2 Manejo de errores en programas concurrentes
lanzador(1) -> Sin errores;
lanzador(2) -> throw(Throw);
lanzador(3) -> exit (Exit);
lanzador(4) -> erlang:error(Error).
atrapador(N)->
try lanzador(N) of
X -> X
catch
throw: X -> X;
exit: X -> X;
error: X -> X
end.
Si se ejecuta la funcion atrapador con argumento 1 devuelve Sin Errores;
con 2, devuelve Throw; con 3, devuelve Exit; con 4, Error.
7.2. Manejo de errores en programas concurrentes
La idea fundamental en el manejo de errores de Erlang son los procesos
enlazados (linking processes). Cuando dos procesos estan enlazados, si uno ter-
mina el otro recibira una se nal de salida, informando la razon de esa terminacion
(nalizo su tarea o a causa de un error).
Cuando la terminacion es causada por un error, tal error se propagara ter-
minando los procesos enlazados, hasta que encuentre uno capaz de atrapar la
se nal de error; tales procesos son llamados procesos de sistema (system process-
es). Los procesos de sistema reciben las se nales de exito como mensajes, que
pueden ser procesados con la sentencia receive.
Este patron es similar al de las excepciones: se propagan hacia niveles mas
altos, hasta que uno sea capaz de manejarla.
De esta manera, Erlang permite el manejo remoto de los errores: el proceso
que arregla un error no tiene que ser el mismo en el que se genera, ni siquiera
tiene que estar en la misma computadora.
7.3. Mecanismos para el manejo de errores
Para enlazar dos procesos, se hace uso de la funcion link(Pid), que enlace
al proceso que la llama con aquel cuyo identicador es Pid. Alternativamente
se puede hacer uso de spawn link(Fun), que crea un nuevo proceso y al mismo
tiempo lo enlaza a su creador.
Cuando ocurre un error, o cuando se llama a la funcion exit(Razon), el
proceso termina y una se nal de salida se envia a aquellos a los que esta enlazado.
Si el proceso termina normalmente sus tareas, se enva el mensaje con la razon
normal.
33
Erlang 7.4 Tolerancia de fallas
Para indicar que un proceso debe ser de sistema, esto es, que podra atrapar
las se nales de salida de los procesos a los que esta enlazado, debe llamar a
la funcion process ag(trap exit, true). Las se nales de salida recibidas seram
entonces convertidas en mensajes de la forma {EXIT,Pid,Razon} y acoladas
en la casilla del proceso.
Ejemplicando lo anterior, la siguiente lnea:
spawn link(fun()-> 10/0 end).
Produce un error de division por cero en el proceso lanzado, que se propaga
al proceso en que se ejecuto la lnea. Si ahora se la modica, haciendo que el
proceso en que se ejecuta el spawn link sea un proceso de sistema:
process flag(trap exit, true).
spawn link(fun()-> 10/0 end).
receive
X-> X
end.
Se recibe el mensaje: {EXIT,<0.41.0>,{badarith,[{erlang,/,[10,0]}]}}, in-
dicando que el proceso <0.41.0> termino por el error descripto en el stack trace
[{erlang,/,[10,0]}].
7.4. Tolerancia de fallas
Uno de los requerimientos esenciales de los sistemas que originaron el de-
sarrollo de Erlang es la tolerancia a fallas. La idea de la tolerancia a fallas en
el software es la posibilidad de que los sistemas contin uen funcionando aun en
presencia de errores; esto se logra creando procesos que monitorean a aquellos
que realizan una tarea y estan listos para continuarla en caso de que fallen. Este
patron se llama trabajador-supervisor.
Erlang facilita este esquema de programacion a partir de la funcion link
descripta antes, y de la posibilidad de correr procesos en diferentes maquinas.
Un estudio en detalle del desarrollo de sistemas tolerantes a fallas, se en-
cuentra en [3].
8. Programaci on distribuida
Los programas distribuidos son aquellos que estan preparados para trabajar
en una red de computadoras.
Las ventajas que nos trae la programacion distribuida son:
Velocidad:
34
Erlang
Podemos dividir la aplicacion en varios procesos, y que distintas computa-
doras se encarguen de una determinada parte de estos.
Extensibilidad:
Si es necesario mas poder computacional frente a determinadas opera-
ciones, uno simplemente puede agregar mas computadoras.
Programas inherentemente distribuidos:
Algunos programas solo existen de forma distribuida, por ejemplo una sala
de chat.
Para entender la programacion distribuida en Erlang, hay que conocer dos
conceptos fundamentales:
Nodos
Un nodo es un sistema Erlang que contiene su propia virtual machine y
procesos. Cada nodo puede realizar transacciones de caracter distribuido.
Cookies
Cada nodo tiene asignado un string secreto llamado cookie. Para que un
nodo se comunique con otro nodo, necesita conocer la cookie. La forma en
que cada Nodo conoce la cookie del otro, depende del sistema operativo.
En los sistemas operativos UNIX se guardan en /home/.erlang.cookies.
8.0.1. Creacion de un Nodo
Para crear un nodo, dependiendo del uso del nodo se va a tener que ingre-
sar en la lnea de comandos de su respectivo sistema operativo alguno de los
siguientes comandos:
Misma computadora: erl -sname unNombre
Diferentes computadoras: erl -name unNombre -setcookie nombreCookie
El nodo que se va a crear se va a llamar unNombre@nombreHost, el cual
debe ser un atomo por lo que si se no respeta las caractersticas del tipo atomo,
se encierra al nombre del nodo entre comillas simples.
8.0.2. Distribucion en Erlang
Erlang distribuido permite crear programas para trabajar en una red local
interna, un ambiente seguro, dado que permite con libertad realizar cualquier
operacion. Tpicamente los programas de Erlang distribuido corren en un cluster
detras de un rewall.
A continuacion se muestra un ejemplo:
35
Erlang
-module(contador).
-export([start/0, sumaUno/0, detener/0]).
start() -> register(contador, spawn(fun() -> loop(0) end)).
sumaUno() -> contador ! {contar}.
detener() -> contador ! {detener}.
loop(ContadorActual) ->
receive
{contar} ->
io:format(Numero de veces que fui
llamado: pn,[ContadorActual +1]),
loop(ContadorActual+1);
{detener} ->
true
end.
Como muestra el codigo, el start lo que hace es registrar un proceso llamado
contador que se trata de un bucle que recibe mensajes. El modulo tambien
exporta otras dos funciones, sumaUno y detener. La tarea de sumaUno es volver
a llamar el loop con el valor actual +1 e imprimir este nuevo valor. detener se
encarga de que el proceso devuelva true y no vuelva a llamarse a s mismo y,
por lo tanto, naliza el proceso contador.
Como se puede ver en el codigo, este programa puede ser usado en una sola
consola, en varias en la misma computadora o en una red de computadoras,
pero esto recien se nota en la forma de llamar las funciones en la shell, el codigo
interno es sorprendentemente el mismo.
Algunas de las primitivas basicas para trabajar nodos y procesos son:
spawn(Node, Mod, Func, ArgList)
Crea un proceso en un nodo remoto, devuelve un PID.
spawn link(Node, Mod, Func, ArgList)
Crea un proceso en un nodo remoto, devuelve un PID y crea un link al
proceso.
disconnect node(Node)
Desconecta el nodo pasado por parametro de aquel que invoca la funcion.
nodes()
Devuelve una lista con todos los nodos visibles.
36
Erlang
is alive()
Devuelve true si el nodo que lo invoca es parte de un sistema distribuido.
8.0.3. Sockets
Un socket es simplemente un canal de comunicacion abstracto entre dos
procesos que pueden estar ejecutandose en una o varias computadoras. Lo pro-
gramado con sockets es mas lento que lo programado con Erlang distribuido,
pero la ventaja que tiene es que permite realizar programas destinados a correr
en ambientes no seguros.
Para transmitir/recibir informacion entre Nodos, tienen que poder entender-
se, para lo que los sockets de Erlang usan el protocolo TCP/IP. El protocolo IP
(Internet Protocol) es el protocolo que usa Internet; como no tiene mecanismos
para asegurar que un paquete llegue a su destino y proporciona escasa seguri-
dad, se usa en conjunto con el protocolo TCP (Transmission Control Protocol)
que es el encargado de asegurar la recepcion de los mensajes y a su vez de que
estos arriben en el orden correcto.
9. Conclusiones
Nos hemos encontrado con dos barreras importantes al elaborar este informe
e investigar Erlang: el paradigma concurrente y la programacion funcional.
La segunda fue producto de no interactuar de forma intensiva con el lenguaje
y por ende hay estructuras e ideas que no fueron faciles de plasmar en un
lenguaje funcional.
La primera tiene que ver con la poca introduccion al paradigma concurrente
y los problemas que intenta resolver. Es facil dejarse llevar por el paradigma al
que venimos acostumbrados: la orientacion a objetos.
Sin embargo, la sintaxis y el manejo de Erlang en general no esconde muchos
secretos: hay buena documentacion y ejemplos para poder introducirse al mundo
Erlang. Es comodo para trabajar con problemas naturalmente concurrentes.
Nos queda a un probar su valor como lenguaje para el desarrollo de aplica-
ciones industriales, pero este primer contacto nos permite al menos tenerlo como
alternativa seria, para problemas que requieran el uso intensivo de la concur-
rencia.
Por ultimo, hay un gran set de herramientas que permiten facilitar la pro-
gramacion de sistemas a gran escala concurrentes, como por ejemplo OTP, del
cual hay documentacion en varios sitios.
37
Erlang
A. Aplicaciones de ejemplo
A.1. Un algoritmo de Backtracing
Nos proponemos implementar el algoritmo de Backtracking en Erlang. Su
aplicacion sera la inteligencia de la computadora para decidir jugadas de Ta-
Te-Ti. Esta idea, as como el algoritmo, la tomamos de [1].
La idea de la resolucion de un problema por Backtracking consiste, en lneas
generales, en probar todas las alternativas posibles hasta encontrar una solucion
optima. En el caso del Ta-Te-Ti, dado un estado del tablero, se busca averiguar
que eleccion para la proxima jugada maximiza las chances de ganar.
La implementacion consiste en construir un arbol del juego, en el que cada
nodo representa un estado del tablero una jugada despues del estado en el nodo
padre. Las hojas del arbol corresponden al juego terminado.
Si se asigna el valor 1, -1 o 0 a las hojas seg un gane el primer jugador, el
segundo o haya un empate, puede elegirse la mejor jugada desde un estado del
tablero, recorriendo todos los caminos posibles, propagando los valores de cada
nodo, asumiendo que un jugador tomara la decision que mas le conviene en cada
turno. En la gura se ilustra este esquema.
Figura 18:

Arbol de juego del Ta-Te-Ti.
Dado el peque no tama no de nuestro problema, en lugar de construir el arbol
de juego y actualizarlo tras cada jugada, usamos una matriz que representa el
tablero, y recalculamos los tableros descendientes cada vez que es necesario.
38
Erlang A.1 Un algoritmo de Backtracing
El algoritmo resulta de la forma:
proximo tablero(Tablero, Jugador) ->
{ ,TableroProximo} = backtrack(Tablero, Jugador),
TableroProximo.
backtrack(Tablero, Jugador)->
{Fin,Gana}= fin juego(Tablero),
if Fin -> {Gana,Tablero};
true ->
Opciones = lists:map(
fun(H)->
{Peso, }= backtrack(H, -1*Jugador),
{Peso,H}
end, hijos(Tablero, Jugador)),
if
Jugador =:= 1 -> lists:max(Opciones);
Jugador =:= -1 -> lists:min(Opciones)
end
end.
La funcion recurrente backtrack primero chequea si el juego termino, en cuyo
caso devuelve en una tupla el n umero del ganador (o si hubo empate) y el estado
del tablero. Si la partida no termina, calcula los posibles siguientes estados del
tablero y vuelve a llamar a la funcion, cambiando el jugador de turno. Cuando
se llega al nal de los estados posibles se elige el estado de tablero que tenga un
valor maximo (o mnimo en el caso del jugador 2); tal valor se calculo propagando
el n umero del ganador en cada hoja, de manera que si se sigue ese camino, se
garantiza la victoria de la partida.
La implementacion de las funciones auxiliares usadas anteriormente se de-
talla a continuacion:
39
Erlang A.1 Un algoritmo de Backtracing
hijos(Tablero, Jugador)-> [reemplazar(Jugador,X,Y,Tablero)||
{X,Y} <- casilleros vacios(Tablero,[],0,0)].
casilleros vacios(Tablero,Acum,X,Y)->
case Tablero of
[[0|T1]|T] -> casilleros vacios([T1|T],[{X,Y}|Acum],X,Y+1);
[[ |T1]|T] -> casilleros vacios([T1|T],Acum,X,Y+1);
[[]|T] -> casilleros vacios(T,Acum,X+1,0);
[] -> Acum
end.
reemplazar(Elemento, X, Y, Tablero)->
L = lists:nth(X+1,Tablero),
L1 = lists:sublist(L,Y) ++ [Elemento] ++
lists:sublist(L,Y+2,2-Y),
lists:sublist(Tablero,X) ++ [L1] ++
lists:sublist(Tablero,X+2,2-X).
fin juego(Tablero)->
Gano1 = gano(1,Tablero),
Gano2 = gano(-1,Tablero),
Empate = not lists:member(0,lists:flatten(Tablero)),
if
Gano1 -> {true,1};
Gano2 -> {true,-1};
Empate-> {true,0};
true -> {false,0}
end.
gano(N,Tablero)->
Linea = lists:member([N,N,N], Tablero),
case Tablero of
Tablero when Linea -> true;
[[N, , ],[ ,N, ],[ , ,N]] -> true;
[[ , ,N],[ ,N, ],[N, , ]] -> true;
[[N, , ],[N, , ],[N, , ]] -> true;
[[ ,N, ],[ ,N, ],[ ,N, ]] -> true;
[[ , ,N],[ , ,N],[ , ,N]] -> true;
Tablero -> false
end.
Por ultimo, se implementaron un par de funciones para permitir al usuario
de la consola de Erlang, enfrentar a la computadora usando el algoritmo anterior
(Y corroborar que funciona). Se incluye una captura del programa funcionando.
40
Erlang A.1 Un algoritmo de Backtracing
comienzo()->
io:format(Nueva partida\n),
jugar([[0,0,0],[0,0,0],[0,0,0]]).
jugar(Tablero)->
imprimir tablero(Tablero),
case fin juego(Tablero) of
{true,0}->io:format(Empate\n);
{true,1}->io:format(Usted Gana\n);
{true,-1}->io:format(Usted Pierde\n);
{false,0}->
{X, }=string:to integer(io:get line(Ingrese X:)),
{Y, }=string:to integer(io:get line(Ingrese Y:)),
Tablero2=reemplazar(1,Y-1,X-1,Tablero),
imprimir tablero(Tablero2),
case fin juego(Tablero) of
{true,0}->io:format(Empate\n);
{true,1}->io:format(Usted Gana\n);
{true,-1}->io:format(Usted Pierde\n);
{false,0}-> jugar(proximo tablero(Tablero2,-1))
end
end.
imprimir tablero(Tablero)->
lists:map(
fun(X)->
lists:map(
fun(Y)->
case Y of
0 -> io:format( |);
1 -> io:format(X|);
-1-> io:format(0|)
end
end, X),
io:nl()
end, Tablero),
io:nl().
41
Erlang A.1 Un algoritmo de Backtracing
Figura 19: Ejecucion de Ta-Te-Ti.
42
Erlang A.2 Chat
A.2. Chat
Aplicando las herramientas elementales de distribucion y concurrencia de
Erlang, buscamos implementar una aplicacion simple de mensajera entre nodos.
En una primera instancia, escribimos un modulo simple para comunicacion
directa entre dos nodos que se reconocen mutuamente.
-module(chat).
-export([start/1]).
start(BuddyNode) ->
register(uname, spawn(fun()-> rloop() end)),
spawn(fun()-> wloop(BuddyNode)end),
io:get line(decir: ).
rloop() ->
receive
{Node, Msg}->
io:format(s dice: s,[Node, Msg]),
rloop()
end.
wloop(BuddyNode)->
A = io:get line(decir: ),
say(BuddyNode, A),
wloop(BuddyNode).
say(BuddyNode, Msg)->
{uname, BuddyNode}!{node(),Msg}.
Cada nodo llama a la funcion start, pasando como argumento el atom cor-
respondiente al nombre de nodo Erlang con el que se quiere comunicar.

Esta funcion a su vez lanza dos procesos: un loop que lee constantemente los
mensajes recibidos al nodo y los imprime por consola (rloop), y otro que lee el
texto ingresado para enviarlo al otro nodo (wloop).
Como segundo ejercicio se busco representar una situacion mas realista,
seg un el modelo cliente-servidor: un nodo servidor, de ubicacion conocida, ad-
ministra la conversacion entre todos los nodos que se conectan a el, recibiendo
los mensajes y redistribuyendolos a los demas. De esta forma cada usuario se
comunica unicamente con el servidor, y desconoce a los otros nodos.
43
Erlang A.2 Chat
-module(server).
-export([start/0]).
start() ->
register(server, spawn (fun() -> loop([]) end)).
loop(Users) ->
receive
{From, join, Nick} ->
event(##++ Nick ++ se unio a la conversacion.\n,
Users),
From ! ##Te has unido a la conversacion.\n,
io:format(##++ Nick ++ joined. \n),
loop([{From, Nick}|Users]);
{From, leave} ->
{ ,{ ,Nick}} = lists:keysearch(From, 1, Users),
event(##++ Nick ++ abandono la conversacion.\n,
Users),
io:format(##++ Nick ++ left. \n),
loop(lists:keydelete(From,1,Users));
{From, users} ->
S = lists:flatten(lists:map(fun({ ,U})-> U ++ , end,
Users)),
Msg = ##Usuarios conectados: ++ S ++ \n,
From ! Msg,
loop(Users);
{From, Msg} ->
{ ,{ ,Nick}}= lists:keysearch(From, 1, Users),
event(Nick ++ : ++ Msg, lists:keydelete(From,1,
Users)),
loop(Users)
end.
event(Msg, Users) ->
lists:foreach( fun ({Pid, }) -> Pid ! Msg end,Users).
Al iniciar el server con start(), se registra el proceso servidor como server,
para poder ser identicado por los usuarios que le enviaran mensajes. Se inicia
un loop de lectura que realiza distintas acciones, de acuerdo a la forma del
mensaje que recibe: agregar o retirar a un usuario de la conversacion, informar
44
Erlang A.2 Chat
los nombres de los usuarios conectados, o reenviar un mensaje enviado por
alguno de esos usuarios. El cliente, similar al primer modulo realizado, ejecuta
bucles de lectura y escritura en consola, formateando el mensaje enviado al
servidor de manera especial, en caso de requerir abandonar la conversacion, o
conocer los usuarios conectados.
-module(client).
-export([join/2]).
join(ServerNode, Nick) ->
net adm:ping(ServerNode),
Pid = spawn(fun()-> rloop() end),
{server, ServerNode}!{Pid, join, Nick},
spawn(fun()-> wloop(ServerNode, Pid) end),
io:get line(decir: ).
rloop()->
receive
Msg ->
{H, M, S} = erlang:time(),
io:format((p:p:p) ++ Msg, [H, M, S]),
rloop()
end.
wloop(ServerNode, Pid)->
case io:get line(decir: ) of
#exit\n->
{server, ServerNode} ! {Pid, leave};
#users\n->
{server, ServerNode} ! {Pid, users},
wloop(ServerNode, Pid);
Msg ->
{server, ServerNode} ! {Pid, Msg},
wloop(ServerNode, Pid)
end.
Se incluye por ultimo una captura de este ultimo ejemplo funcionando en
varios nodos en una misma maquina.
45
Erlang A.2 Chat
Figura 20: ejemplo de ejecucion.
46
Erlang REFERENCIAS
Referencias
[1] Alfred Aho, John Hopcroft, and Jerey Ullman. Data Structures and Al-
gorithms. Addison-Wesley, 1983.
[2] Joe Armstrong. The development of Erlang. ACM SIGPLAN International
Conference on Functional Programming, 1997.
[3] Joe Armstrong. Making reliable distributed systems in the presence of soft-
ware errors. Royal Institute of Technology, 2003.
[4] Joe Armstrong. Programming Erlang: Software for a Concurrent World.
Pragmatic Bookshelf, 2007.
[5] Bjarne Dacker. Concurrent Functional Programming for Telecommunica-
tions: A Case Study of Technology Introduction. Royal Institute of Tech-
nology, 2000.
[6] Bogumil Hausman. Turbo Erlang: Approaching the Speed of C. Kluwer Aca-
demic Publishers, 1994.
[7] Peter Van Roy, and Seif Haridi. Concepts, Techniques, and Models of Com-
puter Programming. MIT Press, 2004.
[8] Erlang/OTP Publications. http://www.erlang.se/publications/
[9] Apache vs. Yaws. http://www.sics.se/joe/apachevsyaws.html
47

Вам также может понравиться