miércoles, 24 de abril de 2024

Correr todos los métodos main de un paquete en C#


Supongamos que tenemos un conjunto de clases que tienen un método main o se puede llamar como quiera y nosotros queremos pasar por parámetro el nombre de la clase y si no pasamos ningun nombre se ejecutan todos los métodos:


 using System;

using System.Linq;

using System.Reflection;



namespace Example

{

    class Program

    {

        static void Main(string[] args)

        {

            if (args[0] != null)

            {

                Run(args[0]);

            }

            else

            {

                var types = AppDomain.CurrentDomain.GetAssemblies()

                    .SelectMany(assembly => assembly.GetTypes())

                    .Where(type => "Example".Equals(type.Namespace)

                                   && !"Program".Equals(type.Name)).OrderBy(type => type.Name);

                foreach (var type in types)

                {

                    Run("Example."+type.Name);

                }

            }

        }


        private static void Run(string className)

        {

            var classType = Type.GetType(className);

            var declaredMethods = (classType as System.Reflection.TypeInfo)?.DeclaredMethods;

            if (declaredMethods == null) return;

            var mainMethod = declaredMethods.FirstOrDefault(method => method.Name == "Main");

            if (mainMethod == null)

            {

                return;

            }

            mainMethod.Invoke(null, null);

        }

    }

}

El método Run corre el metodo main de la clase pasada por parametros. Si no tiene este método, no hace nada. 

Listo!!  

martes, 23 de abril de 2024

Funciones genéricas en Gleam


import gleam/io


pub fn main() {

  let add_one = fn(x) { x + 1 }

  let exclaim = fn(x) { x <> "!" }


  // Invalid, Int and String are not the same type

  // twice(10, exclaim)


  // Here the type variable is replaced by the type Int

  io.debug(twice(10, add_one))


  // Here the type variable is replaced by the type String

  io.debug(twice("Hello", exclaim))

}


// The name `value` refers to the same type multiple times

fn twice(argument: value, my_function: fn(value) -> value) -> value {

  my_function(my_function(argument))

}


Gleam admite genéricos, también conocidos como polimorfismo paramétrico.

Esto funciona utilizando una variable de tipo en lugar de especificar un tipo concreto. Reemplaza cualquier tipo específico que se utilice cuando se llama a la función. Estas variables de tipo se escriben con un nombre en minúscula.

Las variables de tipo no son como cualquier tipo, se reemplazan con un tipo específico cada vez que se llama a la función. 


lunes, 22 de abril de 2024

Usando Roslyn ScriptEngine


La idea es correr C# como un lenguaje script y esto lo podemos hacer con Roslyn. 

Primero, instalamos las dependencias: 


dotnet add package Microsoft.CodeAnalysis.Scripting --version 4.9.2

dotnet add package Microsoft.CodeAnalysis.CSharp.Scripting --version 4.9.2


Y con eso ya estamos, podemos hacer esto: 


using System;

using Microsoft.CodeAnalysis.CSharp.Scripting;

using Microsoft.CodeAnalysis.Scripting;


class Program

{

    static async System.Threading.Tasks.Task Main(string[] args)

