Translate

viernes, 12 de enero de 2024

¡C# es el lenguaje de programación del año 2023!

Como cada año se publica el indice tiobe que indica el uso de los lenguajes. Y este año la novedad fue el amplio crecimiento de C#. 

"Por primera vez en la historia del índice TIOBE, C# ha ganado el premio al lenguaje de programación del año. ¡Felicidades! C# ha estado entre los 10 mejores durante más de 2 décadas y ahora que se está poniendo al día con los 4 grandes lenguajes, ganó el merecido premio al ser el lenguaje con el mayor repunte en un año (+1,43%). Los segundos puestos son Scratch (+0,83%) y Fortran (+0,64%). C# le está quitando cuota de mercado a Java y se está volviendo cada vez más popular en dominios como backends de aplicaciones web y juegos (gracias a Unity). C# se puede utilizar de forma gratuita y evoluciona a un ritmo constante, lo que hace que el lenguaje sea más expresivo con cada nueva versión. C# llegó para quedarse y pronto podría incluso superar a Java.

Aparte de C#, el año pasado hubo muchos cambios interesantes en el índice TIOBE. Fortran y Kotlin se convirtieron permanentemente en los 20 mejores jugadores reemplazando a los antiguos favoritos R y Perl. Fortran está muy preparado para hacer cálculos con buenas bibliotecas y sigue siendo uno de los favoritos de las universidades en muchos ámbitos. Kotlin es el competidor de Java fácil de aprender y escribir. Pregunta interesante: ¿qué lenguajes entrarán en el top 20 del índice TIOBE en 2024? Esto es muy difícil de predecir. Julia tocó brevemente el índice TIOBE en 2023, pero no pudo mantener esa posición. Se necesita la madurez del idioma y la comunidad de Julia para tener una segunda oportunidad. Apostaría por Dart (con Flutter) y TypeScript. Este último ya se utiliza mucho en la industria, pero por alguna razón todavía no se destaca en el índice TIOBE. Veamos qué nos depara el 2024." -- Paul Jansen, director ejecutivo de TIOBE Software (Esto nos dice la pagina oficial de TIOBE.)

Como lenguje más utilizado lo tenemos a python, seguido de c, c++ y java. 


Jan 2024Jan 2023ChangeProgramming LanguageRatingsChange
11Python pagePython13.97%-2.39%
22C pageC11.44%-4.81%
33C++ pageC++9.96%-2.95%
44Java pageJava7.87%-4.34%
55C# pageC#7.16%+1.43%
67changeJavaScript pageJavaScript2.77%-0.11%
710changePHP pagePHP1.79%+0.40%
86changeVisual Basic pageVisual Basic1.60%-3.04%
98changeSQL pageSQL1.46%-1.04%
1020changeScratch pageScratch1.44%+0.86%
1112changeGo pageGo1.38%+0.23%
1227changeFortran pageFortran1.09%+0.64%
1317changeDelphi/Object Pascal pageDelphi/Object Pascal1.09%+0.36%
1415changeMATLAB pageMATLAB0.97%+0.06%
159changeAssembly language pageAssembly language0.92%-0.68%
1611changeSwift pageSwift0.89%-0.31%
1725changeKotlin pageKotlin0.85%+0.37%
1816changeRuby pageRuby0.80%+0.01%
1918changeRust pageRust0.79%+0.18%
2031changeCOBOL pageCOBOL0.78%+0.45%



