Read Only Memories

Let me annoy you in inglés and español.

Desde Debian 11 hacia Debian 12: LDAP

Actualizar Debian entre versiones estables usualmente es un paseo, excepto cuando no lo es. Leer los Release Notes completamente y con intención, ahorra tiempo -- después de todo, fueron escritas por personas que saben mucho más que uno, y que de verdad hicieron el trabajo.

El directorio LDAP suele ser el sustrato de muchas instalaciones de servicios AAA y correo electrónico. Si esa actualización falla, el servicio también. Este es uno de los pocos servicios que no son triviales de actualizar de manera automática.

¿Qué podría salir mal?

Advent of Code 2022 -- Day 14

This challenge felt like «busy work» more than «creative work». It boils down to keeping track of a grid's occupied positions, until a particle goes out of bounds or there's no room for more particles under the rules.

As usual for «grid-centric» problem solving in Haskell, is better to use a Map to focus on occupied positions. After defining a custom Ord instance to sort things the way I needed, it was mostly «busy work».

The simulation turned out adequate to illustrate why unfoldr matters, specially when you fuse into an hylomorphism...

...for the win.

Advent of Code 2022 -- Day 13

Haskell's type classes group types based on shared behavior. That's what we mean when we talk about types being Eq, Num, Functor, Foldable, Monad or whatever. Type classes require a minimal set of functions a type must support in order to belong to the class, and then provide derived functions with default implementations. Parametric polymorphism allows restrictions to function signatures, so that only types belonging to particular type classes can be passed as arguments.

This challenge is a textbook example of how efficient it is to take advantage of a custom implementation for a type class... get things sorted.

Advent of Code 2022 -- Day 12

If the problem say «find the cheapest/fastest/shortest path» from here to there, the answer it's Dijkstra's Algorithm. Anyone who says otherwise is lying or selling something.

The usual trick is turning your input into a graph, in order to run Dijkstra on it. The real trick is using Dijkstra without an actual Graph...

Let me 'splain

Advent of Code 2022 -- Day 10

Emulators are fun! Even when they are unidimensional like in this challenge. The CPU has just one register, a cycle counter in lieu of a clock, and just two instructions. No jumps, no RAM, no I/O. Enough to power a pixel display, that also happens to be unidimensional.

But we still need to process the «assembly language» instructions and keep track of a changing state and side-effects. If pure functional programming is about forbidding side-effects, how can we manage this?

Monads, Monoids, and polymorphism...

Advent of Code 2022 -- Day 9

Did you ever play a snake game? It was one of the first things I tried to program as a kid, using character graphics mind you, writing Z80 assembly language. This challenge is about simulating the snake's path given the list of movements, while keeping track of the tail's position.

I'll say the tricky part is correctly «following the leader». It was a fun «aha» moment when I was a teenager. So much so, that it stuck with me, and being able to use it again made my day.

The rest is lazy list processing...

Advent of Code 2022 -- Day 8

There's not much to this challenge. You get a two dimensional grid, you have to go over it and check things relative to each position. It's meant for imperative arrays, with nested loops, I guess...

At least I got to be clever about parsing an array without knowing it's dimensions in advance, and use the «generative array» Haskell trick. I have that going on for me...

...which is nice.

Advent of Code 2022 -- Day 7

I enjoyed this challenge a lot. Instead of the usual «top to bottom» approach, I decided to apply the compiler writer approach: pick the intermediate representation first, write both ends after.

The intermediate representation is actually provided by Haskell's standard library. It provided Functor, Foldable, and a rich API to make the actual computation clearer to implement. It also provides a «zipper» that allowed writing a front-end that builds the whole structure in a single pass, as long as one writes a stateful parser...

Kind of my bailiwick...

Advent of Code 2022 -- Day 6

Sliding windows are hard. They become annoying when you have to carefully synchronize them with I/O operations, and their buffering. For those, and other reasons relating to cardinality, I suppose Day 6 must've been very annoying for those not using lazy functional programming.

And many got angry at Part B...

Advent of Code 2022 -- Day 5

This is the first problem on AOC 2022 that required thinking a bit about proper data structures.

The input data provides an «initial state» and a set of instructions to modify it. Their respective syntactic structure is noticeably different, so I opted for a mixed approach: a formal parser for the first part, with lazy list processing for the rest.

How to handle the changing state is also interesting. There are several stacks and they need to be accessed randomly, so we need a good data structure here. Within that, each stack can then be efficiently modeled with a Haskell list.

Still getting away with base-only modules...

Advent of Code 2022 -- Day 4

The problem for Day 4 is fiendishly presented in a way that leads you to believe using lists or maps, to then compute intersections, is the «obvious» way to work. And then your program blows (in style and performance), because the input data set would result in large lists and larger maps.

This is were a math background comes in handy.