    {

        try

        {

            // Creamos el script

            string code = @"

                using System;


                public class MyClass

                {

                    public void MyMethod()

                    {

                        Console.WriteLine(""Hello from C#!"");

                    }

                }";


            // Creamos las opciones (usamos las por defecto) 

            ScriptOptions options = ScriptOptions.Default;


            // Creamos el motor que ejecuta el script

            var script = CSharpScript.Create(code, options);


            // corremos el script

            var result = await script.RunAsync();


            // Y chequeamos si hubo error. 

            if (result.Exception != null)

            {

                Console.WriteLine("Script execution failed: " + result.Exception.Message);

            }

        }

        catch (Exception ex)

        {

            Console.WriteLine("Error executing script: " + ex.Message);

        }

    }

}

Y listo! 

Lo unico malo es que este lenguaje C# no es completo, por ejemplo no se pueden utiliza namespace. Pero para hacer cosas chicas, esta bueno. 

Dejo link: 

domingo, 21 de abril de 2024

Más sobre funciones anónimas en Gleam



import gleam/io


pub fn main() {

  // These two statements are equivalent

  let add_one_v1 = fn(x) { add(1, x) }

  let add_one_v2 = add(1, _)


  io.debug(add_one_v1(10))

  io.debug(add_one_v2(10))

}


fn add(a: Int, b: Int) -> Int {

  a + b

}


Gleam tiene una sintaxis abreviada para crear funciones anónimas que toman un argumento e inmediatamente llaman a otra función con ese argumento: la sintaxis de captura de función.

La función anónima fn(a) { some_function(..., a, ...) } se puede escribir como some_function(..., _, ...), con cualquier número de otros argumentos pasados directamente a la función interna . El guión bajo _ es un marcador de posición para el argumento, equivalente a a en fn(a) { some_function(..., a, ...) }.

Guards en Erlang


Guards son cláusulas adicionales que pueden ir en la cabeza de una función para hacer pattern matching más expresivo. Como se mencionó anteriormente, el pattern matching es algo limitado ya que no puede expresar cosas como un rango de valores o ciertos tipos de datos. 

Por ejemplo, esto con Pattern matching : 

old_enough(0) -> false;

old_enough(1) -> false;

old_enough(2) -> false;

...

old_enough(14) -> false;

old_enough(15) -> false;

old_enough(_) -> true.


Es muy trabajoso pero si utilizamos guards : 


old_enough(X) when X >= 16 -> true;

old_enough(_) -> false.


Tenga en cuenta que Guards deben devolver verdadero para tener éxito. Guards fallará si devuelve falso o si genera una excepción. Supongamos que ahora prohibimos conducir a las personas mayores de 104 años. Nuestras edades válidas para conductores ahora son desde 16 años hasta 104 años. Tenemos que ocuparnos de eso, pero ¿cómo? Agreguemos una segunda cláusula de protección:


right_age(X) when X >= 16, X =< 104 -> true;

right_age(_)  -> false.


La coma (,) actúa de manera similar al operador and y el punto y coma (;) actúa un poco como or. Ambas expresiones deben tener éxito para que retorne verdadero. También podríamos representar la función al revés:


wrong_age(X) when X < 16; X > 104 -> true;

wrong_age(_) -> false.


Con punto y coma, si la primera condición falla, intenta con la segunda y luego con la siguiente, hasta que una tenga éxito o todas fallen.

Un punto negativo de los guards es que no aceptan funciones definidas por el usuario debido a los efectos secundarios. Erlang no es un lenguaje de programación puramente funcional (como lo es Haskell) porque depende mucho de los efectos secundarios: puedes realizar E/S, enviar mensajes entre actores o generar errores como quieras y cuando quieras. No existe una forma trivial de determinar si una función que usaría en una protección imprimiría o no texto o detectaría errores importantes cada vez que se prueba en muchas cláusulas de función. Entonces, en cambio, Erlang simplemente no confía en usted (¡y puede que sea correcto hacerlo!)


lunes, 15 de abril de 2024

Capturas de funciones de Gleam

 


import gleam/io


pub fn main() {

  // These two statements are equivalent

  let add_one_v1 = fn(x) { add(1, x) }

  let add_one_v2 = add(1, _)


  io.debug(add_one_v1(10))

  io.debug(add_one_v2(10))

}


fn add(a: Int, b: Int) -> Int {

  a + b

}


Gleam tiene una sintaxis abreviada para crear funciones anónimas que toman un argumento e inmediatamente llaman a otra función con ese argumento: la sintaxis de captura de función.

La función anónima fn(a) { some_function(..., a, ...) } se puede escribir como some_function(..., _, ...), con cualquier cantidad de otros argumentos pasados directamente a la función interna . El guión bajo _ es un marcador de posición para el argumento, equivalente a a en fn(a) { some_function(..., a, ...) }.

domingo, 14 de abril de 2024

Pattern Matching en Erlang parte 2


Iniciemos un nuevo módulo llamado funciones en el que escribiremos un montón de funciones para explorar Pattern Matching:


-module(functions).

-compile(export_all). %% replace with -export() later, for God's sake!


La primera función que escribiremos es head/1, que actúa exactamente como erlang:hd/1, que toma una lista como argumento y devuelve su primer elemento. Se hará con la ayuda del operador | :


head([H|_]) -> H.


Para obtener el segundo elemento de una lista crearíamos la función:


second([_,X|_]) -> X.


Erlang simplemente deconstruirá la lista con Pattern Matching

1> c(functions).

{ok, functions}

2> functions:head([1,2,3,4]).

1

3> functions:second([1,2,3,4]).

2


Crearemos una función same/2 que toma dos argumentos y dice si son idénticos:


same(X,X) ->

true;

same(_,_) ->

false.


Y es así de simple. Antes de explicar cómo funciona la función, repasaremos nuevamente el concepto de variables vinculadas y no vinculadas, por si acaso.

Las variables independientes son variables sin ningún valor asociado. Vincular una variable es simplemente adjuntar un valor a una variable independiente. En el caso de Erlang, cuando se desea asignar un valor a una variable que ya está vinculada, se produce un error a menos que el nuevo valor sea el mismo que el anterior. 

Volviendo a nuestro código: lo que sucede cuando llamas a Same(a,a) es que la primera X se ve como independiente: automáticamente toma el valor a. Luego, cuando Erlang pasa al segundo argumento, ve que X ya está vinculado. Luego lo compara con el a pasado como segundo argumento y mira para ver si coincide. La coincidencia de patrones se realiza correctamente y la función devuelve verdadero. Si los dos valores no son iguales, esto fallará y pasará a la segunda cláusula de función, a la que no le importan sus argumentos (cuando eres el último en elegir, ¡no puedes ser exigente!) y en su lugar lo hará. falso retorno. Tenga en cuenta que esta función puede aceptar cualquier tipo de argumento. Funciona para cualquier tipo de datos, no solo listas o variables individuales. Como ejemplo bastante avanzado, la siguiente función imprime una fecha, pero sólo si tiene el formato correcto:


valid_time({Date = {Y,M,D}, Time = {H,Min,S}}) ->

