sábado, 4 de abril de 2026

WebAssembly con Haskell

WebAssembly es un lenguaje de bajo nivel, similar a ensamblador, diseñado para ser rápido de cargar y ejecutar en navegadores modernos. Su objetivo es permitir que aplicaciones escritas en distintos lenguajes se ejecuten en la web con velocidad casi nativa.

Los formatos que soporta son:

  • .wasm: un formato binario ejecutable. 
  • .wat: un formato formato de texto legible.

Se complementa con JavaScript; permite invocar funciones WASM desde JS y viceversa.

¿Cuál es el objetivo de WebAssembly?

El objetivo de WebAssembly es compilar código escrito en lenguajes como Rust, C o C++ (entre otros) y transformarlo en un módulo .wasm que puede ejecutarse en navegadores o en entornos como Node.js con rendimiento cercano al nativo.

Flujo típico de trabajo con WebAssembly

  1. Escribimos nuestro código en un lenguaje soportado (ej. Rust, C, C++, Go, AssemblyScript). 
  2. Compilamos ese código a WebAssembly y se generará un archivo .wasm
  3. Cargamos el módulo en tu aplicación web usando JavaScript. 
  4. Ejecutamos las funciones exportadas desde el módulo .wasm  como si fueran algo nativo.

¿Y qué con Haskell?

Existen dos alternativas en Haskell para hacer esto:

  1. Mediante las herramientas wasm32-wasi-ghc y wasm32-wasi-cabal
  2. Mediante Asterius (aunque ya se encuentra deprecado).

Usaremos Cabal para crear el código WASM.

1. Crearemos un directorio donde alojar nuestro proyecto Cabal:

$ mkdir demo-cabal-wasm
$ demo-cabal-wasm

2. Creamos el proyecto Cabal:

$ cabal init --non-interactive --package-name=hola-wasm --exe --main-is=Main.hs

La estructura del proyecto será la siguiente:

hola-wasm/
 ├─ app/
    └─ Main.hs
 ├─ hola-wasm.cabal
 └─ cabal.project

El código del programa ``Main.hs`` será el siguiente:

module Main where

main :: IO ()
main = putStrLn "Hola, mundo desde Haskell en WebAssembly!"

3. Editamos el archivo ``hola-wasm.cabal``:

cabal-version:       >=1.10
name:                hola-wasm
version:             0.1.0.0
build-type:          Simple

executable hola-wasm
  main-is:            Main.hs
  build-depends:      base >=4.14 && <4.20
  default-language:   Haskell2010

4. Compilamos a WebAssembly:

$ cabal build --with-compiler=ghc --ghc-options="--target=wasm32-wasi"

5. Si todo va bien, deberá generar un código .wasm. Ahora tendremos que crear un archivo ``main.js`` para incocar el código generado en el .wasm.

async function runWasm() {
  const response = await fetch("hola-wasm.wasm");
  const bytes = await response.arrayBuffer();
  const result = await WebAssembly.instantiate(bytes, {
    wasi_snapshot_preview1: {
      fd_write: (fd, iovs, iovs_len, nwritten, mem) => {
        console.log("Salida desde WASM (stdout simulado)");
        return 0;
      }
    }
  });

}

runWasm();

6. Crear una página HTML donde le incrustamos ese código JS.

<!DOCTYPE html>
<html lang="es">
<head>
  <meta charset="UTF-8">
  <title>Hola Haskell WASM</title>
</head>
<body>
  <h1>Ejemplo Haskell + WebAssembly</h1>
  <pre id="output"></pre>

  <script src="main.js"></script>
</body>
</html>

Ejecutamos con Python:

$ python -m http.server 8000

Abrimos el navegador en la ruta: http://localhost:8000

¡Hemos trabajado con WebAssembly desde Cabal!

Continuaremos con este tema en próximas entregas.

Enlaces:

https://alquimistadecodigo.blogspot.com/2026/04/webassembly-con-rust.html
https://webassembly.org/
https://asterius.netlify.app/
https://ghc.gitlab.haskell.org/ghc/doc/users_guide/wasm.html
https://www.tushar-adhatrao.in/blogs/haskell_to_wasm.html

domingo, 8 de marzo de 2026

Programación funcional en Haskell

Uno de los puntos fuertes de Haskell es la programación funcional pura. La cual se centra en funciones matemáticas puras, sin efectos secundarios, y en transformar datos de manera predecible.

