Translate

domingo, 31 de mayo de 2020

Crear un árbol binario con Haskell


En informática, los árboles crecen al revés. La raíz única está en la parte superior, y las hojas están en la parte inferior. En realidad depende como se lo vea. 

El árbol binario se usa a menudo para almacenar datos ordenados, para permitir una búsqueda eficiente, por ejemplo, un directorio telefónico.

Vamos a definir un tipo de datos Haskell para árboles, almacenando valores enteros.

data Tree = Leaf | Node Int Tree Tree deriving Show

Un valor de árbol puede ser una hoja o un nodo. Tenga en cuenta que este es un tipo de datos recursivo, ya que un Nodo almacena un árbol de enteros y tiene ramificaciones a dos subárboles (a veces llamados hijos). Como se ve definimos que un árbol es una hoja o un nodo con el dato y dos arboles. 

Aquí está el árbol más simple: es solo una hoja.

Leaf

Aquí hay un árbol con un Nodo que contiene el valor 3 y dos hojas.

Node 3 Leaf Leaf

Si escribe esto en ghci, verá los valores devueltos cuando construya estos árboles, siempre que su tipo de datos Tree derive la clase Show type.

El tipo de este valor es:

let l = Node 3 Leaf Leaf
:t l

El tipo del nodo constructor:

:t Node

Esta es una función: el nodo constructor toma tres argumentos y devuelve un resultado de árbol.

Ahora escribamos una función para calcular la profundidad de un árbol: esta es la cantidad máxima de ramas desde la raíz hasta cualquier hoja. Para escribir esta función, haremos coincidir patrones en los diferentes tipos de árbol, es decir, valores de hoja y nodo. Cada hoja es un caso base, pero para cada nodo, necesitamos procesar recursivamente los dos árboles secundarios.

treeDepth :: Tree -> Int
treeDepth Leaf = 0
treeDepth (Node _ leftSubtree rightSubtree) = 
  1 + max (treeDepth leftSubtree) (treeDepth rightSubtree)

Observe el _ en la línea 3, que es un valor de "don’t care" o "no me importa", ya que descartamos el entero en cada nodo.

¿Qué tal una función para verificar si un árbol está ordenado correctamente? La estructura de datos invariable que queremos es que, para cualquier valor de almacenamiento de Nodo x, todos los valores en su subárbol izquierdo sean <x, y todos los valores en su subárbol derecho sean> = x.

Entonces, esta función tomará un Árbol, un valor mínimo, un valor máximo y devolverá un Bool. isSortedTree :: Árbol -> Int -> Int -> Bool

Una hoja se ordena automáticamente, ya que no contiene un valor. Para cada nodo, tenemos que verificar que el valor entre los valores mínimo y máximo, que comienzan lo más lejos posible, luego se dividen en rangos más pequeños según el valor en el nodo.

isSortedTree :: Tree -> Int -> Int -> Bool
isSortedTree Leaf _ _ = True
isSortedTree (Node x leftSubtree rightSubtree) minVal maxVal =
    let leftSorted   = isSortedTree leftSubtree minVal x
        rightSorted = isSortedTree rightSubtree x maxVal
    in x >= minVal && x< maxVal && leftSorted && rightSorted

Hasta ahora, hemos estudiado las funciones de recorrido del árbol, donde revisamos la estructura de datos del árbol y hacemos algunos cálculos incrementales en cada nodo. Ahora queremos hacer una función de modificación del árbol. Esto genera un nuevo árbol que es una versión modificada del árbol de entrada.

La función particular que vamos a definir inserta un nuevo valor máximo. Pasamos por el árbol de entrada hasta encontrar el nodo de la derecha con una hoja a la derecha, luego reemplazamos esta hoja de la derecha con un nuevo nodo que contiene un nuevo valor máximo (uno más grande que el valor máximo anterior).

addNewMax :: Tree -> Tree
-- add a new max element to tree
addNewMax Leaf = Node 0 Leaf Leaf  -- input tree with no nodes
addNewMax (Node x t1 Leaf) = Node x t1 (Node (x+1) Leaf Leaf)  -- this is the rightmost Node
addNewMax (Node x t1 t2) = Node x t1 (addNewMax t2) -- intermediate node, go down right subtree

