Translate

Mostrando las entradas para la consulta erlang ordenadas por relevancia. Ordenar por fecha Mostrar todas las entradas
Mostrando las entradas para la consulta erlang ordenadas por relevancia. Ordenar por fecha Mostrar todas las entradas

domingo, 19 de mayo de 2013

Vistazo a Erlang

Erlang es un lenguaje funcional del cual ya hablamos muchas veces. Por que es tan importante? Porque agrega el concepto de actores, una forma mucho más elegante de resolver el problema de la concurrencia. Hice varios post sobre esto, pero Erlang no es solo importante por los Actores sino por un sin fin de características que lo hacen muy particular.

Erlang no es solo un lenguaje también es una tecnología; dado que cuenta con maquina virtual, un middleware OTP y librerías. Muchas empresas utilizan erlang; pero tal vez se hizo famoso porque se utilizo en el desarrollo de la base de datos NoSQL llamada couchDB.

Erlang es un lenguaje funcional con lo que eso significa por lo tanto tiene transparencia referencial y es declarativo. Erlang fue pensado como un lenguaje que debe correr de forma concurrente y distribuida; eso explica su diseño. A la vez esta basado en convenciones lo que hace que este lenguaje sea muy practico.

Erlang es software libre y se encuentra en los repositorios de linux por lo tanto se puede instalar de la siguiente manera en distribuciones basadas en debian:

apt-get install erlang

En rhel:

yum install erlang

Si vamos a una terminal y ponemos erl vamos a abrir el interprete de erlang. Con el podemos sumar, multiplicar, dividir, etc :

1> 2 + 2.
4
2> (4 + 5) * 2.
18
3> (12 + 3) div 5.
3
4> (12 + 3) / 5.
3.00000
 
En estos ejemplos podemos ver que el delimitador de las sentencias es el “.” como smalltalk. A la vez se puede ver la diferencia de / con div que div nos de vuelve un valor entero.  Podemos seguir jugando  con la consola:

4> 'Hola mundo'.
 'Hola mundo'
5> 1==2.
false
6> not ((1<3) and (2==2)).
false
7> tuple_size({1,{1,2,3},2})
3

Bueno en los siguientes ejemplos podemos ver como se manejan booleanos, similar que otros lenguajes y también podemos ver un ejemplo de tuplas, las tuplas son un conjunto de elementos de igual o distinto tipo similares a las Listas. Las listas en erlang se definen con los corchetes [] vemos ejemplos:

8> []
[]
9> [1, 2, [2, “hola”, 5], 4]
 [1, 2, [2, “hola”, 5], 4]

En Erlang los string son listas de caracteres que se pueden definir con “”. Es decir que “” es igual a []. Los caracteres son representados por medio del simbolo $ y también con el numero del carácter.

10> [72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100]
“Hello Word”
11> [$H, $e, $l, $l, $o, $ , $W, $o, $r, $d]
“Hello Word”

Erlang tienen un conjunto muy amplio de funciones con listas:

12> lists:max([1, 2, 3])
3
13> lists:reverse([1, 2, 3])
[3,2,1]
13> lists:sort([1, 3, 2])
[1, 2, 3]
14> lists:sum([1, 2, 3, 4])
10
15> [1, 2, 3, 4] ++ [5, 6, 7]
[1, 2, 3, 4, 5, 6, 7]
16> [1, 2, 3, 4] -- [3, 4]
[1, 2]

Y eso es todo, los deje con ganas de más?

Dejo link:
http://www.erlang.org/

viernes, 15 de septiembre de 2023

¿Qué es Erlang?


Erlang es un lenguaje de programación funcional. Si alguna vez ha trabajado con lenguajes imperativos, declaraciones como i++ pueden resultarle normales; en programación funcional no están permitidos. De hecho, ¡está estrictamente prohibido cambiar el valor de cualquier variable! Esto puede sonar extraño al principio, pero si recuerdas tus clases de matemáticas, en realidad así es como las aprendiste:

y = 2

x = y + 3

x = 2 + 3

x = 5

Si hubiera agregado lo siguiente:

x = 5 + 1

x = x

∴ 5 = 6

Habrías estado muy confundido. La programación funcional reconoce esto: si digo que x es 5, entonces lógicamente no puedo afirmar que también sea 6. Esto sería deshonesto. Esta es también la razón por la que una función con el mismo parámetro siempre debería devolver el mismo resultado:

x = add_two_to(3) = 5

∴ x = 5

Las funciones que siempre devuelven el mismo resultado para el mismo parámetro se denominan transparencia referencial. Es lo que nos permite reemplazar add_two_to(3) con 5, ya que el resultado de 3+2 siempre será 5. Eso significa que luego podemos unir docenas de funciones para resolver problemas más complejos mientras nos aseguramos de que nada se rompa. Lógico y limpio ¿no? Sin embargo, hay un problema:


x = today() = 2009/10/22

-- wait a day --

x = today() = 2009/10/23

x = x

∴ 2009/10/22 = 2009/10/23


¡Oh, no! ¡Mis hermosas ecuaciones! ¡De repente todos se equivocaron! ¿Cómo es que mi función arroja un resultado diferente cada día?

Evidentemente, hay algunos casos en los que resulta útil romper la transparencia referencial. Erlang tiene este enfoque muy pragmático con la programación funcional: obedece sus principios más puros (transparencia referencial, evitar datos mutables, etc.), pero aléjate de ellos cuando surgen problemas del mundo real.

Ahora, definimos Erlang como un lenguaje de programación funcional, pero también hay un gran énfasis en la concurrencia y la alta confiabilidad. Para poder realizar docenas de tareas al mismo tiempo, Erlang utiliza el modelo de actor, y cada actor es un proceso separado en la máquina virtual. En pocas palabras, si fueras un actor en el mundo de Erlang, serías una persona solitaria, sentada en una habitación oscura sin ventanas, esperando junto a tu buzón para recibir un mensaje. Una vez que recibes un mensaje, reaccionas de una manera específica: pagas las facturas al recibirlas, respondes a las tarjetas de cumpleaños con una carta de agradecimiento e ignoras las cartas que no puedes entender.

El modelo de actor de Erlang puede imaginarse como un mundo en el que todos están sentados solos en su propia habitación y pueden realizar algunas tareas distintas. Todos se comunican estrictamente escribiendo cartas y listo. Si bien suena como una vida aburrida (y una nueva era para el servicio postal), significa que puedes pedirle a muchas personas que realicen tareas muy específicas por ti, y ninguna de ellas hará algo mal o cometerá errores que tendrán repercusiones en tu vida. el trabajo de otros; es posible que ni siquiera conozcan la existencia de otras personas además de ti (y eso es genial).

Para escapar de esta analogía, Erlang te obliga a escribir actores (procesos) que no compartirán información con otros bits de código a menos que se pasen mensajes entre sí. Cada comunicación es explícita, rastreable y segura.

Cuando definimos Erlang, lo hicimos a nivel de lenguaje, pero en un sentido más amplio, esto no es todo: Erlang es también un entorno de desarrollo en su conjunto. El código se compila en código de bytes y se ejecuta dentro de una máquina virtual. Entonces Erlang, al igual que Java, puede ejecutarse en cualquier lugar. La distribución estándar incluye (entre otras) herramientas de desarrollo (compilador, depurador, generador de perfiles, framework de prueba), el framework Open Telecom Platform (OTP), un servidor web, un generador de analizadores y la base de datos mnesia, un sistema de almacenamiento de valores clave capaz de replicarse en muchos servidores, admitiendo transacciones anidadas y permitiéndole almacenar cualquier tipo de datos de Erlang.

La VM y las librería también le permiten actualizar el código de un sistema en ejecución sin interrumpir ningún programa, distribuir su código con facilidad en muchas computadoras y administrar errores y fallas de una manera simple pero poderosa.

Una política general relacionada en Erlang: dejar que se explote. No como un avión con decenas de pasajeros muriendo, sino más bien como un equilibrista con una red de seguridad debajo. Si bien debes evitar cometer errores, en la mayoría de los casos no será necesario verificar cada tipo o condición de error.

La capacidad de Erlang para recuperarse de errores, organizar el código con actores y hacerlo escalar con la distribución y la concurrencia suena increíble!

Dejo link: https://learnyousomeerlang.com/introduction


lunes, 13 de mayo de 2024

Tipos en Erlang


Erlang se escribe dinámicamente: cada error se detecta en tiempo de ejecución y el compilador no siempre le gritará al compilar módulos donde las cosas pueden resultar en fallas.