La verdad es que descreo un poco de este indice, por ejemplo me llama la atención que Rust bajo, cuando en general veo que va creciendo mucho. O por ejemplo que sea más utilizado Scratch que Go o Rust. Son cositas que no me cierran :( 


Dejo link: https://www.tiobe.com/tiobe-index/

Que es gRPC?

 


gRPC es una tecnología de comunicación entre procesos que nos permite conectar, invocar, operar y depurar aplicaciones heterogéneas distribuidas tan fácilmente como realizar una llamada a una función local.

Cuando desarrollamos una aplicación gRPC, lo primero que hacemos es definir una interfaz de servicio. La definición de la interfaz de servicio contiene información sobre cómo los consumidores pueden consumir el servicio, qué métodos permite que los consumidores llamen de forma remota, qué parámetros de método y formatos de mensaje usar al invocar esos métodos, etc. El lenguaje que especificamos en la definición del servicio se conoce como lenguaje de definición de interfaz (IDL).

Con esa definición de servicio, se puede generar el código del lado del servidor conocido como esqueleto del servidor, que simplifica la lógica del lado del servidor al proporcionar abstracciones de comunicación de bajo nivel. Además, puede generar el código del lado del cliente, conocido como código auxiliar del cliente, que simplifica la comunicación del lado del cliente con abstracciones para ocultar la comunicación de bajo nivel para diferentes lenguajes de programación. Los métodos que especifique en la definición de la interfaz de servicio pueden ser invocados remotamente por el lado del cliente tan fácilmente como realizar una invocación de función local. El framework gRPC subyacente maneja todas las complejidades que normalmente se asocian con el cumplimiento de contratos de servicio estrictos, serialización de datos, comunicación de red, autenticación, control de acceso, observabilidad, etc.

Para comprender los conceptos fundamentales de gRPC, echemos un vistazo a un caso de uso del mundo real de un microservicio implementado con gRPC. Supongamos que estamos creando una aplicación minorista en línea compuesta por múltiples microservicios.


La definición del servicio se especifica en el archivo ProductInfo.proto, que utilizan tanto el lado del servidor como el del cliente para generar el código. En este ejemplo, hemos asumido que el servicio se implementa utilizando el lenguaje Go y que el consumidor se implementa utilizando Java. La comunicación de red entre el servicio y el consumidor se realiza a través de HTTP/2.


miércoles, 10 de enero de 2024

Test de integración en Rust


Si necesitamos probar alguna librería o integración con base de datos o otros componentes podemos utilizar pruebas de integración.

Para hacerlas en Rust, debemos crear un archivo .rs en una carpeta tests/ :


// tests/my_library.rs

use my_library::init;


#[test]

fn test_init() {

    assert!(init().is_ok());

}

Y listo. 

Unit Tests en Rust


Rust y Cargo vienen con un framework de prueba unitario simple:

  • Las pruebas unitarias son compatibles con todo el código.
  • Las pruebas de integración se admiten a través del directorio tests/.

Las pruebas están anotadas con el atributo #[prueba]. Las pruebas unitarias a menudo se colocan en un módulo de pruebas anidadas, usando #[cfg(test)] para compilarlas condicionalmente. Veamos un ejemplo: 


fn first_word(text: &str) -> &str {

    match text.find(' ') {

        Some(idx) => &text[..idx],

        None => &text,

    }

}


#[cfg(test)]

mod test {

    use super::*;


    #[test]

    fn test_empty() {

        assert_eq!(first_word(""), "");

    }


    #[test]

    fn test_single_word() {

        assert_eq!(first_word("Hello"), "Hello");

    }


    #[test]

    fn test_multiple_words() {

        assert_eq!(first_word("Hello World"), "Hello");

    }

}

Podemos correr los test con cargo test: 


$ cargo test 

   Compiling hello_cargo v0.1.0 

    Finished test [unoptimized + debuginfo] target(s) in 0.37s

     Running unittests src/main.rs 


running 3 tests

test test::test_multiple_words ... ok

test test::test_empty ... ok

test test::test_single_word ... ok


test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s



martes, 9 de enero de 2024

Primer servicio GRpc con Go


Vamos a hacer un servicio que salude en Go y GRpc. Lo primero que tenemos que hacer es instalar las dependencias: 

$ go install google.golang.org/protobuf/cmd/protoc-gen-go@latest

go: downloading google.golang.org/protobuf v1.28.1

$ go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest

go: downloading google.golang.org/grpc v1.2.1


Luego escribir el .proto : 

syntax = "proto3";


option go_package = "google.golang.org/grpc/examples/helloworld/helloworld";

option java_multiple_files = true;

option java_package = "io.grpc.examples.helloworld";

option java_outer_classname = "HelloWorldProto";


package helloworld;


// The greeting service definition.

service Greeter {

  // Sends a greeting

  rpc SayHello (HelloRequest) returns (HelloReply) {}

}


// The request message containing the user's name.

message HelloRequest {

  string name = 1;

}


// The response message containing the greetings

message HelloReply {

  string message = 1;

}

Este archivo, es un descriptor del servicio y nos permite generar código con el comando protoc, por ejemplo: 

protoc --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative ./greetings/greetings.proto


Y luego podemos escribir el cliente y el servidor. Por ejemplo: 

Server: 

package main


import (

"context"

"flag"

"fmt"

"log"

"net"


"google.golang.org/grpc"

pb "google.golang.org/grpc/examples/helloworld/helloworld"

)


var (

port = flag.Int("port", 50051, "The server port")

)


// server is used to implement helloworld.GreeterServer.

type server struct {

pb.UnimplementedGreeterServer

}


// SayHello implements helloworld.GreeterServer

func (s *server) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) {

log.Printf("Received: %v", in.GetName())

return &pb.HelloReply{Message: "Hello " + in.GetName()}, nil

}