Esta función addNewMax toma un valor de entrada de árbol y devuelve un valor de salida de árbol. 

sábado, 30 de mayo de 2020

Inscripción gratuita a MongoDB.live

Me llego el siguiente mail de la gente de MongoDB para anotarme a Mongo.live un evento gratuito donde podes aprender sobre esta gran base de datos NoSql :

Únanse el 9 y 10 de junio* a MongoDB.live para profundizar en el contenido educativo y conocer las nuevas tecnologías. Aprenderá de los expertos en MongoDB para resolver desafíos y adelantarse a la competencia.

En MongoDB.live podrás:
  • Personalizar tu experiencia con sesiones centradas en temas como arquitectura de aplicaciones, rendimiento de consultas, modelo de datos, diseño de esquemas, análisis, seguridad, microservicios, migración a la nube y más.
  • Aprender de los clientes de MongoDB en todos los sectores sobre las herramientas y características que están utilizando para aumentar la agilidad de su organización y la productividad de sus equipos de desarrollo.
  • ¡Participar durante la conferencia para ganar puntos de actividad y competir con otros asistentes para ganar premios!
Después de asistir, estará equipado con los conocimientos esenciales para crear y administrar aplicaciones basadas en datos. ¡Esperamos verte ahí!


* MongoDB.live comenzará a las 10:00 a.m. ET el 9 de junio y se extenderá hasta el 10 de junio a las 4:00 p.m. ET.

jueves, 21 de mayo de 2020

Libros Gratuitos de Java Code Geek

Download IT Guides!

 

Vaadin Programming Cookbook

Vaadin is an open source web framework for rich Internet applications. In contrast to JavaScript libraries and browser-plugin based solutions, it features a server-side architecture,...

 
 

GWT Programming Cookbook

Google Web Toolkit, or GWT Web Toolkit, is an open source set of tools that allows web developers to create and maintain complex JavaScript front-end applications in Java. Other than a...

 
 

Amazon Elastic Beanstalk Tutorial

AWS Elastic Beanstalk is an orchestration service offered from Amazon Web Services for deploying infrastructure which orchestrates various AWS services, including EC2, S3, Simple...

 
 

Hibernate Tutorial

Hibernate ORM (Hibernate in short) is an object-relational mapping framework, facilitating the conversion of an object-oriented domain model to a traditional relational database....

 

miércoles, 20 de mayo de 2020

Revolution.OS.2001

Quiero recomendarles un buen documental para pasar la pandemia : 



y de yapa:

martes, 19 de mayo de 2020

Design patterns



Quiero recomendar una pagina de patrones de diseño que esta buenisima, trae una descripción de casi todos los patrones con ejemplos y código. El codigo esta en deferentes lenguajes. 


lunes, 18 de mayo de 2020

Juego de Serie en C# con .net core


Cuando quiero aprender un nuevo lenguaje desarrollo un juego de series, es decir aparece una serie con un valor faltante y el jugador debe completarlo.

Uno de los requerimientos no funcionales es que se pueda agregar una serie nueva fácilmente, para cumplirlo vamos a utilizar las ventajas de herencia y polimorfismo.

Vamos a desarrollar este juego en C# para ello creamos el proyecto con : 
$ dotnet new console -lang C#

Luego de esto abrimos nuestro editor favorito, podemos utilizar visual code.  

Empecemos desarrollo de la serie, la serie tiene como responsabilidad generarse y si lo hacemos de esta manera podemos utilizar la potencia del polimorfismo, para que no quede acoplado la generación de la serie con el desarrollo del juego:

using System;
namespace dotNetSecuencia.model
{
    public abstract class Secuencia
    {
        protected int[] nros = new int[4];

        public Secuencia() {
            this.generar();
        }

        public int[] Nro {
            get {
                return nros;
            }
        }
        
        public abstract void generar();
    }
}

Ahora vamos a ver las implementaciones de secuencia:

using System;

