Read Only Memories
Let me annoy you in inglés and español.
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.
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...
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...
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...
This challenge is what we venezuelans describe as «concha de mango». It is deceptively simple at first, but you'll inevitable fall in the trap.
Not to worry. You can get out of big trouble, with a little Chinese magic.
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?
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.
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...
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...
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.
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.
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.
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.
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.
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».
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.
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®...
¿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...
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
.
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...
I always use Debian stable on my work laptop. I also tend to use the provided version for most programming languages. Sometimes I need multiple versions for work or research related reasons. This isn't a problem with languages such as Haskell or Rust, but it tends to be a pain with others, Golang being the cause of these notes.
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.
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.
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.
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.
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
Hello triangle. (full res image at:https://t.co/ZUcxHRUZwW) pic.twitter.com/77xs43Ow3j
— Jari Komppa (@Sol_HSA) September 18, 2019
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.
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...
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.
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.
Disclaimer
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.