Un punto de fricción clásico entre los defensores de los lenguajes de tipado estático y dinámico tiene que ver con la seguridad del software que se escribe. Una idea sugerida con frecuencia es que los buenos sistemas de tipo estático con compiladores que los aplican con fervor detectarán la mayoría de los errores que esperan ocurrir antes de que puedas ejecutar el código. Como tal, los lenguajes escritos estáticamente deben considerarse más seguros que sus homólogos dinámicos. Si bien esto podría ser cierto en comparación con muchos lenguajes dinámicos, Erlang no está de acuerdo y ciertamente tiene un historial que lo demuestra. El mejor ejemplo son los nueve nueves (99,9999999%) de disponibilidad que se ofrecen en los conmutadores ATM Ericsson AXD 301, que constan de más de 1 millón de líneas de código Erlang. Tenga en cuenta que esto no es una indicación de que ninguno de los componentes de un sistema basado en Erlang haya fallado, sino que un sistema de conmutación general estuvo disponible el 99,9999999 % del tiempo, incluidas las interrupciones planificadas. Esto se debe en parte a que Erlang se basa en la noción de que una falla en uno de los componentes no debería afectar a todo el sistema. Se tienen en cuenta los errores provenientes del programador, fallas de hardware o [algunas] fallas de red: el lenguaje incluye características que le permitirán distribuir un programa a diferentes nodos, manejar errores inesperados y nunca dejar de ejecutarse.

Para abreviar, mientras que la mayoría de los lenguajes y sistemas de tipos tienen como objetivo hacer que un programa esté libre de errores, Erlang utiliza una estrategia en la que se supone que los errores ocurrirán de todos modos y se asegura de cubrir estos casos: El sistema de tipos dinámicos de Erlang no es una barrera para confiabilidad y seguridad de los programas. Esto suena como un montón de palabras proféticas, pero verás cómo se hace.

Históricamente se eligió la escritura dinámica por razones simples; Aquellos que implementaron Erlang al principio procedían en su mayoría de lenguajes escritos dinámicamente y, como tal, tener Erlang dinámico era la opción más natural para ellos.

Erlang también está fuertemente tipado. Un lenguaje débilmente tipado haría conversiones de tipos implícitas entre términos. Si Erlang tuviera un tipo débil, posiblemente podríamos hacer la operación 6 = 5 + "1". mientras que en la práctica, se lanzará una excepción:


1> 6 + "1".

** exception error: bad argument in an arithmetic expression

     in operator  +/2

        called as 6 + "1"


Por supuesto, hay ocasiones en las que es posible que desee convertir un tipo de datos en otro: cambiar cadenas normales en cadenas de bits para almacenarlas o un número entero en un número de punto flotante. La biblioteca estándar de Erlang proporciona una serie de funciones para hacerlo.



domingo, 19 de diciembre de 2010

Erlang


Ya hemos hablado de erlangs en otros post, vamos a hacer un repaso y luego desarrollar ejemplos.

Erlang es un lenguaje de programación concurrente y un sistema de ejecución que incluye una máquina virtual y bibliotecas.

El subconjunto de programación secuencial de Erlang es un lenguaje funcional, con evaluación estricta, asignación única, y tipado dinámico. Fue diseñado en la compañía Ericsson para realizar aplicaciones distribuidas, tolerantes a fallos, soft-real-time y de funcionamiento ininterrumpido. Proporciona el cambio en caliente de código de forma que éste se puede cambiar sin parar el sistema. Originalmente, Erlang era un lenguaje propietario de Ericsson, pero fue cedido como software de código abierto en 1998. La implementación de Ericsson es, principalmente interpretada pero también incluye un compilador HiPE (sólo soportado en algunas plataformas).

La creación y gestión de procesos es trivial en Erlang, mientras que, en muchos lenguajes, los hilos se consideran un apartado complicado y propenso a errores. En Erlang toda concurrencia es explícita.

Bueno vamos a bajarnos el runtime de http://www.erlang.org/download.html esto para windows, si estan en linux es más fácil instalarlo por ejemplo en debian es así “apt-get install erlang”, y listo!

Se puede escribir codigo en un archivo .erl y luego compilarlo opteniendo el .beam (ejecutable) nosotros vamos a usar la consola.

Escribimos en la consola erl o werl(para windows)

erl
Erlang (BEAM) emulator version 5.4.13 [source]
Eshell V5.4.13 (abort with ^G)
1>

1> % Este es un comentario
2> 2 + 2.
4
3> 2 + 2,0.
4,0

Veamos las listas:
4> [1, 2, 3,4]
[1, 2, 3,4]

No se puede hacer operaciones con diferentes tipos por ejemplo la suma:

5> 4 + "string".
** exception error: bad argument in an arithmetic expression
in operator +/2
called as 4 + "string"

Las variables deben comenzar con mayuscula:

7> Var = 1.
1
8> Var = 2.
=ERROR REPORT==== 8-Jan-2010::11:47:46 ===
Error in process <0.39.0> with exit value: {{badmatch,2},[{erl_eval,expr,3}]}
** exited: {{badmatch,2},[{erl_eval,expr,3}]} **
8> Var.
1
Como se puede ver solo se puede asignar un valor a una variable una vez; esto es asi porque Erlang es un lenguaje funcional.

Un símbolo es una palabra en minuscula (en la mayoria de los lenguajes que lo implementa) que sirve para representar algo. En Erlang el símbolo se denomina atoms.

9> red.
red
10> Pill = blue.
blue
11> Pill.
blue


Las listas son un conjunto de elementos que pueden tener diferente tipo y longitud:

13> [1, 2, 3].
[1,2,3]
14> [1, 2, "three"].
[1,2,"three"]
15> List = [1, 2, 3].
[1,2,3]

Tuples es una lista fija y heterogénea:

18> {one, two, three}.
{one,two,three}
19> Origin = {0, 0}.
{0,0}

Estas estructuras pueden convinarse:

20> {name, "Spaceman Spiff"}.
{name,"Spaceman Spiff"}
21> {comic_strip, {name, "Calvin and Hobbes"}, {character, "Spaceman Spiff"}}.
{comic_strip,{name,"Calvin and Hobbes"},
{character,"Spaceman Spiff"}}

24> Person = {person, {name, "Agent Smith"}, {profession, "Killing programs"}}.
{person,{name,"Agent Smith"},
{profession,"Killing programs"}}

Para obtener valores de la persona podemos hacer lo siguiente:

25> {person, {name, Name}, {profession, Profession}} = Person.
{person,{name,"Agent Smith"},
{profession,"Killing programs"}}
26> Name.
"Agent Smith"
27> Profession.
"Killing programs"

Se entiende? Obtenemos los valores en Name y Profession por medio de patrones de coincidencia.
Y con patrones de coincidencia se puede hacer más cosas:

28> [Head | Tail] = [1, 2, 3].
[1,2,3]
29> Head.
1
30> Tail.
[2,3]
32> [One, Two|Rest] = [1, 2, 3].
[1,2,3]
33> One.
1
34> Two.
2
35> Rest.
[3]

Si no hay suficientes elementos en la lista el patrón no funciona:

6> [X|Rest] = [].
** exception error: no match of right hand side value []

Erlang es dinámicamente tipado, Erlang puede enlazar tipos en runtime. Vamos a hacer una función para esto vamos a hacer un modulo. Yo uso debian pero para windows debe ser parecido.
Salimos del runtime Ctrl + G.
Escribimos:
nano basic.erl
En nano escribimos el siguiente código:

-module(basic).
-export([mirror/1]).
mirror(Anything) -> Anything.

Salimos y guardamos. Luego escribimos erl en la consola.
Y por ultimo compilamos:

1> c(basic).
{ok,basic}

La función mirror solo devuelve lo que pasamos como parámetro. Pueden ver que el operador -> simplifica el return.

5> mirror(smiling_mug).
** exception error: undefined shell command mirror/1
6> basic:mirror(smiling_mug).
smiling_mug
6> basic:mirror(1).
1
Vemos que hay que ingresar el nombre del modulo.

-module(matching_function).
-export([number/1]).
number(one) -> 1;
number(two) -> 2;
number(three) -> 3.

En la siguiente función se puede ver la influencia de Prolog en Erlang.
Por ultimo implementemos factorial y figonacci :

-module(yet_again).
-export([another_factorial/1]).
-export([another_fib/1]).
another_factorial(0) -> 1;
another_factorial(N) -> N * another_factorial(N-1).
another_fib(0) -> 1;
another_fib(1) -> 1;
another_fib(N) -> another_fib(N-1) + another_fib(N-2).

Hasta aca vimos muy por arriba Erlang en proximos post vamos a seguir hablando.

Dejo links:

domingo, 5 de marzo de 2023

Primeros pasos con Phoenix


Antes de empezar de manera muy rápida aclaremos que Phoenix es un framework web o para hacer API en Elixir. 

Phoenix está escrito en Elixir, y nuestro código de aplicación también estará escrito en Elixir. Por ende el primer paso es instalar Elixir , en mi caso lo voy a instalar con asdf

asdf plugin-add elixir https://github.com/asdf-vm/asdf-elixir.git

asdf install elixir 1.14.3-otp-25

El código de Elixir se compila en el código de bytes de Erlang para ejecutarse en la máquina virtual de Erlang. Sin Erlang, el código de Elixir no tiene una máquina virtual para ejecutarse, por lo que también debemos instalar Erlang. 

asdf plugin add erlang https://github.com/asdf-vm/asdf-erlang.git