namespace dotNetSecuencia.model
{
    public class SecuenciaPar : Secuencia
    {        
        public override void generar() {
            int semilla = new Random ().Next (99) * 2;
            for (int i = 0; i<4; i++) {
                this.nros[i] = (semilla + i * 2); 
            }
        }
    }
}

Y ahora la secuencia Impar: 

using System;

namespace dotNetSecuencia.model
{
    public class SecuenciaImpar : Secuencia
    {
        public override void generar() {
            int semilla = new Random ().Next (99) * 2;
            for (int i = 0; i<4; i++) {
                this.nros[i] = (semilla + i * 2) + 1; 
            }
        }
    }
}

Y ahora la secuencia Fibonacci :

using System;

namespace dotNetSecuencia.model
{
    public class SecuenciaFibonacci : Secuencia
    {
        public override void generar() {
            int until = new Random ().Next (15);
            this.nros[0] = 0;
            this.nros[1] = 1;
            this.nros[2] = 1;
            this.nros[3] = 2;
            for (int i = 0; i<until; i++) {
                 this.nros[0] = this.nros[1];
                 this.nros[1] = this.nros[2];
                 this.nros[2] = this.nros[3];
                 this.nros[3] = this.nros[1] + this.nros[2];
            }
        }
    }
}

Ahora vamos a ver el juego, este tiene la responsabilidad de verificar si el usuario acertó y tambien debe llevar los puntos: 

 using System;

namespace dotNetSecuencia.model
{
    public class Juego
    {
        private int puntaje = 0;
        private Secuencia secuencia = null;

        public Juego() 
        {
            this.generarSecuencia();
        }

        public int Nro1 {
            get {
                return this.secuencia.Nro[0];
            }
        }

        public int Nro2 {
            get {
                return this.secuencia.Nro[1];
            }
        }

        public int Nro4 {
            get {
                return this.secuencia.Nro[3];
            }
        }

        public int Puntaje {
            get {
                return this.puntaje;
            }
        }

        public void generarSecuencia() 
        {
            int semilla = new Random ().Next (3);
            switch (semilla)
            {
                case 0 :
                    this.secuencia = new SecuenciaPar(); 
                break;
                case 1 :
                    this.secuencia = new SecuenciaImpar(); 
                break;
                default:
                    this.secuencia = new SecuenciaFibonacci();
                break;
            }
        }

        public bool isOk(int valor) {
            bool result = false;
            if (this.secuencia.Nro[2] == valor) {
                this.puntaje++;
                result = true;
            } else {
                this.puntaje--;
            }
            this.generarSecuencia();
            return result;
        }
    }

}

Ahora programemos la interfaz por consola por supuesto : 

using System;
using dotNetSecuencia.model;
namespace dotNetSecuencia
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Bienvenido !!");
            Juego juego = new Juego();
            String respuestaStr;
            do {
                Console.WriteLine("La secuencia es : ");
                Console.WriteLine(" " + juego.Nro1 + " " + juego.Nro2 + "  __  " + juego.Nro4 );
                respuestaStr = Console.ReadLine();
                int respuesta = Convert.ToInt32(respuestaStr);
                if (juego.isOk(respuesta)) {
                    Console.WriteLine("Ganaste!! Tu puntaje es " + juego.Puntaje);
                } else {
                    Console.WriteLine("Perdiste!! Tu puntaje es " + juego.Puntaje);
                }
                Console.WriteLine("Quieres seguir Jugando [n/s] ? ");
                respuestaStr = Console.ReadLine();
            } while (respuestaStr != "n");
        }
    }
}

Y eso es todo!!! a jugar se a dicho!!

Dejo el repositorio git: 

sábado, 16 de mayo de 2020

Coconut, programación funcional simple, elegante en python



Coconut es un lenguaje de programación funcional que compila a Python. Como todo codigo válido en Python es válido en Coconut , el uso de Coconut solo extenderá y mejorará lo que ya es capaz de hacer en Python.

¿Por qué usar Coconut? Coconut está hecho para ser útil. Coconut mejora el repertorio de los programadores de Python para incluir las herramientas de la programación funcional moderna, de tal manera que esas herramientas sean fáciles de usar e inmensamente poderosas; es decir, Coconut hace a la programación funcional lo que Python hizo a la programación imperativa. Y el código Coconut se ejecuta igual en cualquier versión de Python.