    io:format("The Date tuple (~p) says today is: ~p/~p/~p,~n",[Date,Y,M,D]),

    io:format("The time tuple (~p) indicates: ~p:~p:~p.~n", [Time,H,Min,S]);

valid_time(_) ->

   io:format("Stop feeding me wrong data!~n").


Tenga en cuenta que es posible utilizar el operador = en el encabezado de la función, lo que nos permite hacer coincidir tanto el contenido dentro de una tupla ({Y,M,D}) como la tupla en su conjunto. La función se puede probar de la siguiente manera:

4> c(functions).

{ok, functions}

5> functions:valid_time({{2011,09,06},{09,04,43}}).

The Date tuple ({2011,9,6}) says today is: 2011/9/6,

The time tuple ({9,4,43}) indicates: 9:4:43.

ok

6> functions:valid_time({{2011,09,06},{09,04}}).

Stop feeding me wrong data!

ok


¡Sin embargo hay un problema! Esta función podría tomar cualquier valor como valor, incluso texto o átomos, siempre que las tuplas tengan la forma {{A,B,C}, {D,E,F}}. Esto denota uno de los límites de Pattern Matching: puede especificar valores realmente precisos, como un número conocido de átomos, o valores abstractos, como el head o tail de una lista, una tupla de N elementos o cualquier cosa _ , etc. Para solucionar este problema utilizamos Guards.


miércoles, 10 de abril de 2024

Funciones anónimas en Gleam