func main() {

flag.Parse()

lis, err := net.Listen("tcp", fmt.Sprintf(":%d", *port))

if err != nil {

log.Fatalf("failed to listen: %v", err)

}

s := grpc.NewServer()

pb.RegisterGreeterServer(s, &server{})

log.Printf("server listening at %v", lis.Addr())

if err := s.Serve(lis); err != nil {

log.Fatalf("failed to serve: %v", err)

}

}


y el cliente: 


package main


import (

"context"

"flag"

"log"

"time"


"google.golang.org/grpc"

"google.golang.org/grpc/credentials/insecure"

pb "google.golang.org/grpc/examples/helloworld/helloworld"

)


const (

defaultName = "world"

)


var (

addr = flag.String("addr", "localhost:50051", "the address to connect to")

name = flag.String("name", defaultName, "Name to greet")

)


func main() {

flag.Parse()

// Set up a connection to the server.

conn, err := grpc.Dial(*addr, grpc.WithTransportCredentials(insecure.NewCredentials()))

if err != nil {

log.Fatalf("did not connect: %v", err)

}

defer conn.Close()

c := pb.NewGreeterClient(conn)


// Contact the server and print out its response.

ctx, cancel := context.WithTimeout(context.Background(), time.Second)

defer cancel()

r, err := c.SayHello(ctx, &pb.HelloRequest{Name: *name})

if err != nil {

log.Fatalf("could not greet: %v", err)

}

log.Printf("Greeting: %s", r.GetMessage())

}


Y listo!

Para probarlo, ejecutamos el server : 

$ go run greeter_server/main.go


Y luego el cliente : 

$ go run greeter_client/main.go


Dejo link: https://grpc.io/docs/languages/go/quickstart/


lunes, 8 de enero de 2024

use, super, self en Rust


Un módulo puede incorporar símbolos de otros módulos con use. Normalmente verá algo como esto en la parte superior de cada módulo:

use std::collections::HashSet;

use std::process::abort;


Paths:

Los paths se pueden resolver de la siguiente manera:


  • Como ruta relativa:

foo o self::foo se refiere a foo del módulo actual,

super::foo se refiere a foo en el módulo principal.


  • Como camino absoluto:

crate::foo se refiere a foo de la raíz del proyecto actual,

bar::foo se refiere a foo en la caja de bar.


Es común “reexportar” símbolos en una ruta más corta. Por ejemplo, las bibliotecas de nivel superior en una caja podrían tener

mod storage;