Instalar Coconut es tan fácil como

instalando Python,
abriendo una línea de comandos,
y escribir:

pip install coconut

Veamos un poco de código: 

Un "hola mundo" : 

"hello, world!" |> print

lambdas:

x -> x ** 2

pattern-matching:

match [head] + tail in [0, 1, 2, 3]:
    print(head, tail)

composición de funciones: 

(f..g..h)(x, y, z)

Data types: 

data Empty()
data Leaf(n)
data Node(l, r)

def size(Empty()) = 0
addpattern def size(Leaf(n)) = 1
addpattern def size(Node(l, r)) = size(l) + size(r)

Sin, más dejo link: 
http://coconut-lang.org/

Funciones recursivas en listas parte 2


Si deseamos realizar una operación en cada elemento de una lista map es la función indicada. map aplica una función a cada elemento de una lista

map f [x0,x1,x2] -- > [f x0, f x1, f x2]

map es una de las herramientas más utilizadas en programación funcional. Un estilo común es definir un conjunto de cálculos simples usando el map y componerlos.

map f (map g xs) = map (f . g) xs

Map se puede definir de esta manera: 

map :: (a -> b) -> [a] -> [b]
map _ []     = []
map f (x:xs) = f x : map f xs

Una iteración sobre una lista para producir un valor se llama pliegue y existen varias variaciones: plegado desde la izquierda, plegado desde la derecha y varias variaciones que tienen que ver con la "inicialización" y algunas variaciones más avanzadas.

Los pliegues pueden parecer difíciles al principio, pero son extremadamente poderosos y se usan mucho. Y en realidad no son muy complicados.

foldl se pliega desde la izquierda y ed como una iteración en una lista, de izquierda a derecha.

Una aplicación típica es por ejemplo, foldl f z xs
Donde z es un valor inicial
El argumento xs :: [a] es una lista de valores que combinamos sistemáticamente utilizando la función proporcionada f
Una intuición útil: piense en el argumento z :: b como un "acumulador".
La función f toma el valor actual del acumulador y un elemento de lista, y da el nuevo valor del acumulador.

foldl :: (b-> a-> b) -> b -> [a] -> b

Similar a foldl, pero funciona de derecha a izquierda

foldr :: (a -> b -> b) -> b -> [a] -> b


Hemos visto que una lista [x0, x1, x2] también se puede escribir como
    x0: x1: x2: []

cons (:) sobre una lista usando la lista vacía [] como el acumulador da:

foldr (:) [] [x0, x1, x2]
  ->
  x0: x1: x2: []
¡Esto es idéntico a construir la lista usando (:) y []! Podemos formalizar esta relación de la siguiente manera:

foldr cons [] xs = xs
 
Veamos algunos ejemplos: 

suma xs = foldr (+) 0 xs
producto xs = foldr (*) 1 xs

De hecho, podemos "factorizar" las x que aparecen a la derecha de cada lado de la ecuación, y escribir:

sum = foldr (+) 0
producto = foldr (*) 1

(Esto a veces se denomina estilo "point free" porque está programando únicamente con las funciones; los datos no se mencionan directamente).


viernes, 15 de mayo de 2020

Programación explicada con música



Funciones recursivas en listas

Hay dos enfoques para trabajar con listas:
  • Escribir funciones utilizando definiciones recursivas que atraviesan la estructura de la lista.
  • Utilizar funciones estandar. 
Se prefiere el segundo enfoque, pero las funciones estándar de procesamiento de listas deben definirse, y esas definiciones usan el primer enfoque (definiciones recursivas).

Se crea una lista a partir de la lista vacía [] y la función cons :: a → [a] → [a] la cual se puede escribir con ":"

Una lista se puede definir como : 
  • [] o
  • (x: xs) para algunas x (el encabezado de la lista) y xs (la cola) donde (x: xs) 
La lista esta definida de forma recursiva, el caso base de la recursión es [], el caso de recursión (o inducción) es (x: xs).

La longitud de una lista se puede calcular de forma recursiva de la siguiente manera:

length :: [a] -> Int           -- function type
length [] = 0                  -- base case
length (x:xs) = 1 + length xs  -- recursion case

filter recibe un predicado (una función que da un resultado booleano) y una lista, y devuelve una lista de los elementos que satisfacen el predicado.
filter :: (a->Bool) -> [a] -> [a]

filter (<5) [3,9,2,12,6,4] -- > [3,2,4]

La podemos definir así:

filter :: (a -> Bool) -> [a] -> [a]
filter pred []    = []
filter pred (x:xs)
  | pred x         = x : filter pred xs
  | otherwise      = filter pred xs

Muchos cálculos que serían calculados con bucles for / while en un lenguaje imperativo se expresan naturalmente como cálculos de lista en un lenguaje funcional.

En Haskell tenemos: 
  • Map : Realizar un cálculo en cada elemento de una lista
  • Foldl: Iterar sobre una lista, de izquierda a derecha 
  • Foldr: Iterar sobre una lista, de derecha a izquierda

Es una buena práctica usar estas tres funciones cuando corresponda

Podemos expresar un gran cálculo "encadenando" una secuencia de funciones que realizan cálculos más pequeños. Por ejemplo tenemos un argumento de tipo a, aplicamos una función g :: a−> b, obteniendo un resultado intermedio de tipo b luego aplicamos una función f :: b−> c al resultado intermedio, obteniendo el resultado final de tipo c. El cómputo completo (primero g, luego f) se escribe como f∘g. Esta es la notación matemática tradicional; solo recuerda que en f∘g, las funciones se usan en orden de derecha a izquierda.

Haskell utiliza el . como operador de composición de funciones

(.) :: (b->c) -> (a->b) -> a -> c
(f . g) x = f (g x)


lunes, 11 de mayo de 2020

Tutorial de Python, Guía básica de Python en español


Quiero compartir una página que nos permite aprender python de forma fácil y práctica. 

Reza la página: 

"Este tutorial de Python es una introducción a los principales aspectos y características del lenguaje. El tutorial sirve de guía de inicio para dar los primeros pasos con Python, familiarizarse con su sintaxis, conocer los principales tipos de datos y entender algunos conceptos clave.

¿Para quién es este tutorial Python?
En principio, el tutorial es apto para todos los públicos. Si nunca has programado en Python, te servirá para aprender lo básico del lenguaje. Por el contrario, si ya lo conoces y/o has desarrollado alguna aplicación con él, te será útil para reforzar conceptos y descubrir cosas nuevas que quizá desconozcas."

domingo, 10 de mayo de 2020

HumanOS


HumanOS es un blog de software libre. Tiene post sobre temas de variados de diferentes temas y el propósito de este blog es mostrarle a las personas cuales son los provechos que se les puede sacar al software libre

Dejo link:
http://humanos.uci.cu/

Juego de adivinanzas en Haskell

Vamos a ser un juego de adivinanzas. Va a haber una palabra que el jugador debe adivinar. Para cada turno del juego, el jugador adivina una sola letra. Si esa letra es correcta, las letras adivinadas se muestran en los lugares correctos de la palabra. Si esa letra es incorrecta, el usuario pierde una estrella. Una vez que el usuario no tiene estrellas, ha perdido el juego. Sin embargo, si el usuario adivina todas las letras de la palabra, ha ganado el juego, como el ahorcado.

Comience creando un archivo de texto vacío llamado ahorcado.hs: la extensión hs es para indicar que este archivo contiene el código fuente de Haskell.


El corazón del juego consiste en verificar las conjeturas del jugador. Queremos saber si la suposición fue correcta. Este resultado es un valor Bool, ya sea verdadero o falso. Necesitamos actualizar la palabra mostrada, si la suposición fue correcta, reemplazando los guiones apropiados en la palabra mostrada con el carácter correctamente adivinado. Por lo tanto, el tipo de resultado de la función es un par (Bool, String). El primer elemento del par es el resultado de la suposición. El segundo elemento es la Cadena que se mostrará al usuario para la próxima ronda.