asdf install erlang 25.0.3

Y ahora vamos a setear las versiones: 

asdf global erlang 25.0.3

asdf global elixir 1.14.3-otp-25

Pero pueden ver como instalar en su equipo en el siguiente link : https://elixir-lang.org/install.html

Cuando instalamos Elixir siguiendo las instrucciones de la página de instalación de Elixir, normalmente también obtendremos Erlang. Para checkear esto hacemos : 

emanuel@crespo:~$ elixir --version

Erlang/OTP 25 [erts-13.1.5] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] [jit:ns]


Elixir 1.14.3 (compiled with Erlang/OTP 25)


También podemos escribir erl que es el comando para la relp de Erlang. 

Si acabamos de instalar Elixir por primera vez, también necesitaremos instalar el administrador de paquetes Hex. Hex es necesario para ejecutar una aplicación de Phoenix (mediante la instalación de dependencias) y para instalar cualquier dependencia adicional que podamos necesitar en el camino. En mi caso es : 

mix local.hex


Ahora debemos instalar phoenix, en mi caso voy a instalar la ultima versión

mix archive.install hex phx_new 

Por lo visto, ya esta todo instalado, ahora vamos a crear nuestro primer proyecto: 

mix phx.new hello_world --module HelloWorld

Y si todo salio bien vamos a ejecutarlo: 

cd hello_world/
mix phx.server

Si vamos a http://localhost:4000/ nos aparecerá una pagina. 

Van a ver que tira como 5000 errores porque no configuramos la base de datos, pero eso lo vamos hacer en el proximo post. 

Dejo link; https://www.phoenixframework.org/

jueves, 1 de mayo de 2014

Manejar la concurrencia con Actores.


El modelo de actores que fue propuesto por primera vez por Carl Hewitt en 1973; es un modelo de concurrencia computacional que al igual que los hilos, trata de solucionar el problema de la concurrencia.

En el modelo de actores, cada objeto es un actor. Esta es una entidad que tiene una cola de mensajes o buzón y un comportamiento. Los mensajes pueden ser intercambiados entre los actores y se almacenan en el buzón. Al recibir un mensaje, el comportamiento del actor se ejecuta. El actor puede : enviar una serie de mensajes a otros actores, crear una serie de actores y asumir un nuevo comportamiento para el próximo mensaje.

La importancia en este modelo es que todas las comunicaciones se llevan a cabo de forma asincrónica. Esto implica que el remitente no espera a que un mensaje sea recibido en el momento que lo envío, solo sigue su ejecución.

Una segunda característica importante es que todas las comunicaciones se producen por medio de mensajes: no hay un estado compartido entre los actores. Si un actor desea obtener información sobre el estado interno de otro actor, se tendrá que utilizar mensajes para solicitar esta información. Esto permite a los actores controlar el acceso a su estado, evitando problemas.

Erlang es un lenguaje de programación concurrente y un sistema de ejecución que incluye una máquina virtual y bibliotecas. Fue diseñado en la compañía Ericsson para realizar aplicaciones distribuidas, tolerantes a fallos y de funcionamiento ininterrumpido. Originalmente, Erlang era un lenguaje propietario de Ericsson, pero fue cedido como software de código abierto en 1998. La implementación de Ericsson es, principalmente interpretada pero también incluye un compilador HiPE (sólo soportado en algunas plataformas).

Entre los mayores logros de la plataforma podemos destacar que el chat de facebook y la base documental CouchDB.

Sin dudas una cosa que hace muy especial de Erlang es como maneja la concurrencia. Erlang no maneja la concurrencia con hilos como nos tiene acostumbrado C, C++ o Java. Erlang soluciona la programación concurrente mediante el modelo de actores.

En Erlang los procesos o actores:

  • Son rápidos de crear y destruir.
  • El envío de mensajes entre procesos es muy rápido.
  • Es fácil mantener un gran número de procesos.
  • Son ligeros.
  • Son independientes y no comparten memoria.
  • Sólo un proceso tratará un mensaje pasado, en ningún caso pasará por otro proceso.


Parece complicado, pero no lo es. Con un ejemplo vamos a aclarar el tema. Supongamos que queremos hacer un actor saludador, pero no muy simpático; que salude solo a los conocidos; en erlang sería así:

-module(saludador).
-export([loop/0]).
loop() ->
receive
% Saluda a un conocido
"conocido" ->
io:format("Hola!! " ),
loop();
% Un desconocido, no lo saluda
_ ->
io:format(" ... " ),
loop()
end.

En la primera línea declaramos el modulo; luego importamos la función loop, con la cual definimos una función vacía e iteramos para siempre. Con receive recibimos un mensaje, es similar al swich, espera a recibir un mensaje y al recibir un mensaje ejecuta la estructura de código que corresponde al mensaje enviado y el “_” es como el default del swich en c, c++ o java.

Primero compilamos, para esto vamos a guardar nuestro saludador en el fichero saludador.erl y luego en la consola de Erlang escribimos:

1> c(saludador).
{ok,saludador}

Con spawn se puede generar un proceso, spawn nos devolverá el PID del proceso, que nos servirá para enviarle mensajes.

2> Pid = spawn(fun saludador:loop/0).
<0.38.0>

Ahora le vamos a mandar un mensaje:

4> Pid ! "conocido".
Hola!! "conocido"

5> Pid ! "Pepe".
... "Pepe"

Como era de esperar solo dice hola a los conocidos. Con el operador ! enviamos mensajes a un actor a partir de su Pid.

Éste es un pequeño ejemplo de manejo de concurrencia en erlang. La forma en que maneja la concurrencia Scala fue inspirada en Erlang.

Scala implementa el modelo de actores similar a Erlang, veamos un poco de código:

import scala.actors.Actor

class Saludador extends Actor  {
  
  def act() = {
        while (true) {
            receive {
                case "conocido" =>
                    println("Hola!")
                case _ =>
                    println("...")
            }
        }
    }

}

object ActorsTest extends App {

  val saludador = new Saludador
  saludador.start()
  
  saludador ! "otro"
  saludador ! "conocido"
}

Akka es un framework java que nos brinda este modelo en el lenguaje java. Permitiéndonos manejar la concurrencia de forma más simple como lo hace scala o erlang.

Veamos un ejemplo:

import akka.actor.Props;
import akka.actor.UntypedActor;
import akka.actor.ActorRef;

public class HelloWorld extends UntypedActor {

  @Override
  public void preStart() {
    // create the greeter actor
    final ActorRef greeter = getContext().actorOf(Props.create(Greeter.class), "greeter");
    // tell it to perform the greeting
    greeter.tell(Greeter.Msg.GREET, getSelf());
  }

  @Override
  public void onReceive(Object msg) {
    if (msg == Greeter.Msg.DONE) {
      // when the greeter is done, stop this actor and with it the application
      getContext().stop(getSelf());
    } else
      unhandled(msg);
  }
}

Como podemos ver en ejemplo podemos hacer un manejo de actores de forma remota. Akka es tolerable a fallos dado que fue concedido con tecnología Let it crash/Embrace failure. Akka es de código abierto y está disponible bajo la licencia Apache 2. A la vez está basado en scala y provee una Api para este lenguaje.

Akka tiene integración con Spring, soporta OSGI, se integra con Apache Camel y la última versión soporta Java 8. ¡Solo falta que cocine y lave la ropa!

Desarrollar aplicaciones concurrentes puede ser un dolor de cabeza. Por este motivo nació el modelo de actores, para simplificar el desarrollo concurrente.

martes, 14 de mayo de 2024

Conversiones de tipos en Erlang


Erlang, como muchos lenguajes, cambia el tipo de un término al convertirlo en otro. Esto se hace con la ayuda de funciones integradas, ya que muchas de las conversiones no se pudieron implementar en Erlang. Cada una de estas funciones toma la forma <tipo>_to_<tipo> y se implementa en el módulo erlang. Éstos son algunos de ellos:


1> erlang:list_to_integer("54").

54

2> erlang:integer_to_list(54).

"54"

3> erlang:list_to_integer("54.32").

** exception error: bad argument

     in function  list_to_integer/1

        called as list_to_integer("54.32")

4> erlang:list_to_float("54.32").

54.32

5> erlang:atom_to_list(true).

"true"

6> erlang:list_to_bitstring("hi there").

<<"hi there">>

7> erlang:bitstring_to_list(<<"hi there">>).

"hi there"


Etcétera. Estamos topando con un problema de lenguaje: debido a que se usa el esquema <tipo>_to_<tipo>, cada vez que se agrega un nuevo tipo al lenguaje, es necesario agregar una gran cantidad de BIF de conversión. Aquí está la lista:


atom_to_binary/2, atom_to_list/1, binary_to_atom/2, binary_to_existing_atom/2, binary_to_list/1, bitstring_to_list/1, binary_to_term/1, float_to_list/1, fun_to_list/1, integer_to_list/1, integer_to_list/2, iolist_to_binary/1, iolist_to_atom/1, list_to_atom/1, list_to_binary/1, list_to_bitstring/1, list_to_existing_atom/1, list_to_float/1, list_to_integer/2, list_to_pid/1, list_to_tuple/1, pid_to_list/1, port_to_list/1, ref_to_list/1, term_to_binary/1, term_to_binary/2 and tuple_to_list/1.