Donde cada función es como una receta que recibe ingredientes (datos de entrada) y devuelve un resultado (salida).

Donde las funciones no alteran cosas externas (osea, sin efectos secundarios), solo trabajan con lo que reciben.

Donde los datos no cambian, se transforman en nuevos resultados.

Donde no se evalúa una expresión hasta que su resultado sea estrictamente necesario, permitiendo el manejo de estructuras de datos infinitas.

Con Haskell es como si trabajaras con fórmulas matemáticas, cada función es una operación que siempre da el mismo resultado con los mismos datos.

Incluso permitiendo que las funciones tomen a otras funciones como argumentos, o simplemente devolviendo éstas.

Es como hacer un jugo de naranja. Tomas la naranja y la exprimes, y así obtienes su jugo. Repitiendo el mismo proceso. Sin explicar ni detallar absolutamente nada.

Función jugo(naranja) -> "jugo de naranja"

Para programadores que usan Java esto puede parecer confuso. Puesto que nos llevaría una lógica muy distinta:

boolean hayNaranjas = true;

if(hayNaranjas){
   irAlaCocina();
   tomarLaNaranja();
   prepararVaso();
   exprimirNaranja();
   servirVaso();
}

Para entender mejor esto tenemos lo siguiente...

Los puntos fuertes de la programación funcional pura (en Haskell) son:

1. Las funciones puras: una función siempre devuelve el mismo resultado; no depende de variables externas ni modifica estados.

2. Inmutabilidad: no existen as mutaciones de estado, los valores no cambian.

3. Transparencia referencial: una expresión puede ser reemplazada por su valor sin alterar el comportamiento del programa.

4. Evaluación perezosa (lazy evaluation): las expresiones se evalúan solo cuando son necesarias.

5. Tipado fuerte y estático: el compilador verifica tipos en tiempo de compilación

Para entender mejor crearemos un programa que defina una función ``suma`` que sume dos números enteros (Int).

suma.hs

suma :: Int -> Int -> Int
suma x y = x + y

La función ``suma`` es pura y siempre que se invoque con los mismos argumentos, devolverá el mismo resultado. Es decir, si introduces dos números enteros, devolverá un resultado tipo entero. Quien haya asistido a la escuela primaria y llevado la materia de aritmética básica entenderá esto.

Entremos al REPL de Haskell:

$ ghci

Cargamos el programa:

ghci> :l suma.hs
[1 of 2] Compiling Main             ( suma.hs, interpreted )
Ok, one module loaded.

Introducimos dos valores tipo entero (Int) y el resultado será entero:

ghci> suma 45 32
77
ghci> suma 1 5
6

Ahora un ejemplo de evaluación perezosa con el programa ``naturales.hs``, en el cual definimos una lista infinita:

naturales :: [Int]
naturales = [1..]

primerosCinco = take 5 naturales

Cargamos el programa:

ghci> :l naturales.hs
[1 of 2] Compiling Main             ( naturales.hs, interpreted )
Ok, one module loaded.

La lista naturales es infinita, pero gracias a la evaluación perezosa podemos trabajar con ella sin problemas.

Salida:

ghci> primerosCinco
[1,2,3,4,5]

Continuaremos con este tema en próximas entregas.

Enlaces:

http://aprendehaskell.es/
https://wiki.haskell.org/index.php?title=Functional_programming

domingo, 1 de marzo de 2026

Tipos de datos en Haskell

Como hemos mencionado, Haskell es un lenguaje de programación funcional de tipado estático. ¿Qué quiere decir esto?

  • En Haskell es necesario especificar qué tipos de datos vamos a emplear en nuestros programas. 
  • Puesto que al compilar el programa (sí, Haskell se compila) se evaluarán los tipos para saber si son enteros, booleanos o cadenas de caracteres.
  • Además al tener inferencia de tipos no tenemos que especificar, por ejemplo, que un número es un número.

Comprobemos esto. Abrimos una terminal y tecleamos:

$ ghci

Esto abrirá el REPL de Haskell. Usemos el comando :type o el abreviado :t para ver los tipos de datos.

ghci> :type "Esto es una cadena"
"Esto es una cadena" :: String
ghci> :type 33
33 :: Num a => a
ghci> :type True
True :: Bool
ghci> :t 'X'
'X' :: Char
ghci> :t 23 + 32
23 + 32 :: Num a => a

En este ejemplo vemos los tipos: Char, String, Num y Bool.

Incluso aplica en las propias funciones de Haskell:

ghci> :type succ
succ :: Enum a => a -> a
ghci> :type max
max :: Ord a => a -> a -> a
ghci> :type min
min :: Ord a => a -> a -> a

Incluso nuestras propias definiciones de función:

ghci> :l factorial.hs
[1 of 2] Compiling Main             ( factorial.hs, interpreted )
Ok, one module loaded.
ghci> :type factorial
factorial :: Int -> Int

Hay más tipos de datos, incluso podrías crear los tuyos. Similar a la lógica de los typedef de C.

Para ello tenemos a data, newtype y type . Veamos unos ejemplos.

Ejemplos con data

Tipos algebraicos de datos. Permiten crear estructuras que pueden tener múltiples constructores.

data Color = Rojo | Verde | Azul

Usar Maybe para representar valores opcionales.

data Maybe a = Nothing | Just a

Los registros permiten definir tipos con campos con nombre, lo que facilita el acceso y la actualización.

data Persona = Persona { nombre :: String, edad :: Int }

Podemos crear "objetos" y acceder a sus "propiedades". Similar a lo que se hace en C con los struct.

juan = Persona { nombre = "Juan", edad = 30 }

Ejemplos con type

Con ellos puedes crear alias de tipos, útiles para dar más claridad.

type Nombre = String
type Edad = Int
type Persona = (Nombre, Edad)

Ejemplos con newtype

Útiles cuando quieres crear un tipo distinto pero basado en otro, con costo cero en tiempo de ejecución.

newtype UsuarioId = UsuarioId Int

En este caso, esto evita confusiones entre enteros que representan cosas diferentes.

Hacer uso de esto es muy útil para cuando necesitemos usar estructuras complejas, alias más legibles o datos más seguros.

Haskell tiene tipos Int e Integer para representar números enteros.

Float para los números reales en coma flotante.

Double para los números reale en coma flotante de doble precisión.

Y demás tipos útiles en nuestros programas, además de permitir nuestras propias definiciones de datos.

Vamos a crear un programa en Haskell que muestre los tipos básicos como Int, Integer, Float, Double, Char, String y Bool.

tipos_datos.hs

-- Programa en Haskell para mostrar tipos de datos básicos
main :: IO ()
main = do
    -- Int: enteros con tamaño fijo
    let xInt :: Int
        xInt = 42
    putStrLn ("Int: " ++ show xInt)

    -- Integer: enteros arbitrariamente grandes
    let xInteger :: Integer
        xInteger = 123456789012345678901234567890
    putStrLn ("Integer: " ++ show xInteger)

    -- Float: números en coma flotante de precisión simple
    let xFloat :: Float
        xFloat = 3.14159
    putStrLn ("Float: " ++ show xFloat)

    -- Double: números en coma flotante de precisión doble
    let xDouble :: Double
        xDouble = 2.718281828459045
    putStrLn ("Double: " ++ show xDouble)

    -- Char: un solo carácter
    let xChar :: Char
        xChar = 'A'
    putStrLn ("Char: " ++ show xChar)

    -- String: lista de caracteres
    let xString :: String
        xString = "Hola, Haskell!"
    putStrLn ("String: " ++ xString)

    -- Bool: valores booleanos
    let xBoolTrue :: Bool
        xBoolTrue = True
    let xBoolFalse :: Bool
        xBoolFalse = False
    putStrLn ("Bool (True): " ++ show xBoolTrue)
    putStrLn ("Bool (False): " ++ show xBoolFalse)

Entramos al REPL de Haskell:

$ ghci

Cargamos el programa y lo ejecutamos. La salida será la siguiente:

ghci> :l tipos_datos.hs
[1 of 2] Compiling Main             ( tipos_datos.hs, interpreted )
Ok, one module loaded.
ghci> main
Int: 42
Integer: 123456789012345678901234567890
Float: 3.14159
Double: 2.718281828459045
Char: 'A'
String: Hola, Haskell!
Bool (True): True
Bool (False): False

Haskell cuida que los tipos de datos sean los correctos, y esto ocurre en el tiempo de compilación. Asegurando que el programa cumpla con los criterios de definición de datos. Lo que asegura que nuestro prograa funcionará correctamente (ahí te hablan Python).

Enlaces:

https://wiki.haskell.org/index.php?title=Type
https://serokell.io/blog/kinds-and-hkts-in-haskell

lunes, 2 de febrero de 2026

Cabal en otro vistazo