Ahora, la función de verificación necesita saber:
  • La palabra secreta, una cadena
  • La palabra que se muestra en pantalla o real, también una cadena
  • El carácter elegido por el jugador.
Estas son las entradas a la función de verificación. Entonces ahora podemos establecer el tipo de la función:

check :: String -> String -> Char -> (Bool, String)

Siempre es útil determinar primero el tipo de función. Esto enfoca su atención en lo que se supone que debe calcular la función, y qué datos necesita para hacerlo. Los buenos ingenieros de software hacen las especificaciones antes de la implementación.

¿Cómo será el cuerpo de la función de verificación? La suposición del jugador es correcta si y solo si el carácter elegido c está en la palabra secreta. Entonces la suposición es correcta si :

c palabra `elem`

La nueva palabra que se mostrará será:

[(if x==c then c else y) | (x,y) <- zip word display]

Esta es una lista de comprensión, donde seleccionamos cada letra de la palabra real o de la pantalla anterior. La palabra es texto sin formato, mientras que la pantalla comienza con todos los caracteres discontinuos.

check :: String -> String -> Char -> (Bool, String)
check word display c
  = (c `elem` word, [if x==c
          then c
          else y | (x,y) <- zip word display])

La siguiente función que definiremos es la función de giro. Esta es la función que se llamará cada vez que sea el turno del jugador para ingresar un caracter. Primero debemos comprobar cuántas conjeturas le quedan al jugador:

if n == 0

Si quedan algunas conjeturas, entonces necesitamos ver si el jugador completo la palabra o no:

if word == display

Entonces tendremos dos verificaciones if, cada una seguida de mensajes de estado putStrLn y el final de la secuencia de llamada a la función (ya que es el final del juego). Sin embargo, si ninguna de las condiciones es verdadera, entonces el jugador puede tomar un turno, por lo que llamamos a otra función para obtener otro personaje de la entrada del usuario.

turn :: String -> String -> Int -> IO ()
turn word display n =
  do if n==0
       then putStrLn "You lose"
       else if word==display
              then putStrLn "You win!"
              else mkguess word display n

Tenga en cuenta que hay una forma más ordenada de escribir la función de giro, utilizando Haskell guards, pero no vamos a utilizarlas para simplificar el programa.

mkguess word display n =
  do putStrLn (display ++ "  " ++ take n (repeat '*'))
     putStr "  Enter your guess: "
     q <- getLine
     let (correct, display') = check word display (q!!0)
     let n' = if correct then n else n-1
     turn word display' n'

¿Cuál es el tipo de mkguess? ¿Puedes resolverlo y agregarlo antes de la definición de la función? Tomamos una línea de entrada del usuario, pero solo usamos el primer carácter para la suposición. Esto fallará si el usuario simplemente presiona ENTER sin escribir ningún carácter, ya que q será una cadena vacía.

Bien, ahora solo necesitamos una función de nivel superior:

starman :: String -> Int -> IO ()
starman word n = turn word ['-' | x <- word] n

Esta función toma dos argumentos, el primero es la palabra a adivinar y el segundo es el número de conjeturas incorrectas que el jugador tiene permitido.

Pongamos todas estas cuatro funciones en un archivo de texto, llamado starman.hs

Guarde el archivo, luego inicie ghci quizás escribiendo ghci en un símbolo del sistema de DOS, ejecutando WinGHCi o escribiendo ghci en una ventana de terminal (macOS o Linux).

Si está en el directorio correcto, es decir, en el que guardó starman.hs, debería poder escribir

:l starman.hs

y el programa debería cargarse. Dirá algo como:

Prelude> :l ahorcado.hs
[1 of 1] Compiling Main             ( ahorcado.hs, interpreted )
Ok, one module loaded.

Starman "funcionalmente" 5

y comienza a jugar el juego! Volverá a la solicitud de GHCi cuando se complete la función starman.

Y Listo!!

miércoles, 6 de mayo de 2020

martes, 5 de mayo de 2020

Swift es como Kotlin


Quiero compartir una pagina que compara Swift con Kotlin.

Lo comparto porque hasta esta pagina, no me parecían similares pero son igualitos :D

Dejo link: http://nilhcem.com/swift-is-like-kotlin/