Translate

domingo, 6 de diciembre de 2020

Donde anda Clojure?



Clojure es un lenguaje de programación de propósito general dialecto de Lisp. Hace un énfasis especial en el paradigma funcional, con el objetivo de eliminar la complejidad asociada a la programación concurrente. Clojure puede ser ejecutado sobre la Máquina Virtual de Java. Por si no lo conocían. 

Hace mucho que no escribo sobre Clojure, por lo tanto estuve googleando a ver a donde anda... 

Y me encontré que su ecosistema ha crecido bastante, no muy rápido pero a paso seguro. 

Si no lo sabían, podemos crear nuestras aplicaciones Clojure en Leiningen que sería el maven de Clojure. 

A la vez podemos utilizar Datomic para guardar datos en la base de datos nosql, hecha en Clojure... 

Si les gusta Lisp, les va a encantar Clojure. 

Para empezar podemos utilizar un entorno online. Uno que esta bueno es jdoodle que se encuentra en : https://www.jdoodle.com/execute-clojure-online/

Veamos un pequeño ejemplito : 

(ns clojure.examples.hello

(:gen-class))


(defn sum-of-numbers [x y]

(println (format "x + y = %d" (+ x y))))


(sum-of-numbers 10 25)

Y esto retornará : x + y = 35


Dejo links : https://clojure.org/

https://www.datomic.com/

https://steemit.com/utopian-io/@laxam/programming-in-clojure-part-1-why-clojure

Tipos en Javascript

Javascript es un lenguaje de tipado dinamico, lo que no quiere decir que no tenga tipos. 

Encontre esta imagen en internet que muestra muy bien los tipos : 


Null es raro porque es primitivo y tambien es un objeto, para mi no se decidian. Pero salvo eso esta muy bien la imagen. 


sábado, 5 de diciembre de 2020

The 2020 State of the OCTOVERSE


Github libero su informe anual llamado "State of the OCTOVERSE" 

En este informe se puede encontrar cosas como, lenguajes más usados, de que parte del mundo se commitea más, cantidad de commits, etc... 

Ya hable de los lenguajes más utilizados en este post : https://emanuelpeg.blogspot.com/2020/12/top-10-de-los-lenguajes-de-programacion.html

Dejo link: https://octoverse.github.com/




Top 10 de los lenguajes de programación más populares en GitHub

 


Github liberó el resultado de una métrica que indica cual es el lenguaje más utilizado en su repositorio. Y el ganador por tercer año consecutivo es Javascript. 

El que sorprendió fue typescript, recuperándose de un 2019 no tan bondadoso. 

Y listo, no hay otras novedades...

jueves, 3 de diciembre de 2020

Distros Linux 2020


Mirando internet me encontre con un post de las mejores distros del 2020 y me gusto la lista, así que se las comparto : 

  1. Mint Cinnamon
  2. Ubuntu Budgie
  3. Deepin OS
  4. Ubuntu
  5. Manjaro
  6. Lubuntu
  7. Antergos
  8. Nitrux
  9. Elementary OS
  10. Zorin OS
  11. MX Linux

No sé si el orden es importante, pero personalmente pienso que esta buena, las 3 primeras distros las use y estan muuuyyy buenas. 

Sin más dejo link al post : 

https://computerhoy.com/listas/software/mejores-distribuciones-linux-2018-75139

Libros Gratuitos de Java Code Geeks

 

Download IT Guides!

 

Advanced Java Tutorial

Learning the basics of Java is easy. But really delving into the language and studying its more advanced concepts and nuances is what will make you a great Java developer. The web is...

 
 

Amazon AWS Lambda Tutorial

AWS Lambda is an event-driven, serverless computing platform provided by Amazon as a part of the Amazon Web Services. It is a computing service that runs code in response to events and...

 
 

JPA Tutorial - Ultimate Guide

The Java Persistence API (JPA) is a vendor independent specification for mapping Java objects to the tables of relational databases. Implementations of this specification allow...

 
 

Apache ActiveMQ Cookbook

Apache ActiveMQ is an open source message broker written in Java together with a full Java Message Service (JMS) client. It provides “Enterprise Features” which means fostering the...

 

Functional Programming in Haskell: Supercharge Your Coding


Los que siguen el blog, notaron varios post de haskell medio seguidos, todo esto es gracias a un curso de futurelearn que les quiero recomendar, el nombre es : Functional Programming in Haskell: Supercharge Your Coding. 

Es gratuito y esta realizado por la universidad de Glasgow. 

Entre los capitulos tenemos, teoría, entrevistas, casos prácticos, etc... 

Dejo link: https://www.futurelearn.com/courses/functional-programming-haskell

domingo, 29 de noviembre de 2020

Secuencia en Kotlin parte 2