pub use storage::disk::DiskStorage;

pub use storage::network::NetworkStorage;


haciendo que DiskStorage y NetworkStorage estén disponibles para otras cajas con una ruta corta y conveniente.

En su mayor parte, sólo es necesario utilizar los elementos que aparecen en un módulo. Sin embargo, un rasgo debe estar dentro del alcance para llamar a cualquier método en ese rasgo, incluso si un tipo que implementa ese rasgo ya está dentro del alcance. Por ejemplo, para usar el método read_to_string en un tipo que implementa el rasgo de lectura, debe usar std::io::Read.

La declaración de uso puede tener un comodín: use std::io::*. Se desaconseja esto porque no está claro qué artículos se importan y estos pueden cambiar con el tiempo.

domingo, 7 de enero de 2024

Visibilidad en Rust


Los módulos permiten definir la visibilidad :

  • Los elementos del módulo son privados por defecto (oculta los detalles de implementación).
  • Los elementos de padres y hermanos siempre están visibles.
  • En otras palabras, si un elemento es visible en el módulo foo, será visible en todos los descendientes de foo.


mod outer {

    fn private() {

        println!("outer::private");

    }


    pub fn public() {

        println!("outer::public");

    }


    mod inner {

        fn private() {

            println!("outer::inner::private");

        }


        pub fn public() {

            println!("outer::inner::public");

            super::private();

        }

    }

}


fn main() {

    outer::public();

}


Podemos utilizar la palabra clave pub para hacer públicos los módulos. Además, existen especificadores pub(...) avanzados para restringir el alcance de la visibilidad pública.


Jerarquía de archivos en Rust

mod garden;

Esto le indica a Rust que el contenido del módulo garden se encuentra en src/garden.rs. De manera similar, se puede definir un módulo garden::vegetables que va estar en src/garden/vegetables.rs.

Los módulos definidos en archivos también se pueden documentar mediante "comentarios internos del documento". Estos documentan el elemento que los contiene, por ejemplo: 


//! This module implements the garden, including a highly performant germination

//! implementation.


// Re-export types from this module.

pub use garden::Garden;

pub use seeds::SeedPacket;


/// Sow the given seed packets.

pub fn sow(seeds: Vec<SeedPacket>) {

    todo!()

}


/// Harvest the produce in the garden that is ready.

pub fn harvest(garden: &mut Garden) {

    todo!()

}


Antes de Rust 2018, los módulos debían estar ubicados en module/mod.rs en lugar de un archivo y esta sigue siendo una alternativa funcional para las ediciones posteriores a 2018.

La razón principal para introducir filename.rs como alternativa a filename/mod.rs fue porque muchos archivos llamados mod.rs pueden ser difíciles de distinguir en los IDE.

Un anidamiento más profundo puede utilizar carpetas, incluso si el módulo principal es un archivo:

src/

├── main.rs

├── top_module.rs

└── top_module/

    └── sub_module.rs


El lugar donde Rust buscará los módulos se puede cambiar con una directiva del compilador:

#[path = "some/path.rs"]
mod some_module;

Esto es útil, por ejemplo, si desea colocar pruebas para un módulo en un archivo llamado some_module_test.rs, similar a la convención en Go.


miércoles, 3 de enero de 2024

Modulos en Rust


Hemos visto cómo los bloques impl nos permiten asignar funciones de espacio de nombres a un tipo.

De manera similar, mod nos permite tipos de espacios de nombres y funciones:


mod foo {

    pub fn do_something() {

        println!("In the foo module");

    }

}


mod bar {

    pub fn do_something() {

        println!("In the bar module");

    }

}


fn main() {

    foo::do_something();

    bar::do_something();

}


Los paquetes brindan funcionalidad e incluyen un archivo Cargo.toml que describe cómo crear un paquete de más de 1 caja.

Las cajas son un árbol de módulos, donde una caja binaria crea un ejecutable y/o una caja de biblioteca se compila en una biblioteca.