 import gleam/io


pub fn main() {

  // Assign an anonymous function to a variable

  let add_one = fn(a) { a + 1 }

  io.debug(twice(1, add_one))


  // Pass an anonymous function as an argument

  io.debug(twice(1, fn(a) { a * 2 }))

}


fn twice(argument: Int, my_function: fn(Int) -> Int) -> Int {

  my_function(my_function(argument))

}


Además de las funciones con nombre a nivel de módulo, Gleam tiene literales de funciones anónimas, escritas con la sintaxis fn() { ... }.

Las funciones anónimas se pueden utilizar indistintamente con funciones con nombre.

Pattern Matching en Erlang


La primera función que escribiremos deberá saludar a alguien de manera diferente según el género. En la mayoría de los lenguajes necesitarías escribir algo similar a esto:

function greet(Gender,Name)

if Gender == male then

    print("Hello, Mr. %s!", Name)

else if Gender == female then

    print("Hello, Mrs. %s!", Name)

else

    print("Hello, %s!", Name)

end


Con Pattern Matching, Erlang le ahorra una gran cantidad de código repetitivo. Una función similar en Erlang se vería así:


greet(male, Name) ->

    io:format("Hello, Mr. ~s!", [Name]);

greet(female, Name) ->

    io:format("Hello, Mrs. ~s!", [Name]);

greet(_, Name) ->

    io:format("Hello, ~s!", [Name]).


La principal diferencia aquí es que usamos Pattern Matching para definir qué partes de una función deben usarse y vincular los valores que necesitamos al mismo tiempo. ¡No era necesario vincular primero los valores y luego compararlos! Entonces en lugar de:

function(X) ->

    Expression;

function(Y) ->

    Expression;

function(_) ->

    Expression.


para obtener resultados similares, pero en un estilo mucho más declarativo. Cada una de estas declaraciones de funciones se denomina cláusula de función. Las cláusulas de función deben estar separadas por punto y coma (;) y juntas forman una declaración de función. Una declaración de función cuenta como una declaración más grande y es por eso que la cláusula de función final termina con un punto. 


lunes, 8 de abril de 2024

Funciones de primer orden en Gleam

 


import gleam/io


pub fn main() {

  // Call a function with another function

  io.debug(twice(1, add_one))


  // Functions can be assigned to variables

  let my_function = add_one

  io.debug(my_function(100))

}


fn twice(argument: Int, passed_function: fn(Int) -> Int) -> Int {

  passed_function(passed_function(argument))

}


fn add_one(argument: Int) -> Int {

  argument + 1

}


En Gleam las funciones son valores. Se pueden asignar a variables, pasar a otras funciones y cualquier otra cosa que pueda hacer con valores.

Aquí la función add_one se pasa como argumento a la función dos veces.

Observe que la palabra clave fn también se usa para describir el tipo de función que toma dos veces como segundo argumento.

ClearScript


ClearScript es una librería que permite ejecutar javascript o VBScript en .NET. Actualmente es compatible con JavaScript (a través de V8 y JScript) y VBScript.

Vamos con un ejemplo:

Primero agregamos la dependencia: 


dotnet add package Microsoft.ClearScript --version 7.4.5


Y bueno, ahora podemos ejecutar javascript por ejemplo: 


using Microsoft.ClearScript;

using Microsoft.ClearScript.V8;


public class Example

{

    static void Main()