jueves, 22 de febrero de 2024

Listas en Erlang


Las listas se utilizan para resolver todo tipo de problemas y son sin duda la estructura de datos más utilizada en Erlang. ¡Las listas pueden contener cualquier cosa! Números, átomos, tuplas, otras listas. La notación básica de una lista es [Elemento1, Elemento2,..., ElementoN] y puedes mezclar más de un tipo de datos en ella:


> [1, 2, 3, {numbers,[4,5,6]}, 5.34, atom].

[1,2,3,{numbers,[4,5,6]},5.34,atom]


Bastante simple, ¿verdad?

2> [97, 98, 99].
"abc"

Los strings son listas y la notación es absolutamente la misma ¿Por qué a la gente no le gusta? Debido a esto:

3> [97,98,99,4,5,6].
[97,98,99,4,5,6]
4> [233].
"é"

Erlang imprimirá listas de números como números solo cuando al menos uno de ellos no pueda representar como una letra. 

Es por eso que quizás hayas escuchado que se dice que Erlang es malo en la manipulación de cadenas: no hay un tipo de cadena incorporado como en la mayoría de los otros lenguajes. Esto se debe a los orígenes de Erlang como lenguaje creado y utilizado por empresas de telecomunicaciones. Nunca (o rara vez) usaron cadenas y, como tal, nunca tuvieron ganas de agregarlas oficialmente. Sin embargo, la mayor parte de la falta de sentido de Erlang en las manipulaciones de cadenas se está solucionando con el tiempo: la máquina virtual ahora admite de forma nativa cadenas Unicode y, en general, se vuelve más rápida en las manipulaciones de cadenas todo el tiempo.

También hay una manera de almacenar cadenas como una estructura de datos binarios, lo que las hace realmente livianas y más rápidas para trabajar. Con todo, todavía faltan algunas funciones en la biblioteca estándar y, si bien el procesamiento de cadenas es definitivamente factible en Erlang, existen lenguajes algo mejores para tareas que necesitan mucho, como Perl o Python.

Para unir listas, usamos el operador ++. Lo opuesto a ++ es -- y eliminará elementos de una lista:

5> [1,2,3] ++ [4,5].
[1,2,3,4,5]
6> [1,2,3,4,5] -- [1,2,3].
[4,5]
7> [2,4,2] -- [2,4].
[2]
8> [2,4,2] -- [2,4,2].
[]

Tanto ++ como -- son asociativos por la derecha. Esto significa que los elementos de muchas operaciones -- o ++ se realizarán de derecha a izquierda, como en los siguientes ejemplos:

9>[1,2,3]-[1,2]-[3].
[3]
10>[1,2,3]-[1,2]-[2].
[2,3]

El primer elemento de una lista se denomina Encabezado y el resto de la lista se denomina Cola. Usaremos dos funciones integradas (BIF) para obtenerlas.

11> hd([1,2,3,4]).
1
12>tl([1,2,3,4]).
[2,3,4]

Las funciones integradas (BIF) suelen ser funciones que no se pueden implementar en Erlang puro y, como tales, se definen en C, o en cualquier lenguaje en el que se implemente Erlang (era Prolog en los años 80). Todavía hay algunos BIF que se pueden realizar en Erlang pero que aún se implementaron en C para proporcionar más velocidad a las operaciones comunes. Un ejemplo de esto es la función length(List), que devolverá la longitud (lo has adivinado) de la lista pasada como argumento.

Como se usa con tanta frecuencia, existe una forma más sencilla de separar el principio del final de una lista con la ayuda de la coincidencia de patrones: [Cabeza|Cola]. Así es como agregarías un nuevo encabezado a una lista:

13> Lista = [2,3,4].
[2,3,4]
14>NuevaLista = [1|Lista].
[1,2,3,4]

Al procesar listas, como normalmente se comienza con la cabeza, podemos desear una forma rápida de almacenar también la cola para operarla más tarde. Si recuerdas la forma en que funcionan las tuplas y cómo usamos la coincidencia de patrones para descomprimir los valores de un punto ({X,Y}), sabrás que podemos cortar el primer elemento (el encabezado) de una lista de manera similar. .

15> [Cabeza|Cola] = NuevaLista.
[1,2,3,4]
16> Cabeza.
1
17> Cola.
[2,3,4]
18> [NuevaCabeza|NuevaCola] = Cola.
[2,3,4]
19> Nuevo jefe.
2

El | que utilizamos se llama operador de contras (constructor). De hecho, cualquier lista se puede construir sólo con el operador:

20> [1 | []].
[1]
21> [2 | [1 | []]].
[2,1]
22> [3 | [2 | [1 | []] ] ].
[3,2,1]

Es decir cualquier lista se puede construir con la siguiente fórmula: [Término1| [Término2 | [... | [TérminoN]]]].... Las listas pueden así definirse recursivamente como un principio que precede a un final, que a su vez es un principio seguido de más principios. En este sentido, podríamos imaginar una lista como una lombriz de tierra: puedes cortarla por la mitad y luego tendrás dos lombrices.

Las formas en que se pueden construir las listas de Erlang a veces resultan confusas para las personas que no están acostumbradas a constructores similares. Para ayudarle a familiarizarse con el concepto, lea todos estos ejemplos (pista: todos son equivalentes):

[a B C D]
[a, b, c, d | []]
[a, b | [cd]]
[a, b | [c | [d]]]
[un | [b | [c | [d]]]]
[un | [b | [c | [d | [] ]]]]

Una vez entendido esto, debería poder lidiar con listas por comprensión.

Usando el formulario [1 | 2] ofrece lo que llamamos una "lista inadecuada". Las listas inadecuadas funcionarán cuando coincida el patrón en la forma [Cabeza|Cola], pero no podrán usarse con funciones estándar de Erlang (longitud uniforme()). Esto se debe a que Erlang espera listas adecuadas. Las listas adecuadas terminan con una lista vacía como última celda. Al declarar un elemento como [2], la lista se forma automáticamente de manera adecuada. ¡Como tal, [1|[2]] funcionaría! Las listas inadecuadas, aunque sintácticamente válidas, tienen un uso muy limitado fuera de las estructuras de datos definidas por el usuario.

domingo, 26 de mayo de 2013

Continuamos con Erlang

Agner Krarup Erlang (1 de enero de 1878 – 3 de febrero de 1929) fue un matemático, estadista, e ingeniero danés que inventó los campos de Ingeniería de tráfico (Telecomunicaciones) y la Teoría de Colas. En su honor bautizaron al lenguaje de programación Erlang con su apellido.

Se acuerdan del post: http://emanuelpeg.blogspot.com.ar/2013/05/vistazo-erlang.html bueno vamos a seguir dándole un vistazo a Erlang.

Las variables en Erlang son un tanto diferentes que otros lenguajes; al ser un lenguaje funcional solo se le pueden asignar valores a varible solo una vez. Es decir que las variables no pueden variar :P

Si necesitamos asignar otro valor, necesitamos otra variable.

3> Integer = 4.
4
4> Integer = Integer + 5.
** exception error: no match of right hand side value 9
5>

Como se puede ver las variables en Erlang comienzan con mayúsculas y pueden contener letras y números. También es importante notar que no indicamos el tipo sino que el compilador lo infiere. 

12> Double2 = 3.5.
3.5
13> Double4 = 3.5 + Double2. 
7.0
14> 
14> Texto = "hola".
"hola"
15> 

Erlang nos ofrece una estructura de datos compleja para poder representar la realidad. 

15> Programadores = [ {person,"Juan","Gomez", 
15>  {lenguajes, [java,python] }
15> },
15> {person,"Pedro","Gomez",
15> {lenguajes, [java,python,erlang] }
15> }].                        
[{person,"Juan","Gomez",{lenguajes,[java,python]}},
 {person,"Pedro","Gomez",{lenguajes,[java,python,erlang]}}]

Hasta acá llegamos por hoy, pero continuaremos aprendiendo este fascinante lenguaje. 

viernes, 15 de septiembre de 2023

Y es Erlang tan bueno?


Actualmente, Erlang está ganando mucha popularidad debido a conversaciones entusiastas que pueden llevar a la gente a creer que es más de lo que realmente es. El primer caso de esto está relacionado con las enormes capacidades de escalamiento de Erlang debido a sus procesos livianos. Es cierto que los procesos de Erlang son muy ligeros: puedes tener cientos de miles de ellos existentes al mismo tiempo, pero esto no significa que tengas que usarlos de esa manera sólo porque puedas. Por ejemplo, crear un juego de disparos en el que todo, incluidas las balas, sea su propio actor, es una locura. Lo único que dispararás en un juego como este será tu propio pie. Todavía hay un pequeño costo al enviar un mensaje de actor a actor, y si divides demasiado las tareas, ¡harás las cosas más lentas!

