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

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