Como vimos en una entrega anterior, Cabal es la herramienta estándar para gestionar dependencias, compilar y empaquetar proyectos Haskell, lo que te permite organizar y distribuir tu código de manera profesional.

Con Haskell (y Cabal) podemos desarrollar desde pequeñas utilidades de línea de comandos hasta aplicaciones web, bibliotecas científicas, proyectos de análisis de datos y compiladores.

Recapitulando:

  • Cabal es el sistema de construcción y empaquetado de Haskell. 
  • Se basa en archivos .cabal que describen el proyecto: nombre, dependencias, módulos, ejecutables, etc. 
  • Permite compilar, instalar y distribuir bibliotecas y programas de forma portable. 
  • Es el equivalente a package.json en Node.js o pom.xml en Maven.

Conversión de grados Celsius a Fahrenheit con Haskell (y Cabal)

Crearemos una sencilla calculadora de conversión de grados Celsius a Fahrenheit. El único dato necesario serán los grados en Celsius.

1. Mostramos la versión instalada de Cabal:

$ cabal --version

2. Creamos directorio y nos ubicamos en el mismo:

$ mkdir conversion_celsius && cd conversion_celsius 

3. Creamos el proyecto:

$ cabal update && cabal init

Una vez creado el proyecto podemos comenzar a crear la funcionalidad.

La fórmula para la conversión de grados Celsius a Fahrenhei es la siguiente:

F = 1.8*C + 32

Donde C son los grados Celsius.

Para definir una función en Haskell tomemos esta sintaxis:

nombreFunc :: TipoVar1 -> TipoVar2 -> TipoVarN

Por lo que la función quedaría de la siguiente manera:

conversionFahr :: Float -> Float

Editemos el programa Main.hs:

module Main where

-- Función que convierte grados Celsius a Fahrenheit
conversionFahr :: Float -> Float
conversionFahr c = 1.8 * c + 32

main :: IO ()
main = do
    putStrLn "Conversión grados Celsius a Fahrenheit en Haskell!"
    let gradoCels = 90.0
    let gradoFahr = conversionFahr gradoCels
    putStrLn ("Grados Celsius: " ++ show gradoCels)
    putStrLn ("Grados Fahrenheit: " ++ show gradoFahr)

Ejecutemos el programa:

$ cabal run

Salida:

Conversión grados Celsius a Fahrenheit en Haskell!
Grados Celsius: 90.0
Grados Fahrenheit: 194.0

Este programa no recibe datos desde teclado, editemos el programa para que pueda hacerlo.

module Main where

-- Función que convierte grados Celsius a Fahrenheit
conversionFahr :: Float -> Float
conversionFahr c = 1.8 * c + 32

main :: IO ()
main = do
    putStrLn "Conversor de Celsius a Fahrenheit"
    putStrLn "Ingresa la temperatura en grados Celsius:"
    input <- getLine
    let gradoCels = read input :: Float
    let gradoFahr = conversionFahr gradoCels
    putStrLn ("Grados Celsius: " ++ show gradoCels)
    putStrLn ("Grados Fahrenheit: " ++ show gradoFahr)

Ejecutemos el programa:

$ cabal run

Salida:

Conversor de Celsius a Fahrenheit
Ingresa la temperatura en grados Celsius:
60.4
Grados Celsius: 60.4
Grados Fahrenheit: 140.72

¡Hemos creado un proyecto con Haskell y Cabal!

Continuaremos con estas entregas sobre Haskell.

Enlaces:

https://www.haskell.org/cabal/
https://www.servant.dev/

sábado, 4 de octubre de 2025

Aprende Haskell por el bien de todos (libro online)

Para quienes quieran aprender Haskell y no sepan dónde buscar, hay un sitio imperdible que debes visitar: http://aprendehaskell.es/

Se empieza con saber de qué trata el lenguaje, su paradigma, qué herramientas instalar, además de muchos ejemplos. Desde los tipos de datos (Haskell es de tipado fuerte), la sintaxis básica de una función, declaración de variables, estructuras, etc.

El sitio ideal para los principiantes.

Enlaces:

http://aprendehaskell.es/

domingo, 28 de septiembre de 2025

Cabal

Cabal es un conjunto de herramientas para proyectos Haskell.

Nos ayuda a crear y empaquetar bibliotecas y programas de Haskell. Define una interfaz común para que los creadores y distribuidores de paquetes creen fácilmente sus aplicaciones de forma portable. Forma parte de una infraestructura más amplia para distribuir, organizar y catalogar bibliotecas y programas de Haskell.