We revisit the Functor and Arrow tricks to keep things point-free.

Still feels like a warmup...

Advent of Code 2022 -- Day 3

Day 3 is a cute one. Again, simple lazy list processing parser taking advantage of the standard library, or writing lazy recursive functions.

One of those rare cases when using length is not frowned upon.

I'll allow it!

Advent of Code 2022 -- Day 2

Day 2 is another parse-and-compute problem. I opted for a simple lazy list processing parser, with a couple of neat tricks thanks to Arrow combinators.

On a hunch, I wrote the first part in the form of a higher order function. It payed up: the second part was trivial to write.

Another top-down approach...

Advent of Code 2022 -- Day 1

Advent of Code 2022 has started. I usually try and solve most of it using Haskell. Some problems are more interesting than others, specially when they make it possible to contrast two or more techniques.

Day 1 is a straightforward parse-and-compute problem. I propose two solutions that exhibit two ways to think in a functional context: «lazy stream processing» and «synthetic parsing».

Here they are...

Category Theory for Programmers

You don't need to learn Category Theory to be proficient at functional programming.

A little Category Theory may help you understand some concepts quicker, and it can be argued that it will make you realize how many concepts you «sorta kinda get» have deeper meanings. It is not needed by a practitioner, but it will make you an outstanding one faster, if that's your goal.

I started studying Category Theory over twenty years ago, suffering through Saunder's canonical «Categories for the Working Mathematician». I do not recommend it, even if you are a working mathematician. I felt thick as brick for a while...

I started my shift from Standard ML and Miranda towards Haskell in the early 2000's. I was advised to read Pierce's «Basic Category Theory for Computer Scientists». It made a lot more sense. I still think is too theoretical for anyone who hasn't had a strong discrete math background.

I was finally able to grasp the material after my (second) reading of Walters' «Categories and Computer Science». Not because I think it's particularly easy to follow, but because I'd read the aforementioned two: it's like reading the «Compiler's» (the «Dragon») after having studied «The Theory of Parsing, Translation, and Compiling»...

The Orange Combinator's Meetup agreed to go through Bartosz Milewski's book. I found it very entertaining: quite pragmatic, a bit «hand-wavy» at times (your Jedi tricks don't work on me), and not heavy on theory nor formalisms (not that there's anything wrong with that). Definitely not a textbook, yet able to introduce complex concepts in a somewhat familiar setting.

Each chapter has several challenges that range from writing things in Haskell, trying the same in lesser programming languages, and some equational reasoning bits.

The Orange Combinator's Meetup tries to go over the challenges in a collaborative fashion. I'm going to be adding my answers to most challenges here, after they've been discussed by the group.

Here they are...

Emojis en mi PDF generado con Pandoc

Hace años que escribo la mayoría de mis documentos usando pandoc porque es una de esas herramientas tan poderosas, que no usarlas es incivilizado. Aparte está escrita en Haskell, lo cual lo hace civilizado con título.

En general, edito el documento con vim usando las extensiones para Markdown. Casi siempre es puro texto. De vez en cuando hay que hacer alguna curiosidad usando LaTeX para insertar una fórmula matemática o TiKZ/PGF para programar diagramas.

En esta ocasión, quise insertar varios Emojis acompañando el texto y Nunca es Fácil®...

...hasta que le encuentras la vuelta.

Navegar a través de SSH

¿Estás en una red con acceso restringido a Internet? Quizás detrás de un filtro restrictivo de contenidos en una empresa, o en un país donde imponen control de contenidos generalizados.

Si te encuentras en esa circunstancia, pero tienes acceso SSH como usuario regular a algún servidor que está fuera de esas restricciones...

...te conviene esta técnica.

A better printf

printf is the canonical example of a variadic function. Many people believe that kind of function is impossible to write in a type-safe fashion, so it's often brought into conversation with an obnoxious «Static typing, huh? I'd like to see how you write printf in Haskell».

Thanks to Haskell's type system capabilites, not only is it possible to write variadic functions, but also a type-safe, polymorphic, extensible, and composable printf, that is way better than your «regular» printf.

'Tis but a neat trick

Cuando REINDEX no funciona

Hay dos tareas recurrentes en la operación de bases de datos PostgreSQL que uno toma por «automáticas»: la recolección forzada de filas con VACUUM, y la reconstrucción de índices con REINDEX.

La primera, cuando el «autovacuum» no es suficiente en una base de datos con mucho tráfico. La segunda, después de algunas migraciones, o cuando el comportamiento de las consultas sugiere que los índices tienen defectos después de una falla abrupta.

Los DBA PostgreSQL damos por descontado que siempre van a funcionar...

Excepto cuando no funcionan

Lenovo y sus .iso que no son ISO9660