Los módulos definen la organización, el alcance de los proyectos. 

martes, 2 de enero de 2024

FromIterator en Rust


FromIterator te permite crear una colección a partir de un Iterator.


fn main() {

    let primes = vec![2, 3, 5, 7];

    let prime_squares = primes.into_iter().map(|p| p * p).collect::<Vec<_>>();

    println!("prime_squares: {prime_squares:?}");

}


Iterator iteradores:


fn collect<B>(self) -> B

where

    B: FromIterator<Self::Item>,

    Self: Sized


Hay dos formas de especificar B para este método:

  • Con el “turbofish”: some_iterator.collect::<COLLECTION_TYPE>(), como se muestra. La abreviatura _ utilizada aquí le permite a Rust inferir el tipo de elementos Vec.
  • Con inferencia de tipos: let prime_squares: Vec<_> = some_iterator.collect(). Vuelva a escribir el ejemplo para utilizar este formulario.

Hay implementaciones básicas de FromIterator para Vec, HashMap, etc. También hay implementaciones más especializadas que le permiten hacer cosas interesantes como convertir un Iterator<Item = Result<V, E>> en un Result<Vec<V>, E> .

sábado, 30 de diciembre de 2023

Feliz Navidad y buen año para todos!!


Como todos los años les deseo una feliz navidad y un buen 2024. 

Gracias por leerme! 

viernes, 29 de diciembre de 2023

IntoIterator en Rust


El trait Iterator le indica cómo iterar una vez que haya creado un iterador. El trait relacionado IntoIterator define cómo crear un iterador para un tipo. Es utilizado automáticamente por el bucle for.


struct Grid {

    x_coords: Vec<u32>,

    y_coords: Vec<u32>,

}


impl IntoIterator for Grid {

    type Item = (u32, u32);

    type IntoIter = GridIter;

    fn into_iter(self) -> GridIter {

        GridIter { grid: self, i: 0, j: 0 }

    }

}


struct GridIter {

    grid: Grid,

    i: usize,

    j: usize,

}


impl Iterator for GridIter {

    type Item = (u32, u32);


    fn next(&mut self) -> Option<(u32, u32)> {

        if self.i >= self.grid.x_coords.len() {

            self.i = 0;

            self.j += 1;

            if self.j >= self.grid.y_coords.len() {

                return None;

            }

        }

        let res = Some((self.grid.x_coords[self.i], self.grid.y_coords[self.j]));

        self.i += 1;

        res

    }

}


fn main() {

    let grid = Grid {

        x_coords: vec![3, 5, 7, 9],

        y_coords: vec![10, 20, 30, 40],

    };

    for (x, y) in grid {

        println!("point = {x}, {y}");

    }

}


Cada implementación de IntoIterator debe declarar dos tipos:

  • Item: el tipo sobre el que se va a iterar, como i8,
  • IntoIter: el tipo de Iterator devuelto por el método into_iter.

Tenga en cuenta que IntoIter y Item están vinculados: el iterador debe tener el mismo tipo de elemento, lo que significa que devuelve Option<Item>

El ejemplo itera sobre todas las combinaciones de coordenadas x e y.


domingo, 24 de diciembre de 2023

Iterator en Rust


El trait Iterator admite la iteración sobre valores en una colección. Requiere un método next y proporciona muchos métodos. Muchos tipos de bibliotecas estándar implementan Iterator y usted también puede implementarlo usted mismo:


struct Fibonacci {

    curr: u32,

    next: u32,

}


impl Iterator for Fibonacci {

    type Item = u32;


    fn next(&mut self) -> Option<Self::Item> {

        let new_next = self.curr + self.next;

        self.curr = self.next;

        self.next = new_next;

        Some(self.curr)

    }

}


fn main() {

    let fib = Fibonacci { curr: 0, next: 1 };

    for (i, n) in fib.enumerate().take(5) {

        println!("fib({i}): {n}");

    }

}