También se dice que Erlang puede escalar de manera directamente proporcional a la cantidad de núcleos que tiene su computadora, pero esto generalmente no es cierto. Es posible, pero la mayoría de los problemas no se comportan. de una manera que te permita ejecutar todo al mismo tiempo.

Hay algo más a tener en cuenta: si bien Erlang hace algunas cosas muy bien, técnicamente todavía es posible obtener los mismos resultados en otros lenguajes. Lo opuesto también es cierto; evaluar cada problema como debe ser y elegir la herramienta adecuada según el problema que se aborda. Erlang no es una solución mágica y será particularmente malo en cosas como procesamiento de imágenes y señales, controladores de dispositivos de sistemas operativos, etc. y brillará en cosas como software grande para uso de servidor (es decir, colas, reducción de mapas), haciendo algo de levantamiento junto con otros lenguajes, implementación de protocolos de nivel superior, etc. Las áreas intermedias dependerán de usted. No necesariamente debes encerrarte en un software de servidor con Erlang: ha habido casos de personas que hacen cosas inesperadas y sorprendentes. Un ejemplo es IANO, un robot creado por el equipo UNICT, que utiliza Erlang por su inteligencia artificial y ganó la medalla de plata en el concurso eurobot de 2009. Otro ejemplo es Wings 3D, un modelador 3D de código abierto (pero no un renderizador) escrito en Erlang y, por lo tanto, multiplataforma.

Dejo link: https://learnyousomeerlang.com/introduction

domingo, 8 de mayo de 2011

Concurrencia en Erlang


Ya hemos hablado de este tema anteriormente:


Pero vamos a hacer un repaso, Erlang es un lenguaje de programación concurrente y un sistema de ejecución que incluye una máquina virtual y bibliotecas. Fue diseñado en la compañía Ericsson para realizar aplicaciones distribuidas, tolerantes a fallos, soft-real-time y de funcionamiento ininterrumpido. Proporciona el cambio en caliente de código de forma que éste se puede cambiar sin parar el sistema. Originalmente, Erlang era un lenguaje propietario de Ericsson, pero fue cedido como software de código abierto en 1998. La implementación de Ericsson es, principalmente interpretada pero también incluye un compilador HiPE (sólo soportado en algunas plataformas).

Entre los mayores logros de la plataforma podemos destacar que el chat de facebook y la base documental CouchDB.

Sin dudas una cosa que hace muy especial a Erlang es como maneja la concurrencia. Erlang no maneja la concurrencia con thread como nos tiene acostumbrado C, C++ o Java. Erlang soluciona la programación concurente mediante el modelo de actores. El modelo de actores es un modelo de concurrencia computacional que trata a los "actores" como los primitivos universal de la computación digital en paralelo: en respuesta a un mensaje que recibe, un actor puede tomar decisiones locales, crear más actores, envía más mensajes, y determinar cómo responder al siguiente mensaje recibido.

Parece complicado, pero no lo es. Con un ejemplo vamos a aclarar el tema. Supongamos que queremos hacer un actor saludador, pero no muy simpático; que salude solo a los conocidos; en erlang sería así:

-module(saludador).
-export([loop/0]).
loop() ->
receive
% Saluda a un conocido
"conocido" ->
io:format("Hola!! " ),
loop();
% Un desconocido, no lo saluda
_ ->
io:format(" ... " ),
loop()
end.

En la primera linea declaramos el modulo; luego importamos la función loop, con la cual definimos una función vacía y iteramos para siempre. Con receive recibimos un mensaje, es similar al swich, espera a recibir un mensaje y al recibir un mensaje ejecuta la estructura de codigo que corresponde al mensaje enviado y el “_” es como el default en c, c++ o java.

Primero compilamos:

1> c(saludador).
{ok,saludador}

Con spawn se puede generar un proceso, spawn nos devolverá el PID del proceso, que nos servirá para enviarle mensajes.

2> Pid = spawn(fun saludador:loop/0).
<0.38.0>

Ahora le vamos a mandar un mensaje:

4> Pid ! "conocido".
Hola!! "conocido"

5> Pid ! "Pepe".
... "Pepe"

Como era de esperar solo dice hola a los conocidos. Con el operador ! enviamos mensajes a un actor a partir de su Pid.

Este es un pequeño ejemplo de manejo de concurrencia en erlang. La forma en que maneja la concurrencia Scala fue inspirada en Erlang.

domingo, 24 de marzo de 2024

Modulos en Erlang


Trabajar con el shell interactivo a menudo se considera una parte vital del uso de lenguajes de programación dinámicos. Es útil para probar todo tipo de códigos y programas. La mayoría de los tipos de datos básicos de Erlang se utilizaron sin necesidad de abrir un editor de texto o guardar archivos. Podrías dejar caer el teclado, salir a jugar y dar por terminado el día, pero serías un pésimo programador de Erlang si te detuvieras ahí mismo. ¡El código debe guardarse en algún lugar para poder usarse!

Para eso están los módulos. Los módulos son un conjunto de funciones reagrupadas en un único archivo, bajo un único nombre. Además, todas las funciones en Erlang deben definirse en módulos. 

Los BIF del módulo erlang se diferencian de otras funciones en que se importan automáticamente cuando usa Erlang. Cualquier otra función definida en un módulo que vaya a utilizar debe llamarse con el formato Módulo:Función(Argumentos).

Puedes verlo por ti mismo:

1> erlang:element(2, {a,b,c}).

b

2> element(2, {a,b,c}).

b

3> lists:seq(1,4).

[1,2,3,4]

4> seq(1,4).

** exception error: undefined shell command seq/2


Aquí, la función seq del módulo de lista no se importó automáticamente, mientras que el element sí. El error 'exception error: undefined shell command seq/2' proviene de que el shell busca un comando de shell como f() y no puede encontrarlo. Hay algunas funciones del módulo erlang que no se importan automáticamente, pero no se usan con demasiada frecuencia.

Lógicamente, deberías poner funciones sobre cosas similares dentro de un solo módulo. Las operaciones comunes en listas se mantienen en el módulo de listas, mientras que las funciones para realizar entradas y salidas (como escribir en la terminal o en un archivo) se reagrupan en el módulo io. Uno de los únicos módulos que encontrará que no respeta ese patrón es el módulo erlang antes mencionado que tiene funciones que hacen matemáticas, conversiones, tratan con multiprocesamiento, modifican la configuración de la máquina virtual, etc. No tienen ningún punto en común excepto ser funciones integradas. Debes evitar la creación de módulos como erlang y, en su lugar, centrarte en separaciones lógicas limpias.


viernes, 9 de febrero de 2024

Álgebra booleana y operadores de comparación en Erlang


Uno estaría en serios problemas si no pudiera distinguir entre lo que es pequeño y lo grande, lo que es verdadero y lo falso. Como cualquier otro lenguaje, Erlang tiene formas que le permiten utilizar operaciones booleanas y comparar elementos.

El álgebra booleana es muy simple:


1> true and false.

false

2> false or true.

true

3> true xor false.

true

4> not false.

true

5> not (true and true).

false

Los operadores booleanos and y or siempre evaluarán los argumentos en ambos lados del operador. Si desea tener operadores de cortocircuito (que solo evaluarán el argumento del lado derecho si es necesario), use andalso y orelse.

La prueba de igualdad o desigualdad también es muy simple, pero tiene símbolos ligeramente diferentes a los que se ven en muchos otros lenguajes:


6> 5 =:= 5.

true

7> 1 =:= 0.

false

8> 1 =/= 0.

true

9> 5 =:= 5.0.

false

10> 5 == 5.0.

true

11> 5 /= 5.0.

false


En primer lugar, si su lenguaje habitual usa == y != para probar a favor y en contra de la igualdad, Erlang usa =:= y =/=. Las tres últimas expresiones (líneas 9 a 11) también nos presentan un problema: a Erlang no le importarán los números flotantes y enteros en aritmética, pero sí lo hará al compararlos. Pero no te preocupes, porque los operadores == y /= están ahí para ayudarte en estos casos. Es importante recordar esto si desea igualdad exacta o no.

Otros operadores para comparaciones son < (menor que), > (mayor que), >= (mayor o igual que) y =< (menor o igual que). Este último está al revés (en mi opinión) y es la fuente de muchos errores de sintaxis en mi código. Esté atento a eso =<.


12> 1 < 2.

true

13> 1 < 1.

false

14> 1 >= 1.

true

15> 1 =< 1.

true


¿Qué pasa al hacer 5 + llama o 5 == verdadero? ¡No hay mejor manera de saberlo que probarlo y luego asustarse con mensajes de error!


12> 5 + llama.

** exception error: bad argument in an arithmetic expression

in operator  +/2 called as 5 + llama


¡Bien! ¡A Erlang realmente no le gusta que hagas mal uso de algunos de sus tipos fundamentales! El emulador devuelve un bonito mensaje de error aquí. ¡Nos dice que no le gusta uno de los dos argumentos utilizados en torno al operador +!