Seguimos con las secuencias en Kotlin. 

Las operaciones de secuencia se pueden clasificar en los siguientes grupos con respecto a sus requisitos de estados:

  • Operaciones sin estado no requieren ningún estado y procesan cada elemento de forma independiente, por ejemplo, map () o filter (). Las operaciones sin estado también pueden requerir una pequeña cantidad constante de estado para procesar un elemento, por ejemplo, take () o drop ().
  • Operaciones con estado requieren una cantidad significativa de estado, generalmente proporcional al número de elementos en una secuencia.

Si una operación de secuencia devuelve otra secuencia, que se produce de forma perezosa, se llama intermedia. De lo contrario, la operación es terminal. Ejemplos de operaciones de terminal son toList () o sum (). Los elementos de secuencia se pueden recuperar solo con operaciones de terminal.

Las secuencias se pueden iterar varias veces; sin embargo, algunas implementaciones de secuencia pueden limitarse a repetirse una sola vez. Eso se menciona específicamente en su documentación.

Echemos un vistazo a la diferencia entre Iterable y Sequence con un ejemplo.

Suponga que tiene una lista de palabras. El siguiente código filtra las palabras de más de tres caracteres e imprime la longitud de las primeras cuatro palabras.

val words = "The quick brown fox jumps over the lazy dog".split(" ")

val lengthsList = words.filter { println("filter: $it"); it.length > 3 }

    .map { println("length: ${it.length}"); it.length }

    .take(4)

println("Lengths of first 4 words longer than 3 chars:")

println(lengthsList)

Cuando ejecute este código, verá que las funciones filter () y map () se ejecutan en el mismo orden en que aparecen en el código. Primero, verá filter: para todos los elementos, luego length: para los elementos que quedan después de filtrar, y luego la salida de las dos últimas líneas. Así es como va el procesamiento de la lista:

Ahora escribamos lo mismo con las secuencias:

val words = "The quick brown fox jumps over the lazy dog".split(" ")

//convert the List to a Sequence

val wordsSequence = words.asSequence()

val lengthsSequence = wordsSequence.filter { println("filter: $it"); it.length > 3 }

    .map { println("length: ${it.length}"); it.length }

    .take(4)

println("Lengths of first 4 words longer than 3 chars")

// terminal operation: obtaining the result as a List

println(lengthsSequence.toList())

La salida de este código muestra que las funciones filter () y map () se llaman solo cuando se genera la lista de resultados. Entonces, primero verá la línea de texto “Longitudes de ..” y luego se iniciará el procesamiento de la secuencia. Para los elementos que quedan después del filtrado, el mapa se ejecuta antes de filtrar el siguiente elemento. Cuando el tamaño del resultado llega a 4, el procesamiento se detiene porque es el tamaño más grande posible es 4 por ".take(4)"


Función Open de Python


Open abre un archivo. Bastante simple, ¿eh? La mayoría de las veces, vemos que se usa así:

f = open('photo.jpg', 'r+')

jpgdata = f.read()

f.close()

El valor de retorno de open es un identificador de archivo, dado desde el sistema operativo. 

Llamar explícitamente a close cierra el archivo, pero solo si la lectura fue exitosa. Si hay algún error justo después de f = open (...), no se llamará a f.close (). Para asegurarse de que el archivo se cierre ya sea que ocurra una excepción o no, podemos usar with:

with open('photo.jpg', 'r+') as f:

    jpgdata = f.read()

El primer argumento de abrir es el nombre del archivo. El segundo (el modo) determina cómo se abre el archivo.

Si desea leer el archivo, pase r

Si desea leer y escribir el archivo, pase r +

Si desea sobrescribir el archivo, pase w

Si desea agregar al archivo, pase a

El modo es importante no solo porque cambia el comportamiento, sino también porque puede resultar en errores de permisos. Por ejemplo, si abriéramos un archivo jpg en un directorio protegido contra escritura, abrir (.., 'r +') fallaría. El modo puede contener un carácter más; podemos abrir el archivo en binario (obtendrás una cadena de bytes) o en modo texto (una cadena de caracteres).

En general, si el formato está escrito por humanos, suele ser en modo texto. Los archivos de imagen jpg generalmente no están escritos por humanos (y de hecho no son legibles por humanos) y, por lo tanto, debe abrirlos en modo binario agregando ab a la cadena de modo (si está siguiendo el ejemplo de apertura, el modo correcto sería rb). Si abre algo en modo texto (es decir, agrega una t, o nada aparte de r / r + / w / a), también debe saber qué codificación usar. Para una computadora, todos los archivos son solo bytes, no caracteres.