Iterator implementa muchas operaciones de programación funcional comunes sobre colecciones (por ejemplo, mapear, filtrar, reducir, etc.). Este es el rasgo donde puedes encontrar toda la documentación sobre ellos. En Rust, estas funciones deberían producir un código tan eficiente como las implementaciones imperativas equivalentes.

sábado, 23 de diciembre de 2023

Invertir una lista en prolog


Si queremos invertir una lista en prolog lo que podemos hacer es utilizar el predicado union del post anterior y hacer lo siguiente : 


inversa([], []).

inversa([H|T], L) :-

    inversa(T, IT),

    union(IT, [H], L).


Lo probamos : 


inversa([1,2,3,4], X)

X = [4, 3, 2, 1]

Introducción a gRPC


gRPC es un sistema de llamadas a procedimientos remotos (RPC) de código abierto desarrollado por Google. Se basa en el protocolo HTTP/2 para la comunicación entre servicios, lo que ofrece una comunicación eficiente y de bajo consumo de recursos.

Características Principales:

  • Protocolo basado en HTTP/2: Utiliza HTTP/2 como su protocolo subyacente, lo que proporciona una comunicación más rápida, eficiente y multiplexada.
  • IDL y generación de código: Utiliza Protocol Buffers (protobuf) para definir la estructura del servicio y los mensajes intercambiados entre los clientes y servidores. Esto permite la generación automática de código en varios lenguajes.
  • Soporte para múltiples lenguajes: Ofrece soporte para una variedad de lenguajes de programación, lo que permite a los desarrolladores construir servicios heterogéneos y sistemas distribuidos.
  • Tipado fuerte y serialización eficiente: Utiliza Protocol Buffers para la serialización de datos, lo que resulta en una comunicación más rápida y eficiente que otros métodos de serialización.

Ventajas:

  • Alta eficiencia y rendimiento en la comunicación entre microservicios.
  • Facilita la creación de servicios interoperables en diferentes lenguajes.
  • Útil en entornos distribuidos, como arquitecturas de microservicios, Internet de las cosas (IoT) y sistemas basados en la nube.


Veamos un ejemplo de un protobuf:

syntax = "proto3";


service Greeter {

  rpc SayHello (HelloRequest) returns (HelloResponse) {}

}


message HelloRequest {

  string name = 1;

}


message HelloResponse {

  string message = 1;

}



gRPC ofrece una forma eficiente y poderosa de comunicación entre servicios, facilitando el desarrollo de aplicaciones distribuidas escalables y de alto rendimiento. Su capacidad para generar código y su enfoque en la eficiencia lo convierten en una herramienta valiosa para la construcción de sistemas modernos y distribuidos.

Tal vez te preguntas si esto va a sustituir a Rest y la respuesta es no, Rest proporciona una interfaz clara tanto para aplicaciones como para humanos para aplicaciones en cambio gRPC sacrifica la claridad de las apis en post de una mayor eficiencia. 

Si tenes que hacer una API que no interesa tanto la performance y es necesario que sea super clara para que todo el mundo la use, Rest es la mejor opción. Si es necesaria una comunicación rápida entre sistemas que tengo el control, gRPC viene bien. 

Dejo link: https://grpc.io/



viernes, 22 de diciembre de 2023

Unir dos listas en prolog


Vamos a hacer un predicado que una dos listas en prolog: 


unir([], Lista, Lista).

unir([X | Resto], Lista, [X | Resultado]) :-

   unir(Resto, Lista, Resultado).


Y lo vamos a probar : 

unir([5,6,7],[1,2,3,4], X)

X = [5, 6, 7, 1, 2, 3, 4]

jueves, 21 de diciembre de 2023

Maps en Go