Instalando Cabal en Windows:

$ Set-ExecutionPolicy Bypass -Scope Process -Force;[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; try { & ([ScriptBlock]::Create((Invoke-WebRequest https://www.haskell.org/ghcup/sh/bootstrap-haskell.ps1 -UseBasicParsing))) -Interactive -DisableCurl } catch { Write-Error $_ }

Verificando la instalación:

$ cabal --version

Instalación en Linux:

$ curl --proto '=https' --tlsv1.2 -sSf https://get-ghcup.haskell.org | sh

$ source ~/.bashrc
$ ghcup install cabal latest
$ cabal update

Verificando la instalación:

$ cabal --version

Creando un proyecto con Cabal:

$ mkdir miproyecto && cd miproyecto
$ cabal update && cabal init
$ cabal run

En caso de algún error debemos modificar el archivo ``miproyecto.cabal``, debe quedar de la siguiente forma:

   -- build-depends:    base ^>=4.18.3.0
   build-depends: base >= 4.18 && < 4.20

Una vez hecho y guardado el archivo procedemos a actualizar, construir y ejecutar el proyecto, pero antes echemos un vistazo al programa ``Main.hs``:

module Main where

main :: IO ()
main = putStrLn "Hola,mundo en Haskell!"

Ahora si:

$ cabal update
$ cabal build
$ cabal run

Salida:

Hola,mundo en Haskell!

Si necesitas actualizar la versión de ghc, teclea esto:

$ ghcup install ghc 9.6.3
$ ghcup set ghc 9.6.3

Hemos instalado Cabal y creado nuestro primer programa.

Enlaces:

https://www.haskell.org/cabal/
https://cabal.readthedocs.io/en/stable/getting-started.html#installing-cabal
https://www.haskell.org/ghc/
https://www.cs.us.es/~fsancho/Blog/posts/Haskell_el_lenguaje_funcional.md

lunes, 22 de septiembre de 2025

Hola, mundo en Haskell

Haskell es un lenguaje de programación funcional cuyas características fundamentales son:

  • Existencia de variables inmutables. 
  • El estado mutable solo se puede mediante monads
  • Pureza por default (los efectos secundarios es mediante monads). 
  • Evaluación perezosa (lazy): los resultados solo se calculan si es necesario. 
  • En Haskell todo es una expresión
  • Funciones de primera clase: las funciones pueden definirse en cualquier lugar; pasarse como argumentos y devolverse como valores. 
  • Implementaciones compiladas e interpretadas disponibles. 
  • Inferencia de tipos completa: las declaraciones de tipo son opcionales. 
  • Coincidencia de patrones (pattern matching) en estructuras de datos: son de primera clase. 
  • Polimorfismo paramétrico.

Con Haskell nos olvidamos de la declaración de tipos, pero si hay tipos y son:

  • Bool. 
  • Char. 
  • String. 
  • Integer o Int. 
  • Float. 
  • Double. 
  • Num.

Veamos el clásico programa "Hola, mundo" en Haskell.

holamundo.hs

main = putStrLn "¡Hola, mundo en Haskell!"

Para poder compilarlo y ejecutarlo debemos tener Haskell instalado en nuestras máquinas: https://www.haskell.org/downloads/

Una vez instalado abrimos una terminal y tecleamos:

$ ghc --version

Ya podremos compilar nuestro programa:

$ ghc holamundo.hs

Nos creará un ejecutable:

$ holamundo.exe

Salida:

¡Hola, mundo en Haskell!

Si solo quieres ejecutar sin tener que compilar puedes usar ``runghc``:

$ runghc holamundo.hs

Hemos aprendido como compilar y ejecutar un programa en Haskell. Además de sus fundamentos.

Enlaces:

https://typeclasses.com/
https://www.reddit.com/r/haskell/comments/10jw67n/please_explain_monads_to_me_like_im_12/
https://wiki.haskell.org/All_About_Monads
https://haskellbook.com/
https://www.haskell.org/
https://cabal.readthedocs.io/en/stable/
https://www.haskell.org/ghc/
https://docs.haskellstack.org/en/stable/
https://github.com/haskell/haskell-language-server

WebAssembly con Haskell

WebAssembly es un lenguaje de bajo nivel, similar a ensamblador, diseñado para ser rápido de cargar y ejecutar en navegadores modernos. ...