Mi plataforma preferida para usar Linux es la portátil Thinkpad, antes IBM y ahora Lenovo. En particular, prefiero las portátiles series T o X. Además que su hardware no es «genérico barato», y está soportado perfectamente, Lenovo hace un esfuerzo bastante bueno por mantener el UEFI/BIOS al día (excepto cuando no, pero esa es otra historia). Es más, Lenovo provee las imágenes para que sean actualizadas desde Linux. Pero como «Nunca es Fácil», me toca descargar imágenes ISO.

Excepto que a veces no son ISO

Haskell String Types Cheatsheet

People who are new to Haskell often wonder what's going on with «string» types. Specially those who still go by using strings and half-baked regex-based parsers, because they still don't know better. As I often say, «String is the poor man's data structure». But I digress...

This cheat sheet helps figuring out what the usual string types are, what are they useful for, and how to go back and forth among them.

It's handy!

De imagen oblonga a cuadrada

Tengo una imagen de altura H y anchura W, oblonga (H > W) en original SVG. Hace falta una imagen cuadrada de lado L en formato PNG. Después de darle vueltas a la página de manual de convert, parte de ImageMagick, esta magia funciona

convert original.svg -resize LxL -gravity center -extent LxL final.png

También funciona con un original en otro formato, siempre y cuando H <= L y W < L.


El siguiente es uno de los problemas más entretenidos que he encontrado recientemente en uno de esos libros de «Acertijos y Problemas para resolver con computadora».

Demuestre que si un jugador de béisbol registra un promedio de bateo de .334, tiene que haber tomado al menos 287 turnos al bate.

El énfasis en demuestre y al menos, es mío.

Me pareció entretenido porque no es de búsqueda exhaustiva (típico en esos libros), e involucra la frontera entre números racionales e irracionales, dos infinitos diferentes.

Porque computación es matemática...

Verificar vigencia de firmas DNSSEC

Cuando una zona DNS está firmada con DNSSEC, a cada registro (RR) en la zona, se le agregan uno o más registros con las firmas digitales (RRSIG). Cada RRSIG tiene una fecha de inserción (inception) y una fecha de caducidad (expiration). Cuando un DNS de resolución (resolver) consulta la zona para obtener los RR y solicita firmas DNSSEC, una de las cosas que hace es verificar que los RRSIG estén vigentes.

¿cómo puedo asegurarme que estén vigentes?

I (used to) do (a lot of) OpenGL

Not many people know that I used to do a lot of OpenGL back when I was way younger. I'll say about three or four people know that I wanted to do my MsC in Computer Graphics and Multimedia Applications, but «things happened» and I ended up switching back to good ol' Programming Languages (again).

Just today this showed up in my timeline

Since the Orange Combinator meetups have been suspended due to the COVID-19 situation, I thought I'd try to write an equivalent program using Haskell.

and this is what I ended up with

Pirata, como tu teoría del maya disléxico

Lo único gracioso de pensar que la dislexia hizo que un maya escribiera 2012 en lugar de 2021, sería escribirlo en Comic-Sans.

No me tienes que explicar qué es un troll, y que ahora tienen más tiempo libre para ejercer su encomiable labor en pro de la hipertensión de otros. Tampoco es necesario explicar el valor del humor como un mecanismo de trascendencia que va más allá de las ideas preconcebidas sobre el lenguaje y la semiótica. La comedia es tragedia más tiempo, y no tengo tiempo para la tragedia que eres creyéndote comediante.

Pero me distraigo, y no hay que distraerse con trolls...

click para ofenderte

Examen dentro de un examen

Hasta que entiendas recursión...

El uso de recursión, tanto para definir algunas estructuras de datos, como para expresar algoritmos que resuelven problemas de computación, tiene un lugar especial en mi corazón.

Las definiciones recursivas resultan compactas, libres de efectos de borde o estado mutable, y terminan presentando un problema complejo como un conjunto de relaciones entre versiones más simples del mismo problema, o de problemas más simples.

Y eso es algo que hay que enseñarle a las nuevas generaciones.

click para el examen que no pudo ser

De Subversion a Git

Me encontré con la necesidad de migrar varios repositorios Subversion a nuevos repositorios Git. La migración necesitaba conservar los nombres de los autores de la mejor manera posible.

click para la receta



It's been a few years since I've tried to explain continuations to anyone, much less in English. This is my take on what, why, when, how, and WTF when using continuations for fun and profit. I'm probably not the first one explaining them this way, and I've borrowed ideas from many places.

I hope former CI3641 and CI4251 students who heard the hand-wavy «I want a sandwich» explanation realize I was trying to convey a very complicated topic that wasn't worth mentioning in class. Also hope former CI4721/CI4722 students feel my pain at having to focus on less interesting non-functional code generation instead of vastly superior continuation based code generation for functional languages.

Comments are welcome at the usual e-mail addresses.

continue clicking