Los maps son una estructura de datos que asocia valores de un tipo (la clave) con valores de otro tipo (el elemento o valor). La clave puede ser de cualquier tipo para el que esté definido el operador de igualdad, como números enteros, números de punto flotante y complejos, cadenas, punteros, interfaces (siempre que el tipo dinámico admita la igualdad), estructuras y matrices. Los slices no se pueden utilizar como claves de map porque la igualdad no está definida en ellos. Al igual que los slices, los map contienen referencias a una estructura de datos subyacente. Si pasa un map a una función que cambia el contenido del map, los cambios serán visibles en la persona que llama.

Los map se pueden construir utilizando la sintaxis literal compuesta habitual con pares clave-valor separados por dos puntos, por lo que es fácil construirlos durante la inicialización.0


var timeZone = map[string]int{

    "UTC":  0*60*60,

    "EST": -5*60*60,

    "CST": -6*60*60,

    "MST": -7*60*60,

    "PST": -8*60*60,

}


Asignar y recuperar valores de maps parece sintácticamente igual que hacer lo mismo con matrices y slices, excepto que no es necesario que el índice sea un número entero.


offset := timeZone["EST"]


Un intento de recuperar un valor de mapa con una clave que no está presente en el mapa devolverá el valor cero para el tipo de entradas en el mapa. Por ejemplo, si el mapa contiene números enteros, buscar una clave inexistente devolverá 0. Un conjunto se puede implementar como un mapa con valor de tipo bool. 

attended := map[string]bool{

    "Ann": true,

    "Joe": true,

    ...

}


if attended[person] { // will be false if person is not in the map

    fmt.Println(person, "was at the meeting")

}


A veces es necesario distinguir una entrada faltante de un valor cero. ¿Hay una entrada para "UTC" o es 0 porque no está en el mapa? Se puede discriminar con una forma de asignación múltiple.


var seconds int

var ok bool

seconds, ok = timeZone[tz]


Por razones obvias, esto se denomina modismo "coma ok". En este ejemplo, si tz está presente, los segundos se configurarán apropiadamente y ok será verdadero; de lo contrario, los segundos se establecerán en cero y ok será falso. Aquí hay una función que lo combina con un bonito informe de errores:


func offset(tz string) int {

    if seconds, ok := timeZone[tz]; ok {

        return seconds

    }

    log.Println("unknown time zone:", tz)

    return 0

}


Para probar la presencia en el mapa sin preocuparse por el valor real, puede utilizar el identificador en blanco (_) en lugar de la variable habitual para el valor.


_, present := timeZone[tz]


Para eliminar una entrada de mapa, utilice la función incorporada de eliminación, cuyos argumentos son el mapa y la clave que se va a eliminar. Es seguro hacer esto incluso si la clave ya no está en el mapa.


delete(timeZone, "PDT")  // Now on Standard Time


martes, 19 de diciembre de 2023

Predicado que nos indique si un elemento existe en una lista en prolog


Vamos a hacer un predicado que nos indique si un elemento existe en una lista en prolog: 


existe(Elemento, [Elemento | _]).

existe(Elemento, [_ | Tail]) :-

    existe(Elemento, Tail).


Si la probamos : 


existe(5,[1,2,3,4])

false

existe(4,[1,2,3,4])

true

lunes, 18 de diciembre de 2023

Contar elementos de una lista en prolog


Vamos a hacer un predicado que cuenten los elementos de una lista en prolog: 

count_elements([], 0).

count_elements([_ | Tail], Count) :-

    count_elements(Tail, TailCount),

    Count is TailCount + 1.

Contar valores que cumplan un criterio en Lisp

 


Función para contar valores de una lista en lisp según un criterio (que va a ser una función) : 

(defun contarSegun (lista fx) 

 (cond

     ((null lista) 0)

     ((funcall fx (first lista)) 

           (+ (contarSegun (rest lista) fx) 1))

     (T (contarSegun (rest lista) fx))

 )

)


Y vamos a probarla : 