Desafortunadamente, open no permite la especificación de codificación explícita en Python 2.x. Sin embargo, la función io.open está disponible tanto en Python 2.x y 3.x (donde es un alias de open) y hace lo correcto. Puede pasar la codificación con la palabra clave de codificación. Si no pasa ninguna codificación, se elegirá un sistema (y Python) predeterminado específico. Puede tener la tentación de confiar en estos valores predeterminados, pero los valores predeterminados a menudo son incorrectos o la codificación predeterminada no puede expresar todos los caracteres en el archivo (esto sucederá a menudo en Python 2.x y/o Windows). Así que adelante, elija una codificación. La codificación es la forma de instruir a las computadoras sobre cómo se deben almacenar los números como bytes en la memoria. utf-8 es excelente y es compatible con los principales navegadores y lenguajes de programación. Cuando escribe un archivo, puede elegir la codificación a su gusto (o al gusto del programa que eventualmente leerá su archivo).

¿Cómo averigua en qué codificación se escribió un archivo que está leyendo? Bueno, desafortunadamente, no existe una forma infalible de detectar la codificación: los mismos bytes pueden representar caracteres diferentes pero igualmente válidos en diferentes codificaciones. Por lo tanto, debe confiar en los metadatos (por ejemplo, en los encabezados HTTP) para conocer la codificación. Cada vez más, los formatos solo definen la codificación como UTF-8.

Armados con este conocimiento, escribamos un programa que lea un archivo, determine si es JPG (pista: estos archivos comienzan con los bytes FF D8) y escriba un archivo de texto que describa el archivo de entrada.

import io

with open('photo.jpg', 'rb') as inf:

    jpgdata = inf.read()


if jpgdata.startswith(b'\xff\xd8'):

    text = u'This is a JPEG file (%d bytes long)\n'

else:

    text = u'This is a random file (%d bytes long)\n'


with io.open('summary.txt', 'w', encoding='utf-8') as outf:

    outf.write(text % len(jpgdata))


Y listo!

sábado, 28 de noviembre de 2020

Manejo de errores en Go vs Rust parte 3

Seguimos viendo el manejo de errores en Go y Rust.

En Go, Panic es una función incorporada que detiene el flujo ordinario de control y comienza a entrar en pánico. Cuando la función F llama a Panic, la ejecución de F se detiene, cualquier función diferida en F se ejecuta normalmente y luego F vuelve a su llamador. El proceso continúa en la pila hasta que todas las funciones de la goroutine actual han regresado, momento en el que el programa se bloquea. Los pánicos se pueden iniciar invocando el Panic directamente. También pueden deberse a errores en tiempo de ejecución.

Rust tambien tiene panic! pero en este caso en una macro, cuando panic! se ejecuta, el programa imprimirá un mensaje de error y limpiará la pila y luego se cerrará. Esto ocurre más comúnmente cuando se detecta un error de algún tipo y el programa no tiene claro cómo manejar el error.

Veamos un ejemplo para ver cómo es cuando se ejecuta panic!: 

fn main() {

    let v = vec![1, 2, 3];

    v[99];

}

Aquí, estamos intentando acceder al elemento en la posición 100 de nuestro vector (que está en el índice 99 porque la indexación comienza en cero), pero solo tiene 3 elementos. En esta situación, Rust entrará en pánico. Se supone que el uso de [] devuelve un elemento, pero si pasa un índice no válido, no hay ningún elemento que Rust pueda devolver aquí que sea correcto.

En C, intentar leer más allá del final de una estructura de datos es un comportamiento indefinido. Puede obtener lo que esté en la ubicación de la memoria que corresponda a ese elemento en la estructura de datos, aunque la memoria no pertenezca a esa estructura. Esto se denomina sobrelectura del búfer y puede generar vulnerabilidades de seguridad si un atacante es capaz de manipular el índice de tal manera que lea datos que no deberían tener permitido y que se almacenan después de la estructura de datos.

Para proteger el programa de este tipo de vulnerabilidad, si intenta leer un elemento en un índice que no existe, Rust detendrá la ejecución y se negará a continuar. Probémoslo y veamos:

$ cargo run

   Compiling panic v0.1.0 (file:///projects/panic)

    Finished dev [unoptimized + debuginfo] target(s) in 0.27s

     Running `target/debug/panic`

thread 'main' panicked at 'index out of bounds: the len is 3 but the index is 99', /rustc/5e1a799842ba6ed4a57e91f7ab9435947482f7d8/src/libcore/slice/mod.rs:2806:10

note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace.


Este error apunta a un archivo que no escribimos, libcore / slice / mod.rs. Esa es la implementación de slice en el código fuente de Rust. El código que se ejecuta cuando usamos [] en nuestro vector v está en libcore / slice / mod.rs, ¡y ahí es donde entra el pánico! 

La siguiente línea de nota nos dice que podemos configurar la variable de entorno RUST_BACKTRACE para obtener un seguimiento de lo que sucedió exactamente. Un backtrace es una lista de todas las funciones que se han llamado para llegar a este punto. Los backtraces en Rust funcionan como lo hacen en otros lenguajes: la clave para leer el backtrace es comenzar desde arriba y leer hasta que veas los archivos que escribiste. Ese es el lugar donde se originó el problema. Veamos un ejemplo : 

$ RUST_BACKTRACE=1 cargo run
thread 'main' panicked at 'index out of bounds: the len is 3 but the index is 99', /rustc/5e1a799842ba6ed4a57e91f7ab9435947482f7d8/src/libcore/slice/mod.rs:2806:10
stack backtrace:
   0: backtrace::backtrace::libunwind::trace
             at /Users/runner/.cargo/registry/src/github.com-1ecc6299db9ec823/backtrace-0.3.40/src/backtrace/libunwind.rs:88
   1: backtrace::backtrace::trace_unsynchronized
             at /Users/runner/.cargo/registry/src/github.com-1ecc6299db9ec823/backtrace-0.3.40/src/backtrace/mod.rs:66
   2: std::sys_common::backtrace::_print_fmt
             at src/libstd/sys_common/backtrace.rs:84
   3: <std::sys_common::backtrace::_print::DisplayBacktrace as core::fmt::Display>::fmt
             at src/libstd/sys_common/backtrace.rs:61
   4: core::fmt::ArgumentV1::show_usize
   5: std::io::Write::write_fmt
             at src/libstd/io/mod.rs:1426
   6: std::sys_common::backtrace::_print
             at src/libstd/sys_common/backtrace.rs:65
   7: std::sys_common::backtrace::print
             at src/libstd/sys_common/backtrace.rs:50
   8: std::panicking::default_hook::{{closure}}
             at src/libstd/panicking.rs:193
   9: std::panicking::default_hook
             at src/libstd/panicking.rs:210
  10: std::panicking::rust_panic_with_hook
             at src/libstd/panicking.rs:471
  11: rust_begin_unwind
             at src/libstd/panicking.rs:375
  12: core::panicking::panic_fmt
             at src/libcore/panicking.rs:84
  13: core::panicking::panic_bounds_check
             at src/libcore/panicking.rs:62
  14: <usize as core::slice::SliceIndex<[T]>>::index
             at /rustc/5e1a799842ba6ed4a57e91f7ab9435947482f7d8/src/libcore/slice/mod.rs:2806
  15: core::slice::<impl core::ops::index::Index<I> for [T]>::index
             at /rustc/5e1a799842ba6ed4a57e91f7ab9435947482f7d8/src/libcore/slice/mod.rs:2657
  16: <alloc::vec::Vec<T> as core::ops::index::Index<I>>::index
             at /rustc/5e1a799842ba6ed4a57e91f7ab9435947482f7d8/src/liballoc/vec.rs:1871
  17: panic::main
             at src/main.rs:4
  18: std::rt::lang_start::{{closure}}
             at /rustc/5e1a799842ba6ed4a57e91f7ab9435947482f7d8/src/libstd/rt.rs:67
  19: std::rt::lang_start_internal::{{closure}}
             at src/libstd/rt.rs:52
  20: std::panicking::try::do_call
             at src/libstd/panicking.rs:292
  21: __rust_maybe_catch_panic
             at src/libpanic_unwind/lib.rs:78
  22: std::panicking::try
             at src/libstd/panicking.rs:270
  23: std::panic::catch_unwind
             at src/libstd/panic.rs:394
  24: std::rt::lang_start_internal
             at src/libstd/rt.rs:51
  25: std::rt::lang_start
             at /rustc/5e1a799842ba6ed4a57e91f7ab9435947482f7d8/src/libstd/rt.rs:67
  26: panic::main

En Go, Recover es una función incorporada que recupera el control de una goroutine en pánico. Recuperar solo es útil dentro de funciones diferidas. Durante la ejecución normal, una llamada para recuperar devolverá cero y no tendrá ningún otro efecto. Si la goroutine actual entra en pánico, una llamada para recuperar capturará el valor dado al pánico y reanudará la ejecución normal.

Aquí hay un programa de ejemplo que demuestra la mecánica del panic y el defer:

package main

import "fmt"


func main() {

    f()

    fmt.Println("Returned normally from f.")

}


func f() {

    defer func() {

        if r := recover(); r != nil {

            fmt.Println("Recovered in f", r)

        }

    }()

    fmt.Println("Calling g.")

    g(0)

    fmt.Println("Returned normally from g.")

}


func g(i int) {

    if i > 3 {

        fmt.Println("Panicking!")

        panic(fmt.Sprintf("%v", i))

    }

    defer fmt.Println("Defer in g", i)

    fmt.Println("Printing in g", i)

    g(i + 1)

}

La función g toma el int i, y entra en pánico si i es mayor que 3, o se llama a sí misma con el argumento i + 1. La función f difiere una función que llama a recuperar e imprime el valor recuperado (si no es nulo). Esto da como resultado: 

Calling g.

Printing in g 0

Printing in g 1

Printing in g 2

Printing in g 3

Panicking!

Defer in g 3

Defer in g 2

Defer in g 1

Defer in g 0

Recovered in f 4

Returned normally from f.


Si eliminamos la función diferida de f, el pánico no se recupera y alcanza la parte superior de la pila de llamadas de goroutine, terminando el programa. Este programa modificado generará:


Calling g.

Printing in g 0

Printing in g 1

Printing in g 2

Printing in g 3

Panicking!

Defer in g 3

Defer in g 2

Defer in g 1

Defer in g 0

panic: 4

panic PC=0x2a9cd8

[stack trace omitted]

La convención en las bibliotecas de Go es que incluso cuando un paquete usa panic internamente, su API externa aún presenta valores de retorno de error explícitos.


jueves, 26 de noviembre de 2020

Deno 1.5 fue liberado

 


No puede ser que no haya hablado de deno en el blog. Como se me paso...

Bueno un pequeño resumen, el creador de nodejs se canso de c++ y otras cosas que tenia node y dijo yo empiezo otro proyecto de 0 y probo Go pero no le termino de convencer, así que se paso a Rust y se enamoro, hizo un node que bautizo deno, porque lo de él era ser original. En fin deno es muy superior a node en performance (gracias a Rust) y trae otras características. por ejemplo deno permite ejecutar typescipt nativo. 

El equipo detrás del tiempo de ejecución de Deno para JavaScript y TypeScript lanzó recientemente Deno 1.5. Deno 1.5 mejoró el tiempo de empaquetado mediante el uso del compilador swc de JavaScript / TypeScript basado en Rust. Deno reduce aún más el tamaño del paquete con la agitación de árboles e implementa las API de plataforma web de alerta, confirmación y solicitud. Esto último puede permitir a los desarrolladores escribir aplicaciones interactivas simples en la terminal.

El equipo de Deno refactorizó la infraestructura del compilador TypeScript de Deno para usar swc. Este último es un compilador y paquete de JavaScript / TypeScript escrito en Rust. Swc afirma ser 20 veces más rápido que el compilador de Babel en un solo hilo, y 70 veces más rápido en un punto de referencia de cuatro núcleos. Las notas de la versión de Deno 1.5 comentaron sobre el impacto de swc en el rendimiento de la compilación de Deno.

Las nuevas habilidades de los árboles se traducen en paquetes reducidos. La nota de lanzamiento dio un ejemplo de código fuente que vio una reducción de tamaño del 35% cuando se compiló con v1.5 en lugar de v1.4.

La nueva versión de Deno implementa las API de la plataforma web para alertar, confirmar y solicitar con una semántica similar a la del navegador. Por ejemplo, en el navegador, Window.prompt muestra un cuadro de diálogo con un mensaje opcional que solicita al usuario que ingrese algún texto. En una terminal Deno, la función de solicitud solicitará de manera similar al usuario y bloqueará sincrónicamente hasta que se reciba esa entrada.

Las API mencionadas pueden permitir a los desarrolladores implementar interacciones interactivas simples en la terminal. La nota de la versión proporciona un ejemplo trivial.

Solicitar al usuario una entrada en Node.js puede requerir que los desarrolladores manipulen los flujos de E / S directamente (por ejemplo, process.stdin) o mediante una biblioteca.

La nueva versión de Deno también mejora el REPL con la adición de varias características nuevas. Las propiedades y métodos de los objetos se pueden completar dentro del REPL presionando la tecla TAB. El código puede estar resaltado en sintaxis si el terminal admite colores. El REPL ahora también admite instrucciones de espera de nivel superior.

La nota de la versión detalla características menores adicionales que son parte de la versión. Los desarrolladores interesados ​​pueden revisar la nota de la versión en línea.

Deno es un software de código abierto disponible bajo la licencia MIT. Se fomentan las contribuciones a través del Proyecto Deno y deben seguir las pautas de contribución de Deno.


Dejo link : https://deno.land/posts/v1.5

https://deno.land

lunes, 23 de noviembre de 2020

Manejo de errores en Go vs Rust Parte 2


Las segundas partes a veces son buenas como terminator 2. Por lo tanto seguimos con el manejo de errores de Go y Rust. 

En Go, una declaración defer empuja una llamada de función a una lista. La lista de llamadas guardadas se ejecuta después de que regrese la función circundante. Defer se usa comúnmente para simplificar funciones que realizan varias acciones de limpieza.

Por ejemplo, veamos una función que abre dos archivos y copia el contenido de un archivo al otro:

func CopyFile(dstName, srcName string) (written int64, err error) {

    src, err := os.Open(srcName)

    if err != nil {

        return

    }

    dst, err := os.Create(dstName)

    if err != nil {

        return

    }

    written, err = io.Copy(dst, src)

    dst.Close()

    src.Close()

    return

}

Esto funciona, pero hay un error. Si la llamada a os.Create falla, la función regresará sin cerrar el archivo fuente. Esto puede remediarse fácilmente llamando a src.Close antes de la segunda declaración de retorno, pero si la función fuera más compleja, el problema podría no ser detectado y resuelto tan fácilmente. Al introducir declaraciones diferidas, podemos asegurarnos de que los archivos siempre estén cerrados:

func CopyFile(dstName, srcName string) (written int64, err error) {

    src, err := os.Open(srcName)

    if err != nil {

        return

    }

    defer src.Close()

    dst, err := os.Create(dstName)

    if err != nil {

        return

    }

    defer dst.Close()

    return io.Copy(dst, src)

}

Las declaraciones diferidas nos permiten pensar en cerrar cada archivo justo después de abrirlo, garantizando que, independientemente del número de declaraciones devueltas en la función, los archivos se cerrarán.

El comportamiento de las declaraciones diferidas es sencillo y predecible. Hay tres reglas simples:

Los argumentos de una función diferida se evalúan cuando se evalúa la sentencia defer.

En este ejemplo, la expresión "i" se evalúa cuando se aplaza la llamada Println. La llamada diferida imprimirá "0" después de que la función regrese.

func a() {

    i := 0

    defer fmt.Println(i)

    i++

    return

}

Las llamadas a funciones diferidas se ejecutan en el orden Último en entrar, primero en salir después de que regrese la función circundante.

Esta función imprime "3210":

func b() {

    for i := 0; i < 4; i++ {

        defer fmt.Print(i)

    }

}

Las funciones diferidas pueden leer y asignar a los valores de retorno nombrados de la función de retorno.

En este ejemplo, una función diferida incrementa el valor de retorno i después de que regresa la función circundante. Por lo tanto, esta función devuelve 2:

func c() (i int) {

    defer func() { i++ }()

    return 1

}

Esto es conveniente para modificar el valor de retorno de error de una función. A mi me suena como que defer es el finaly de una expesión try-catch de Java o C++. 

Pero Rust no tiene tampoco la estructura try-catch de Java o C++ entonces ¿como podríamos simular el finally? o cerrar un archivo luego de utilidad. En realidad Rust carece de estas estructuras porque no son necesarias. Por ejemplo podemos hacer algo así : 

fn main() {

    let do_steps = || -> Result<(), MyError> {

        do_step_1()?;

        do_step_2()?;

        do_step_3()?;

        Ok(())

    };


    if let Err(_err) = do_steps() {

        println!("Failed to perform necessary steps");

    }

     runFinallyMethod(); 

}

Y listo! Bueno, vamos a seguir en proximos posts... 


jueves, 19 de noviembre de 2020

Excepciones en Python


En código que puede causar que ocurra una excepción se coloca en el bloque try y el manejo de la excepción se implementa en el bloque except. El código en el bloque except solo se ejecutará si el bloque try se encuentra con una excepción. He aquí un ejemplo sencillo:

try:

    file = open('test.txt', 'rb')

except IOError as e:

    print('An IOError occurred. {}'.format(e.args[-1]))

En el ejemplo anterior, estamos manejando solo la excepción IOError.

Podemos usar tres métodos para manejar múltiples excepciones. El primero implica poner todas las excepciones que probablemente ocurran en una tupla. Al igual que:

try:

    file = open('test.txt', 'rb')

except (IOError, EOFError) as e:

    print("An error occurred. {}".format(e.args[-1]))

Otro método consiste en manejar excepciones individuales en bloques de excepción separados. Podemos tener tantos excepto bloques como queramos. Aquí hay un ejemplo:

try:

    file = open('test.txt', 'rb')

except EOFError as e:

    print("An EOF error occurred.")

    raise e

except IOError as e:

    print("An error occurred.")

    raise e

De esta manera, si la excepción no es manejada por el primer bloque except, entonces puede ser manejada por un bloque siguiente, o ninguno en absoluto. Ahora, el último método implica atrapar TODAS las excepciones:

try:

    file = open('test.txt', 'rb')

except Exception as e:

    # Some logging if you want

    raise e

Esto puede ser útil cuando no tiene idea de las excepciones que puede generar su programa. Si solo está buscando capturar todas las ejecuciones, pero en realidad no le importa lo que son, puede incluso excluir la excepción como parte.

Nota: la captura de todas las excepciones puede tener consecuencias no deseadas porque la captura de todas las excepciones también puede detectar las que desea que ocurran; por ejemplo, en muchos programas basados ​​en la línea de comandos, presionar control + c terminará el programa, pero si detecta todas las excepciones, KeyboardInterrupt se detectará como una excepción, por lo que presionar control + c NO terminará el programa.

Envolvemos nuestro código principal en la cláusula try. Después de eso, envolvemos algún código en una cláusula except que se ejecuta si ocurre una excepción en el código envuelto en la cláusula try. En este ejemplo también usaremos una tercera cláusula que es la cláusula finally. El código que está envuelto en la cláusula finally se ejecutará tanto si se produjo una excepción como si no. Podría usarse para realizar una limpieza después de un script. He aquí un ejemplo sencillo:

try:

    file = open('test.txt', 'rb')

except IOError as e:

    print('An IOError occurred. {}'.format(e.args[-1]))

finally:

    print("This would be printed whether or not an exception occurred!")


# Output: An IOError occurred. No such file or directory

# This would be printed whether or not an exception occurred!

A menudo, es posible que deseemos que se ejecute algún código si no se produce ninguna excepción. Esto se puede lograr fácilmente utilizando una cláusula else. Uno podría preguntarse: ¿por qué, si solo desea que se ejecute algún código si no ocurre ninguna excepción, no simplemente pondría ese código dentro del intento? La respuesta es que entonces cualquier excepción en ese código será detectada por el intento, y es posible que no desee eso. La mayoría de la gente no lo usa. Aquí hay un ejemplo:

try:

    print('I am sure no exception is going to occur!')

except Exception:

    print('exception')

else:

    # any code that should only run if no exception occurs in the try,

    # but for which exceptions should NOT be caught

    print('This would only run if no exception occurs. And an error here '

          'would NOT be caught.')

finally:

    print('This would be printed in every case.')


# Output: I am sure no exception is going to occur!

# This would only run if no exception occurs. And an error here would NOT be caught

# This would be printed in every case.

La cláusula else solo se ejecutará si no se produce ninguna excepción y se ejecutará antes de la cláusula finalmente.

miércoles, 18 de noviembre de 2020

Listas, conjuntos definidos por comprensión en Python


Las comprensiones son construcciones que permiten construir secuencias a partir de otras secuencias. Se admiten varios tipos de comprensión tanto en Python 2 como en Python 3:

  • listas por comprensión
  • diccionarios por comprensión
  • conjuntos  por comprensión
  • Generadores por comprensión

Las listas por comprensión proporcionan una forma breve y concisa de crear listas. Consiste en corchetes que contienen una expresión seguida de una cláusula for, luego cero o más cláusulas for o if. Las expresiones pueden ser cualquier cosa, lo que significa que puede incluir todo tipo de objetos en listas. El resultado sería una nueva lista realizada después de la evaluación de la expresión en el contexto de las cláusulas if y for.

variable = [out_exp for out_exp in input_list if out_exp == 2]

Aquí hay un pequeño ejemplo:

multiples = [i for i in range(30) if i % 3 == 0]

print(multiples)

# Output: [0, 3, 6, 9, 12, 15, 18, 21, 24, 27]

Esto puede resultar muy útil para hacer listas rápidamente. Algunos incluso lo prefieren en lugar de la función de filtro. Las comprensiones de listas realmente brillan cuando desea proporcionar una lista a un método o función para hacer una nueva lista agregándola en cada iteración del ciclo for. Por ejemplo, normalmente haría algo como esto:

squared = []

for x in range(10):

    squared.append(x**2)

Puede simplificarlo usando listas por comprensión. Por ejemplo:

squared = [x**2 for x in range(10)]

Los diccionarios por comprensión se utilizan de forma similar. Aquí hay un ejemplo que encontré recientemente:

mcase = {'a': 10, 'b': 34, 'A': 7, 'Z': 3}

mcase_frequency = {

    k.lower(): mcase.get(k.lower(), 0) + mcase.get(k.upper(), 0)

    for k in mcase.keys()

}

# mcase_frequency == {'a': 17, 'z': 3, 'b': 34}

En el ejemplo anterior, estamos combinando los valores de las claves que son iguales pero en diferentes tipos de letra. También puede cambiar rápidamente las claves y los valores de un diccionario:

{v: k for k, v in some_dict.items()}

Los conjuntos  por comprensión también son similares a las listas por comprensión. La única diferencia es que usan llaves {}. Aquí hay un ejemplo:

squared = {x**2 for x in [1, 1, 2]}

print(squared)

# Output: {1, 4}

Los Generadores por comprensión también son similares a las listas por comprensión. La única diferencia es que no asignan memoria para toda la lista, sino que generan un elemento a la vez, por lo que la memoria es más eficiente.

multiples_gen = (i for i in range(30) if i % 3 == 0)

print(multiples_gen)

# Output: <generator object <genexpr> at 0x7fdaa8e407d8>

for x in multiples_gen:

  print(x)

  # Outputs numbers

sábado, 14 de noviembre de 2020

Maybe


Veamos la mónada Maybe, que facilita mucho el uso del tipo Maybe.

Ya conoces la definición del tipo Maybe:

    data Maybe a = Just a | Nothing

Las funciones de Head y Tail de Prelude no son seguras en el sentido de que fallan cuando se llaman en una lista vacía. Podemos definir versiones seguras usando Maybe:


    myHead :: [a] -> Maybe a

    myHead [] = Nothing

    myHead (x:xs) = Just x


    myTail :: [a] -> Maybe []

    myTail [] = Nothing

    myTail (x:xs) = Just xs


Ahora podemos hacer de Maybe una instancia de la clase de tipo Monad, simplemente proporcionando las definiciones apropiadas para return, bind, then y fail:


    import Control.Monad


    instance Monad Maybe where

        return           =   Just

        Nothing  >>= f = Nothing

        (Just x) >>= f = f x

        fail _           =   Nothing


Hay algunas funciones adicionales definidas en la clase de tipo MonadPlus:


    instance MonadPlus Maybe where

        mzero               = Nothing

        Nothing `mplus` x = x

        x `mplus` _         = x


Eso es todo, ¡ahora tenemos una mónada Maybe!

Veamos qué nos da esta mónada:

Un cálculo usando Maybe explícito

    foo :: [a] -> Maybe a

    foo xs =

      case myTail xs of

        Nothing -> Nothing

        Just a -> case myTail a of

                    Nothing -> Nothing

                    Just b -> myHead b

Para combinar cálculos que usan el tipo Maybe, necesitamos expresiones de caso explícitas para hacer coincidir el patrón con el tipo.

Escribamos este cálculo usando la mónada Maybe, primero usando el operador >> =:


    bar :: [a] -> Maybe a

    bar xs =

      myTail xs >>=

        (\a -> myTail a >>=

          (\b -> myHead b))


Ahora cambiemos un poco los saltos de línea y la sangría para que se vea mejor:


    bar2 :: [a] -> Maybe a

    bar2 xs =

      myTail xs >>= (\a ->

      myTail a >>=  (\b ->

      myHead b))


Gracias a la ley de asociatividad, también podemos eliminar los paréntesis innecesarios:


    bar3 :: [a] -> Maybe a

    bar3 xs =

      myTail xs >>= \a ->

      myTail a >>=  \b ->

      myHead b


Esto ya es mucho más limpio, pero finalmente podemos usar la notación do:


    bar3 :: [a] -> Maybe a

    bar3 xs = do

      a <- myTail xs

      b <- myTail a

      myHead b


Claramente, el código monádico final es mucho más legible que el código no monádico original.


Ejemplo: Reducción de barra [5,6]

        bar [5,6]

    -- > substitute [5,6] for xs in definition of bar

        myTail [5,6] >>=

         (\a -> myTail a >>=

          (\b -> myHead b))

    -- > def. myTail

        Just [6]  >>=

         (\a -> myTail a >>=

          (\b -> myHead b))

    -- >  def.2 of (>>=)

         (\a -> myTail a >>=

          (\b -> myHead b))

            [6]

    -- > beta reduction, substitute [6] for a

         myTail [6] >>= (\b -> myHead b)

    -- > reduce myTail

         Just [] >>=  (\b -> myHead b)

    -- >  def.2 of (>>=)   

        (\b -> myHead b) []

    -- > beta reduction, substitute [] for b

       myHead []

    -- > def.1 myHead

      Nothing


Ejemplo: Reducción de barra [5,6,7]

        bar [5,6,7]

    -> sustituir [5,6,7] por xs en la definición de bar

        bar [5,6,7]

    -- > substitute [5,6,7] for xs in definition of bar

        myTail [5,6,7] >>=

         (\a -> myTail a >>=

          (\b -> myHead b))

    -- > def. myTail

        Just [6,7]  >>=

         (\a -> myTail a >>=

          (\b -> myHead b))

    -- >  def.2 of (>>=)

         (\a -> myTail a >>=

          (\b -> myHead b))

            [6,7]

    -- > beta reduction, substitute [6,7] for a

         myTail [6,7] >>= (\b -> myHead b)

    -- > reduce myTail

         Just [7] >>=  (\b -> myHead b)

    -- >  def.2 of (>>=)   

        (\b -> myHead b) [7]

    -- > beta reduction, substitute [7] for b

        myHead [7]

    -- > def myHead

        Just 7