Sin embargo, algunas veces no se toma tan en serio el tema de los tipos :


13> 5 =:= true.

false


¿Por qué rechaza distintos tipos en unas operaciones pero no en otras? Si bien Erlang no te permite agregar nada con todo, te permitirá compararlos. Esto se debe a que los creadores de Erlang pensaron que el pragmaticismo vence a la teoría y decidieron que sería fantástico poder escribir simplemente cosas como algoritmos de clasificación generales que pudieran ordenar cualquier término. Está ahí para simplificarle la vida y puede hacerlo la gran mayoría del tiempo.

Hay una última cosa a tener en cuenta al hacer álgebra booleana y comparaciones:


14> 0 == false.

false

15> 1 < false.

true


Lo más probable es que te estés tirando de los pelos si vienes de lenguajes procedimentales o de la mayoría de los lenguajes orientados a objetos. ¡La línea 14 debe evaluarse como verdadera y la línea 15 como falsa! Después de todo, falso significa 0 y verdadero es cualquier otra cosa. Excepto en Erlang. 

Erlang no tiene valores booleanos verdadero y falso. Los términos verdadero y falso son átomos, pero están lo suficientemente bien integrados en el lenguaje como para no tener problemas con eso, siempre y cuando no esperes que falso y verdadero signifiquen otra cosa que falso y verdadero.

Nota: El orden correcto de cada elemento en una comparación es el siguiente:

number < atom < reference < fun < port < pid < tuple < list < bit string

¡Solo recuerda que es por eso que puedes comparar cualquier cosa con cualquier cosa! Para citar a Joe Armstrong, uno de los creadores de Erlang: "El orden real no es importante, pero sí es importante que un orden total esté bien definido".

sábado, 3 de febrero de 2024

Erlang shell




En Erlang, puedes probar la mayoría de tus cosas en un emulador; ejecutará sus scripts cuando los compile e implemente, pero también te permite ejecutar código en vivo. Para esto, iniciamos el shell en Linux y luego escribimos $ erl. Y si esta todo bien, deberíamos ver un texto como este:

Erlang R13B01 (erts-5.7.2) [source] [smp:2:2] [rq:2] [async-threads:0] [hipe] [kernel-poll:false]

Eshell V5.7.2  (abort with ^G)


Para los usuarios de Windows, aún pueden ejecutar el shell erl.exe, pero se recomienda que se utilice werl.exe, que se puede encontrar en el menú de inicio (programas > Erlang). Werl es una implementación solo para Windows del shell Erlang, que tiene su propia ventana con barras de desplazamiento y admite edición de línea de comandos (como copiar y pegar, lo que llegó a ser una molestia con el shell cmd.exe estándar en Windows). El shell erl aún es necesario si desea redirigir la entrada o salida estándar, o utilizar canalizaciones.

Podremos ingresar y ejecutar código en el emulador, pero primero, veamos cómo podemos movernos en él. El shell Erlang tiene un editor de líneas incorporado basado en un subconjunto de Emacs, un popular editor de texto que se utiliza desde los años 70. Si conoce Emacs, debería estar bien. Para los demás, te irá bien de todos modos.

En primer lugar, si escribe algo de texto y luego va ^A (Ctrl+A), debería ver que el cursor se mueve al principio de la línea. ^E (Ctrl+E) te lleva al final. Puede usar las teclas de flecha para avanzar, retroceder, mostrar líneas anteriores o siguientes para poder repetir el código.

Si escribe algo como li y luego presiona "tab", el shell habrá completado los términos y si presionamos tabulador nuevamente y el shell le sugerirá muchas funciones para usar después. Este es Erlang completando las listas de módulos y luego sugiriendo funciones a partir de ellos. 

Creo que hemos visto suficiente funcionalidad del shell para estar bien, excepto por una cosa: ¡no sabemos cómo salir! Hay una forma rápida de descubrir cómo hacerlo. Simplemente escriba help(). y debería obtener información sobre un montón de comandos que puede usar en el shell (no olvide el punto (.) ya que es necesario para que se ejecute el comando). Usaremos algunos de ellos más adelante, pero la única línea que nos preocupa para poder salir es

q() -- salir - abreviatura de init:stop()

Esta es una manera de hacerlo (de hecho, dos maneras). Si estabas prestando atención, cuando inició el shell, hubo un comentario sobre "abortar con ^G". ¡Hagámoslo y luego presione h para obtener ayuda!


User switch command

--> h

c [nn]            - connect to job

i [nn]            - interrupt job

k [nn]            - kill job

j                 - list all jobs

s [shell]         - start local shell

r [node [shell]]  - start remote shell

q        - quit erlang

? | h             - this message

-->


Si escribe i y luego c, Erlang debería detener el código que se está ejecutando actualmente y devolverlo a un shell responsivo. j le dará una lista de procesos en ejecución (una estrella después de un número indica que este es el trabajo que está ejecutando actualmente), que luego puede interrumpir con i seguido del número. Si usa k, matará el shell tal como está en lugar de simplemente interrumpirlo. Presione s para iniciar uno nuevo.


Eshell V5.7.2  (abort with ^G)

1> "OH NO THIS SHELL IS UNRESPONSIVE!!! *hits ctrl+G*"

User switch command

--> k

--> c

Unknown job

--> s

--> j

2* {shell,start,[]}

--> c 2

Eshell V5.7.2  (abort with ^G)

1> "YESS!"


Si vuelve a leer el texto de ayuda, notará que podemos iniciar shells remotos. 

lunes, 4 de marzo de 2024

Manipular datos binarios con Erlang


La mayoría de los lenguajes admiten la manipulación de datos como números, átomos, tuplas, listas, registros y/o estructuras, etc. La mayoría de ellos también solo tienen funciones muy básicas para manipular datos binarios. Erlang hace todo lo posible para proporcionar abstracciones útiles cuando se trata de valores binarios con coincidencia de patrones llevada al siguiente nivel. Hace que tratar con datos binarios sin procesar sea divertido y fácil, lo cual era necesario para las aplicaciones de telecomunicaciones para las que fue creado. La manipulación de bits tiene una sintaxis y modismos únicos que pueden parecer un poco extraños al principio, pero si sabes cómo funcionan generalmente los bits y los bytes, esto debería tener sentido. 

La sintaxis de bits encierra datos binarios entre << y >>, los divide en segmentos legibles y cada segmento está separado por una coma. Un segmento es una secuencia de bits de un binario (no necesariamente en un límite de bytes, aunque este es el comportamiento predeterminado). Digamos que queremos almacenar un píxel naranja (24 bits). Si alguna vez comprobó los colores en Photoshop o en una hoja de estilos CSS para la web, sabrá que la notación hexadecimal tiene el formato #RRGGBB. Un tinte naranja es #F09A29 en esa notación, que podría ampliarse en Erlang a:


1> Color = 16#F09A29.

15768105

2> Pixel = <<Color:24>>.

<<240,154,41>>


Básicamente dice "Coloque los valores binarios de #F09A29 en 24 bits (rojo en 8 bits, verde en 8 bits y azul también en 8 bits) en la variable Píxel". Posteriormente se puede tomar el valor para escribirlo en un archivo. Esto no parece mucho, pero una vez escrito en un archivo, lo que obtendría al abrirlo en un editor de texto sería un montón de caracteres ilegibles. Cuando vuelva a leer el archivo, Erlang interpretará el binario en el bonito formato <<240,151,41>> nuevamente.

Lo que es más interesante es la capacidad de hacer coincidir patrones con archivos binarios para descomprimir contenido:


3> Pixels = <<213,45,132,64,76,32,76,0,0,234,32,15>>.

<<213,45,132,64,76,32,76,0,0,234,32,15>>

4> <<Pix1,Pix2,Pix3,Pix4>> = Pixels.

** exception error: no match of right hand side value <<213,45,132,64,76,32,76,

0,0,234,32,15>>

5> <<Pix1:24, Pix2:24, Pix3:24, Pix4:24>> = Pixels.

<<213,45,132,64,76,32,76,0,0,234,32,15>>


Lo que hicimos en el comando 3 fue declarar lo que serían exactamente 4 píxeles de colores RGB en binario.

En la expresión 4, intentamos descomprimir 4 valores del contenido binario. Lanza una excepción, porque tenemos más de 4 segmentos, ¡de hecho tenemos 12! Entonces, lo que hacemos es decirle a Erlang que cada variable del lado izquierdo contendrá 24 bits de datos. Eso es lo que significa Var:24. Luego podemos tomar el primer píxel y descomprimirlo en valores de un solo color:


6> <<R:8, G:8, B:8>> = <<Pix1:24>>.

<<213,45,132>>

7> R.

213


"Sí, eso es genial. ¿Y si solo quisiera el primer color desde el principio? ¿Tendré que descomprimir todos estos valores todo el tiempo?" ¡Ja! ¡No lo dudes! Erlang introduce más azúcar sintáctico y coincidencia de patrones para ayudarte con:


8> <<R:8, Rest/binary>> = Pixels.

<<213,45,132,64,76,32,76,0,0,234,32,15>>

9> R.

213


Bonito, ¿eh? Esto se debe a que Erlang acepta más de una forma de describir un segmento binario. Todos estos son válidos:


Value

Value:Size

Value/TypeSpecifierList

Value:Size/TypeSpecifierList


donde Tamaño representará bits o bytes (según el Tipo y Unidad a continuación) y TypeSpecifierList representa uno o más de los siguientes:

integer | float | binary | bytes | bitstring | bits | utf8 | utf16 | utf32

Esto representa el tipo de datos binarios utilizados. Tenga en cuenta que "bytes" es la abreviatura de "binario" y "bits" es la abreviatura de "cadena de bits". Cuando no se especifica ningún tipo, Erlang asume un tipo "entero".

Firma

Valores posibles: signed | unsigned

Solo importa para la coincidencia cuando el tipo es un número entero. El valor predeterminado es "sin firmar".

Endianidad

Valores posibles: big | little | native

La endianidad solo importa cuando el tipo es entero, utf16, utf32 o flotante. Esto tiene que ver con cómo el sistema lee los datos binarios. Como ejemplo, el formato de encabezado de imagen BMP mantiene el tamaño de su archivo como un número entero almacenado en 4 bytes. Para un archivo que tiene un tamaño de 72 bytes, un sistema little-endian lo representaría como <<72,0,0,0>> y uno big-endian como <<0,0,0,72>>. Uno se leerá como '72' mientras que el otro se leerá como '1207959552', así que asegúrese de utilizar el endianismo correcto. También existe la opción de usar 'nativo', que elegirá en tiempo de ejecución si la CPU usa little endianness o big endianness de forma nativa. De forma predeterminada, la endianidad está establecida en "grande".

Unidad

unidad unit:Integer

Este es el tamaño de cada segmento, en bits. El rango permitido es 1..256 y está establecido de forma predeterminada en 1 para números enteros, flotantes y cadenas de bits y en 8 para binarios. Los tipos utf8, utf16 y utf32 no requieren que se defina ninguna unidad. La multiplicación de Tamaño por Unidad es igual a la cantidad de bits que tomará el segmento y debe ser divisible por 8. El tamaño de la unidad generalmente se usa para garantizar la alineación de bytes.

TypeSpecifierList se construye separando los atributos por un '-'.


Algunos ejemplos pueden ayudar a digerir las definiciones:


10> <<X1/unsigned>> =  <<-44>>.

<<"Ô">>

11> X1.

212

12> <<X2/signed>> =  <<-44>>. 

<<"Ô">>

13> X2.

-44

14> <<X2/integer-signed-little>> =  <<-44>>.

<<"Ô">>

15> X2.

-44

16> <<N:8/unit:1>> = <<72>>.

<<"H">>

17> N.

72

18> <<N/integer>> = <<72>>.

<<"H">>

19> <<Y:4/little-unit:8>> = <<72,0,0,0>>.     

<<72,0,0,0>>

20> Y.

72


Puede ver que hay más de una forma de leer, almacenar e interpretar datos binarios. Esto es un poco confuso, pero aún así es mucho más sencillo que utilizar las herramientas habituales que ofrecen la mayoría de los lenguajes.

Las operaciones binarias estándar (desplazamiento de bits a izquierda y derecha, 'y' binario, 'o', 'xor' o 'no') también existen en Erlang. Simplemente use las funciones bsl (Bit Shift Left), bsr (Bit Shift Right), band, bor, bxor y bnot.


2#00100 = 2#00010 bsl 1.

2#00001 = 2#00010 bsr 1.

2#10101 = 2#10001 bor 2#00101.


Con ese tipo de notación y la sintaxis de bits en general, el análisis y la coincidencia de patrones de datos binarios es pan comido. Se podrían analizar segmentos TCP con un código como este:

<<SourcePort:16, DestinationPort:16,
AckNumber:32,
DataOffset:4, _Reserved:4, Flags:8, WindowSize:16,
CheckSum: 16, UrgentPointer:16,
Payload/binary>> = SomeBinary.

La misma lógica se puede aplicar a cualquier cosa binaria: codificación de vídeo, imágenes, otras implementaciones de protocolos, etc.

Erlang es lento en comparación con lenguajes como C o C++. A menos que seas una persona paciente, sería una mala idea hacer cosas como convertir vídeos o imágenes con él, aunque la sintaxis binaria lo hace extremadamente interesante, como insinué anteriormente. Erlang simplemente no es tan bueno para hacer cálculos numéricos intensos.

Tenga en cuenta, sin embargo, que Erlang sigue siendo muy rápido para aplicaciones que no requieren cálculos numéricos: reaccionar a eventos, pasar mensajes (con la ayuda de átomos que son extremadamente livianos), etc. Puede manejar eventos en cuestión de milisegundos y como Este es un gran candidato para aplicaciones suaves en tiempo real.

Hay un aspecto completamente diferente en la notación binaria: las cadenas de bits. Las cadenas binarias están atornilladas encima del lenguaje de la misma manera que con las listas, pero son mucho más eficientes en términos de espacio. Esto se debe a que las listas normales son listas enlazadas (1 'nodo' por letra), mientras que las cadenas de bits se parecen más a matrices C. Las cadenas de bits utilizan la sintaxis <<"¡esta es una cadena de bits!">>. La desventaja de las cadenas binarias en comparación con las listas es la pérdida de simplicidad cuando se trata de coincidencia y manipulación de patrones. En consecuencia, la gente tiende a utilizar cadenas binarias cuando almacenan texto que no será manipulado demasiado o cuando la eficiencia del espacio es un problema real.

Nota: Aunque las cadenas de bits son bastante ligeras, debes evitar usarlas para etiquetar valores. Podría resultar tentador utilizar cadenas literales para decir {<<"temperatura">>,50}, pero siempre utilice átomos al hacerlo. Anteriormente, se decía que los átomos ocupaban sólo 4 u 8 bytes en el espacio, sin importar su longitud. Al usarlos, básicamente no tendrá gastos generales al copiar datos de una función a otra o enviarlos a otro nodo Erlang en otro servidor.
Por el contrario, no utilice átomos para reemplazar cadenas porque son más ligeras. Las cadenas se pueden manipular (división, expresiones regulares, etc.), mientras que los átomos sólo se pueden comparar y nada más.

miércoles, 14 de agosto de 2024

Try ... catch en Erlang parte 2


Erlang tiene otra estructura de manejo de errores. Esa estructura se define como la palabra clave catch y básicamente captura todos los tipos de excepciones además de los buenos resultados. Es un poco extraña porque muestra una representación diferente de las excepciones:


1> catch throw(whoa).

whoa

2> catch exit(die).

{'EXIT',die}

3> catch 1/0.

{'EXIT',{badarith,[{erlang,'/',[1,0]},

                   {erl_eval,do_apply,5},

                   {erl_eval,expr,5},

                   {shell,exprs,6},

                   {shell,eval_exprs,6},

                   {shell,eval_loop,3}]}}

4> catch 2+2.

4


Lo que podemos ver de esto es que los lanzamientos siguen siendo los mismos, pero que las salidas y los errores se representan como {'EXIT', Reason}. Esto se debe a que los errores se incorporan al lenguaje después de las salidas (mantuvieron una representación similar para compatibilidad con versiones anteriores).

La forma de leer este seguimiento de pila es la siguiente:


5> catch doesnt:exist(a,4).              

{'EXIT',{undef,[{doesnt,exist,[a,4]},

                {erl_eval,do_apply,5},

                {erl_eval,expr,5},

                {shell,exprs,6},

                {shell,eval_exprs,6},

                {shell,eval_loop,3}]}}


El tipo de error es indefinido, lo que significa que la función que llamaste no está definida.

La lista que aparece justo después del tipo de error es un seguimiento de la pila

La tupla que está en la parte superior del seguimiento de la pila representa la última función que se llamó ({Módulo, Función, Argumentos}). Esa es tu función indefinida.

Las tuplas que siguen son las funciones llamadas antes del error. Esta vez tienen la forma {Módulo, Función, Aridad}.

Eso es todo lo que hay que hacer, en realidad.

También se puede obtener un seguimiento de la pila manualmente llamando a erlang:get_stacktrace/0 en el proceso que falló.

A menudo verás que catch está escrito de la siguiente manera:


catcher(X,Y) ->

    case catch X/Y of

        {'EXIT', {badarith,_}} -> "uh oh";

        N -> N

    end.


Y como era de esperar:


6> c(exceptions).

{ok,exceptions}

7> exceptions:catcher(3,3).

1.0

8> exceptions:catcher(6,3).

2.0

9> exceptions:catcher(6,0).

"uh oh"


Suena compacto y fácil de capturar excepciones, pero hay algunos problemas con catch. El primero de ellos es la precedencia de operadores:


10> X = catch 4+2.

* 1: syntax error before: 'catch'

10> X = (catch 4+2).

6