> (contarSegun '(1 2 3 4 5 6) (lambda (a) (> a 3)))

3


> (contarSegun '(1 2 3 4 5 6) (lambda (a) (>= a 3)))

4


> (contarSegun '(1 2 3 4 5 6) (lambda (a) (= a 3)))

1


sábado, 16 de diciembre de 2023

Slices en Rust


Los Slices brindan una vista de una colección más grande, es como una porción:


fn main() {

    let mut a: [i32; 6] = [10, 20, 30, 40, 50, 60];

    println!("a: {a:?}");

    let s: &[i32] = &a[2..4];

    println!("s: {s:?}");

}


Los Slice toman prestados el tipo del arreglo.

Si el Slice comienza en el índice 0, la sintaxis de rango de Rust nos permite eliminar el índice inicial, lo que significa que &a[0..a.len()] y &a[..a.len()] son idénticos. Lo mismo ocurre con el último índice, por lo que &a[2..a.len()] y &a[2..] son idénticos. Por lo tanto, para crear fácilmente un  Slice de todo el vector, podemos usar &a[..].

El tipo de s (&[i32]) ya no menciona la longitud de la matriz. Esto nos permite realizar cálculos en sectores de diferentes tamaños.

miércoles, 13 de diciembre de 2023

¿Qué es Go-Zero?

 


En el mundo del desarrollo de software, la velocidad, la eficiencia y la simplicidad son pilares fundamentales. El framework Go-Zero emerge como una solución poderosa para aquellos que buscan crear aplicaciones escalables y de alto rendimiento utilizando el lenguaje de programación Go (Golang).


Pero ¿Qué es Go-Zero? Go-Zero es un framework moderno y de código abierto diseñado para acelerar el proceso de desarrollo de aplicaciones en Go. Ofrece una arquitectura robusta y flexible, proporcionando herramientas y patrones que permiten construir aplicaciones web, API y microservicios de manera eficiente.


Características Principales:

  • Alto rendimiento: Go-Zero se destaca por su capacidad para manejar cargas de trabajo intensivas y mantener un alto rendimiento incluso en entornos de gran escala.
  • Productividad mejorada: Proporciona abstracciones y utilidades que reducen la complejidad del código, permitiendo a los desarrolladores enfocarse en la lógica de negocio en lugar de detalles de implementación.
  • Facilidad de uso: Con una curva de aprendizaje amigable, su estructura modular y su amplia documentación, Go-Zero facilita a los desarrolladores tanto principiantes como experimentados.
  • Soporte para microservicios: Ofrece herramientas específicas para la construcción de arquitecturas de microservicios, simplificando la comunicación entre ellos y la gestión de datos distribuidos.
Veamos un ejemplo básico de cómo se podría crear un servidor HTTP simple utilizando el framework Go-Zero:

package main

import (
"github.com/tal-tech/go-zero/core/conf"
"github.com/tal-tech/go-zero/rest"
"github.com/tal-tech/go-zero/rest/httpx"
)

type Request struct {
Name string `form:"name"`
}

type Response struct {
Message string `json:"message"`
}

func helloHandler(w httpx.ResponseWriter, r *httpx.Request) {
var req Request
if err := r.ParseForm(&req); err != nil {
w.Error(httpx.BadRequest(err.Error()))
return
}

resp := Response{
Message: "Hello, " + req.Name + "!",
}
w.WriteJson(resp)
}

func main() {
var c rest.RestConf
conf.MustLoad("path/to/config.yaml", &c)

server := rest.MustNewServer(c)
server.AddRoute(rest.Route{
Method:  "GET",
Path:    "/hello",
Handler: helloHandler,
})
defer server.Stop()

server.Start()
}


Go-Zero representa una opción valiosa para aquellos que buscan desarrollar aplicaciones en Go de manera rápida, eficiente y escalable. Su enfoque en el rendimiento y la productividad lo convierten en una herramienta atractiva para proyectos de diversos tamaños y complejidades.

Dejo link: https://github.com/zeromicro/go-zero