    {

        // Create a new V8ScriptEngine

        using var engine = new V8ScriptEngine();

        try

        {

            // Execute JavaScript code

            engine.Execute("var x = 10; var y = 20; var z = x + y;");


            // Get the value of a JavaScript variable

            var zValue = engine.Script.z;


            Console.WriteLine("The value of z is: " + zValue);

        }

        catch (ScriptEngineException ex)

        {

            Console.WriteLine("Error executing JavaScript: " + ex.Message);

        }

    }

}


Y si todo fue bien el resultado es: 


The value of z is: 30


Y listo! 

Dejo link: https://microsoft.github.io/ClearScript/

sábado, 6 de abril de 2024

Funciones en Gleam



import gleam/io


pub fn main() {

  io.debug(double(10))

}


fn double(a: Int) -> Int {

  multiply(a, 2)

}


fn multiply(a: Int, b: Int) -> Int {

  a * b

}


La palabra clave fn se utiliza para definir nuevas funciones.

Las funciones double y multiply se definen sin la palabra clave pub. Esto las convierte en funciones privadas, solo se pueden utilizar dentro de este módulo. Si otro módulo intentara usarlos, se produciría un error del compilador.

Al igual que con las asignaciones, las anotaciones de tipo son opcionales para los argumentos de funciones y los valores de retorno. Se considera una buena práctica utilizar anotaciones tipográficas para funciones, para mayor claridad y para fomentar un diseño intencional y reflexivo.

viernes, 5 de abril de 2024

Más acerca de los módulos de Erlang


Seguimos con los módulos. 

Los atributos del módulo son metadatos que describen el módulo en sí. ¿Dónde podemos encontrar estos metadatos cuando no tenemos acceso a la fuente? Bueno, al compilar un módulo, recogerá la mayoría de los atributos del módulo y los almacenará (junto con otra información) en una función module_info/0. Puedes ver los metadatos del módulo useless de la siguiente manera:

9> useless:module_info().

[{exports,[{add,2},

{hello,0},

{greet_and_add_two,1},

{module_info,0},

{module_info,1}]},

{imports,[]},

{attributes,[{vsn,[174839656007867314473085021121413256129]}]},

{compile,[{options,[]},

{version,"4.6.2"},

{time,{2009,9,9,22,15,50}},

{source,"/home/ferd/learn-you-some-erlang/useless.erl"}]}]

10> useless:module_info(attributes).

[{vsn,[174839656007867314473085021121413256129]}]


El fragmento anterior también muestra una función adicional, module_info/1, que le permitirá obtener una información específica. Puede ver funciones exportadas, funciones importadas, atributos (aquí es donde irían sus metadatos personalizados) y opciones e información. 

vsn es un valor único generado automáticamente que es diferente en cada versión del código, excluyendo los comentarios. Se utiliza en la carga en caliente de código (actualización de una aplicación mientras se ejecuta, sin detenerla) y en algunas herramientas relacionadas con el manejo de versiones. También podemos especificar un valor vsn: simplemente agregando -vsn(VersionNumber) al módulo.

Otro punto que sería bueno abordar con respecto al diseño general del módulo: ¡evite las dependencias circulares! Un módulo A no debe llamar a un módulo B que también llama al módulo A. Estas dependencias suelen terminar dificultando el mantenimiento del código. De hecho, depender de demasiados módulos, incluso si no están en una dependencia circular, puede dificultar el mantenimiento. Lo último que desea es despertarse en medio de la noche y encontrar a un ingeniero de software o informático maníaco tratando de arrancarle los ojos debido al terrible código que ha escrito.

Por motivos similares (mantenimiento y miedo a la vista), suele considerarse una buena práctica reagrupar funciones que tienen funcionamiento similar.

martes, 2 de abril de 2024

Constantes en Gleam


 

import gleam/io


const ints: List(Int) = [1, 2, 3]


const floats = [1.0, 2.0, 3.0]


pub fn main() {

  io.debug(ints)

  io.debug(ints == [1, 2, 3])


  io.debug(floats)

  io.debug(floats == [1.0, 2.0, 3.0])

}

Y el resultado será: 

[1, 2, 3]

True

[1, 2, 3]

True


Además de permitir tareas, Gleam también tiene constantes, que se definen en el nivel superior de un módulo.

Las constantes deben ser valores literales, no se pueden utilizar funciones en sus definiciones.

Las constantes pueden ser útiles para los valores que se utilizan en todo el programa, ya que permiten nombrarlos y garantizar que no haya diferencias en la definición entre cada uso.

Usar una constante puede ser más eficiente que crear el mismo valor en múltiples funciones, aunque las características de rendimiento exactas dependerán del tiempo de ejecución y de si se compila en Erlang o JavaScript.

Declaración de módulos en Erlang parte 2


Seguimos con los módulos. 

Si compilamos el modulo se genera un '.beam' significa Erlang Abstract Machine de Bogdan/Björn, que es la propia VM. Existen otras máquinas virtuales para Erlang, pero ya no se usan y son historia: JAM (Joe's Abstract Machine, inspirada en WAM de Prolog y el antiguo BEAM, que intentó compilar Erlang en C y luego en código nativo. Las pruebas comparativas demostraron pocos beneficios en esta práctica y se abandonó el concepto.

Existen una gran cantidad de indicadores de compilación para tener más control sobre cómo se compila un módulo. Podemos obtener una lista de todos ellos en la documentación de Erlang. Las banderas más comunes son:


-debug_info

Las herramientas de Erlang, como los depuradores, la cobertura de código y las herramientas de análisis estático, utilizarán la información de depuración de un módulo para realizar su trabajo.

-{outdir,Dir}

De forma predeterminada, el compilador de Erlang creará los archivos 'beam' en el directorio actual. Esto le permitirá elegir dónde colocar el archivo compilado.

-export_all

Ignorará el atributo del módulo -export y en su lugar exportará todas las funciones definidas. Esto es principalmente útil al probar y desarrollar código nuevo, pero no debe usarse en producción.

-{d,Macro} o {d,Macro,Valor}

Define una macro que se utilizará en el módulo, donde Macro es un átomo. Esto se usa con más frecuencia cuando se realizan pruebas unitarias, lo que garantiza que un módulo solo tendrá sus funciones de prueba creadas y exportadas cuando se deseen explícitamente. De forma predeterminada, el valor es "verdadero" si no está definido como el tercer elemento de la tupla.

La compilación de código nativo no está disponible para todas las plataformas y sistemas operativos, pero en aquellos que lo admiten, puede hacer que sus programas vayan más rápido (aproximadamente un 20% más rápido, según evidencia anecdótica). Para compilar en código nativo, necesita usar el módulo hipe y llamarlo de la siguiente manera: hipe:c(Module,OptionsList). También puedes usar c(Módulo,[nativo]). cuando está en el caparazón para lograr resultados similares. Tenga en cuenta que el archivo .beam generado contendrá código nativo y no nativo, y la parte nativa no será portátil entre plataformas.

lunes, 1 de abril de 2024

Listas en Gleam


import gleam/io


pub fn main() {

  let ints = [1, 2, 3]


  io.debug(ints)


  // Immutably prepend

  io.debug([-1, 0, ..ints])


  // Uncomment this to see the error

  // io.debug(["zero", ..ints])


  // The original lists are unchanged

  io.debug(ints)

}


Las listas son colecciones ordenadas de valores.

La lista es un tipo genérico y tiene un parámetro de tipo para el tipo de valores que contiene. Una lista de enteros tiene el tipo List(Int) y una lista de cadenas tiene el tipo List(String).

Las listas son listas inmutables de enlace único, lo que significa que son muy eficientes para agregar y eliminar elementos del principio de la lista.

Contar la longitud de una lista u obtener elementos de otras posiciones en la lista es costoso y rara vez se hace. Es raro escribir algoritmos que indexen secuencias en Gleam, pero cuando se escriben, una lista no es la elección correcta de estructura de datos.

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.


jueves, 28 de marzo de 2024

Cursos Gugler

 Como todos los años se dictan los cursos gugler que son una buena opción para capacitarse. 









miércoles, 27 de marzo de 2024

¿Listo para ver lo que la IA puede hacer por ti?

Recibi este mail y lo quería compartir con ustedes: 


IA integrada en las aplicaciones de Oracle Cloud
IA integrada en las aplicaciones de Oracle Cloud
Obtenga mejores estadísticas empresariales
Descubra cómo las aplicaciones de IA se adaptan a su forma de trabajar con el aprendizaje automático y la inteligencia artificial.

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.


sábado, 23 de marzo de 2024

Los bloques { } en Gleam


import gleam/io


pub fn main() {

  let fahrenheit = {

    let degrees = 64

    degrees

  }

  // io.debug(degrees) // <- This will not compile


  // Changing order of evaluation

  let celsius = { fahrenheit - 32 } * 5 / 9

  io.debug(celsius)

}


Los bloques son una o más expresiones agrupadas entre llaves. Cada expresión se evalúa en orden y se devuelve el valor de la última expresión.

Cualquier variable asignada dentro del bloque solo se puede utilizar dentro del bloque.

Los bloques { } también se pueden utilizar para cambiar el orden de evaluación de expresiones de operadores binarios.

* se resuelve antes que + por lo que la expresión 1 + 2 * 3 se evalúa como 7. Si 1 + 2 debe evaluarse primero para que la expresión se evalúe como 9, entonces la expresión se puede envolver en un bloque: { 1 + 2 } * 3. Esto es similar a agrupar entre paréntesis en otros lenguajes.

martes, 19 de marzo de 2024

Alias de tipos en Gleam


import gleam/io


pub type UserId =  Int


pub fn main() {

  let one: UserId = 1

  let two: Int = 2


  // UserId and Int are the same type

  io.debug(one == two)

}


Se puede utilizar un alias de tipo para hacer referencia a un tipo con un nombre diferente. Darle un alias a un tipo no crea un nuevo tipo, sigue siendo el mismo tipo.

El nombre de un tipo siempre comienza con una letra mayúscula, a diferencia de las variables y funciones, que comienzan con una letra minúscula.

Cuando se utiliza la palabra clave pub, el alias de tipo es público y otros módulos pueden hacer referencia a él.

domingo, 17 de marzo de 2024

Anotaciones de tipo en gleam



pub fn main() {

  let _name: String = "Gleam"

  let _is_cool: Bool = True

  let _version: Int = 1

}


let se pueden escribir con una anotación de tipo después del nombre.

Las anotaciones de tipo pueden ser útiles para fines de documentación, pero no cambian la forma en que Gleam verifica el código más allá de garantizar que la anotación sea correcta.

Normalmente, el código Gleam no tendrá anotaciones de tipo para las asignaciones.


sábado, 16 de marzo de 2024

Comprensiones binarias en Erlang


 Las comprensiones binarias son para la sintaxis de bits lo que las listas por comprensión son para las listas: una forma de hacer que el código sea breve y conciso. Son relativamente nuevos en el mundo de Erlang como lo fueron en revisiones anteriores de Erlang, pero requirieron un módulo que los implementara para usar un indicador de compilación especial para poder funcionar. Desde las revisiones R13B (las que se usan aquí), se han convertido en estándar y se pueden usar en cualquier lugar, incluido el shell:


1> [ X || <<X>> <= <<1,2,3,4,5>>, X rem 2 == 0].    

[2,4]


El único cambio en la sintaxis con respecto a las listas por comprensión normales es <- que se convirtió en <= y usa binarios (<<>>) en lugar de listas ([]). Anteriormente vimos un ejemplo en el que había un valor binario de muchos píxeles en el que utilizamos la coincidencia de patrones para capturar los valores RGB de cada píxel. Estaba bien, pero en estructuras más grandes, posiblemente sería más difícil de leer y mantener. El mismo ejercicio se puede hacer con una comprensión binaria de una línea, que es mucho más clara:


2> 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>>

3> RGB = [ {R,G,B} || <<R:8,G:8,B:8>> <= Pixels ].

[{213,45,132},{64,76,32},{76,0,0},{234,32,15}]


Cambiando <- a <= usemos un flujo binario como generador. La comprensión binaria completa básicamente cambió los datos binarios a números enteros dentro de tuplas. Existe otra sintaxis de comprensión binaria que le permite hacer exactamente lo contrario:


4> << <<R:8, G:8, B:8>> ||  {R,G,B} <- RGB >>.

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


Los elementos del binario resultante requieren un tamaño claramente definido si el generador devolvió binarios:


5> << <<Bin>> || Bin <- [<<3,7,5,4,7>>] >>.

** exception error: bad argument

6> << <<Bin/binary>> || Bin <- [<<3,7,5,4,7>>] >>. 

<<3,7,5,4,7>>


También es posible tener una comprensión binaria con un generador binario, siempre que se respete la regla de tamaño fijo anterior:


7> << <<(X+1)/integer>> || <<X>> <= <<3,7,5,4,7>> >>.

<<4,8,6,5,8>>