Esto no es exactamente intuitivo, dado que la mayoría de las expresiones no necesitan estar entre paréntesis de esta manera. Otro problema con catch es que no se puede ver la diferencia entre lo que parece ser la representación subyacente de una excepción y una excepción real:


11> catch erlang:boat().

{'EXIT',{undef,[{erlang,boat,[]},

                {erl_eval,do_apply,5},

                {erl_eval,expr,5},

                {shell,exprs,6},

                {shell,eval_exprs,6},

                {shell,eval_loop,3}]}}

12> catch exit({undef, [{erlang,boat,[]}, {erl_eval,do_apply,5}, {erl_eval,expr,5}, {shell,exprs,6}, {shell,eval_exprs,6}, {shell,eval_loop,3}]}). 

{'EXIT',{undef,[{erlang,boat,[]},

                {erl_eval,do_apply,5},

                {erl_eval,expr,5},

                {shell,exprs,6},

                {shell,eval_exprs,6},

                {shell,eval_loop,3}]}}


Y no puedes saber la diferencia entre un error y una salida real. También podrías haber usado throw/1 para generar la excepción anterior. De hecho, un throw/1 en un catch también podría ser problemático en otro escenario:


one_or_two(1) -> return;

one_or_two(2) -> throw(return).


Y ahora el problema mortal:


13> c(exceptions).

{ok,exceptions}

14> catch exceptions:one_or_two(1).

return

15> catch exceptions:one_or_two(2).

return


Como estamos detrás de un catch, nunca podemos saber si la función generó una excepción o si devolvió un valor real. Es posible que esto no suceda con mucha frecuencia en la práctica, pero sigue siendo un problema lo suficientemente grave como para justificar la incorporación de la construcción try...catch.


domingo, 2 de junio de 2024

Alpaca, un lenguaje funcional, de tipado estático que corre en la VM de Erlang


Me quedo relargo el titulo :( 

Alpaca es un lenguaje de programación funcional inspirado en Elm y Haskell, diseñado para ser simple, seguro y eficiente.

Alpaca es un lenguaje de programación funcional que se ejecuta sobre la máquina virtual de Erlang (BEAM). Está diseñado para aprovechar las ventajas de la concurrencia y la tolerancia a fallos inherentes a la VM de Erlang, mientras proporciona una sintaxis limpia y moderna inspirada en lenguajes como Elm y Haskell. Alpaca está orientado a ser utilizado en el desarrollo de sistemas distribuidos y aplicaciones concurrentes.

Alpaca es un lenguaje puramente funcional, lo que significa que las funciones son ciudadanos de primera clase y no hay efectos secundarios.

Utiliza un sistema de tipos estático y fuerte, lo que ayuda a atrapar errores en tiempo de compilación, mejorando la fiabilidad del código.

Aprovecha la VM de Erlang, famosa por su modelo de actor y su capacidad para manejar grandes volúmenes de procesos concurrentes.

Ideal para desarrollar sistemas distribuidos y aplicaciones que requieren alta disponibilidad.

Alpaca puede interactuar fácilmente con código Erlang, permitiendo a los desarrolladores integrar nuevas funcionalidades en sistemas existentes escritos en Erlang.

Inspirado en Elm y Haskell, Alpaca presenta una sintaxis clara y concisa que facilita la lectura y escritura del código.

Enfocado en la simplicidad, lo que permite a los desarrolladores concentrarse en la lógica del negocio sin distraerse con detalles innecesarios del lenguaje.

Veamos un ejemplo: 


module Factorial


let rec fact n =

  if n == 0 then

    1

  else

    n * fact (n - 1)


En este ejemplo, la función fact calcula el factorial de un número n. Utiliza recursión, una característica común en los lenguajes funcionales, para realizar el cálculo.

Alpaca es un lenguaje de programación funcional prometedor que combina la potencia y fiabilidad de la VM de Erlang con una sintaxis moderna y clara. Es una excelente opción para desarrolladores interesados en sistemas concurrentes y distribuidos, y aquellos que disfrutan de los beneficios de la programación funcional. Con Alpaca, puedes escribir código limpio, eficiente y altamente concurrente, aprovechando al máximo las capacidades de Erlang.


Dejo link: 

https://github.com/alpaca-lang/alpaca

lunes, 1 de abril de 2024

Declaración de módulos en Erlang

 


Al escribir un módulo, puedes declarar dos tipos de cosas: funciones y atributos. Los atributos son metadatos que describen el módulo en sí, como su nombre, las funciones que deberían ser visibles para el mundo exterior, el autor del código, etc. Este tipo de metadatos es útil porque le da pistas al compilador sobre cómo debe hacer su trabajo y también porque permite a las personas recuperar información útil del código compilado sin tener que consultar el fuente.

Actualmente existe una gran variedad de atributos de módulo utilizados en el código Erlang en todo el mundo; de hecho, incluso puedes declarar tus propios atributos para lo que quieras. Hay algunos atributos predefinidos que aparecerán con más frecuencia que otros en el código. Todos los atributos del módulo siguen el formato -Name(Attribute). Sólo uno de ellos es necesario para que su módulo sea compilable:

-module(Name).

Este es siempre el primer atributo (y declaración) de un archivo, y por una buena razón: es el nombre del módulo actual, donde Nombre es un átomo. Este es el nombre que usará para llamar funciones de otros módulos. Las llamadas se realizan con la forma M:F(A), donde M es el nombre del módulo, F la función y A los argumentos.

¡Ya es hora de codificar! Nuestro primer módulo será muy simple e inútil. Abra su editor de texto y escriba lo siguiente, luego guárdelo en useless.erl:


-module(useless).

Esta línea de texto es un módulo válido. Por supuesto que es inútil sin funciones. Primero decidamos qué funciones se exportarán desde nuestro módulo 'useless'. Para ello usaremos otro atributo:

-export([Función1/Aridad, Función2/Aridad, ..., FunciónN/Aridad]).

Esto se utiliza para definir qué funciones de un módulo pueden ser invocadas por el mundo exterior. Se necesita una lista de funciones con su respectiva aridad. La aridad de una función es un número entero que representa cuántos argumentos se pueden pasar a la función. Esta es información crítica, porque diferentes funciones definidas dentro de un módulo pueden compartir el mismo nombre si y sólo si tienen una aridad diferente. Por lo tanto, las funciones agregar(X,Y) y agregar(X,Y,Z) se considerarían diferentes y se escribirían en la forma agregar/2 y agregar/3 respectivamente.

Nota: Las funciones exportadas representan la interfaz de un módulo. Es importante definir una interfaz que revele estrictamente lo necesario para su uso y nada más. Hacerlo le permite jugar con todos los demás detalles de implementación sin romper el código que podría depender del módulo.

Nuestro módulo inútil primero exportará una función útil llamada 'agregar', que tomará dos argumentos. Se puede agregar el siguiente atributo -export después de la declaración del módulo:

-export([add/2]).

Y ahora escribe la función:

add(A,B) ->

A + B.

La sintaxis de una función sigue la forma Nombre(Args) -> Cuerpo, donde Nombre tiene que ser un átomo y Cuerpo puede ser una o más expresiones de Erlang separadas por comas. La función finaliza con un punto. Tenga en cuenta que Erlang no utiliza la palabra clave "retorno". En cambio, la última expresión lógica de una función que se ejecutará devolverá su valor.

El código Erlang se compila en código de bytes para poder ser utilizado por la máquina virtual. Puede llamar al compilador desde muchos lugares: $ erlc marca file.erl cuando está en la línea de comando, compile:file(FileName) cuando está en el shell o en un módulo, c() cuando está en el shell, etc.

Es hora de compilar nuestro módulo inútil y probarlo. Abra el shell de Erlang, escriba:


1> cd("/path/to/where/you/saved/the-module/").

"Path Name to the directory you are in"

ok

De forma predeterminada, el shell solo buscará archivos en el mismo directorio en el que se inició y en la biblioteca estándar: cd/1 es una función definida exclusivamente para el shell Erlang, que le indica que cambie el directorio a uno nuevo para que sea menos molesto. para buscar nuestros archivos. Los usuarios de Windows deben recordar utilizar barras diagonales. Cuando haya terminado, haga lo siguiente:

2> c(useless).

{ok,useless}

Si tiene otro mensaje, asegúrese de que el archivo tenga el nombre correcto, que esté en el directorio correcto y que no haya cometido ningún error en su módulo. Una vez que haya compilado el código con éxito, notará que se agregó un archivo useless.beam junto a useless.erl en su directorio. Este es el módulo compilado. Probemos nuestras primeras funciones:

3> useless:add(7,2).

9

4> useless:not_a_real_function().

** exception error: undefined function useless:not_a_real_function/0

La función funciona como se esperaba. Las funciones y expresiones de Erlang siempre deben devolver algo, incluso si no fuera necesario en otros lenguaje. 

La expresión 2 muestra un error que se genera porque una función no existe. Si olvidó exportar una función, este es el tipo de mensaje de error que recibirá al probarla.