Showing 46 links. See a condensed link blog feed.
Do-nothing scripting: the key to gradual automation (via) by Dan Slimmon on 17-02-2025 19:48
In this article, Dan defines “do-nothing scripting” and presents it as an excellent starting point to making it easier to automate boring, repetitive tasks that don't really add long-term value to your project or life. The idea is simple: create a basic script that essentially just prompts the user to do each step of the boring repetitive task, and wait for user confirmation before showing the steps for the next task.
Here's an example for the task of creating a testimonial on my website based on what someone writes on social media:
do-nothing-testimonial.py
def wait():
input("Press Enter when done...")
print("Copy an existing testimonial as the boilerplate.")
wait()
print("Delete details of the copied testimonial.")
wait()
print("Copy the text of the online testimonial into the new page.")
wait()
print("Fill in details of the online testimonial.")
wait()
print("Does the review have an associated profile with a picture?")
has_pic = input("y/n >>> ").strip().casefold()
if has_pic.startswith("y"):
print("Download the picture.")
wait()
print("Compress it with optimizt and put it in the page folder.")
wait()
else:
print("Generate a new picture.")
wait()
print("Add & commit the new testimonial.")
This script is already valuable because it gives me all of the steps I need to follow and makes sure I don't forget anything.
Furthermore – and I feel like this is the greatest advantage – the fact that the script already exists means I can gradually replace sections with their automated versions instead of just printing instructions to follow.
Fish eye for text by Amelia Wattenberger on 12-02-2025 20:59
In this article, Amelia proposes applying a fish eye lens to text (and other media) to provide an interface that lets the user focus on a specific part of the context (the magnified centre) while also preserving some reduced information about the surrounding content (the distorted, “not magnified” part of the picture).
The article exemplifies this with a story. The story clearly has 10 paragraphs, as indicated by vertical bars on the left of the text. As you move the mouse across those bars, the paragraph you're hovering expands into the full text. The paragraphs immediately before and after fold into a single-sentence summary, and the group of all paragraphs before that one, and the group of all paragraphs after that one, are also summarised together into a single-sentence summary.
Something with this post got me really excited really quickly. This idea of using a fish-eye lens for educational content seems really promising. I hope I figure out how to use this well, soon.
LLMs are a tool for thought (via) by Amelia Wattenberger on 12-02-2025 20:50
In this visually stunning article, Amelia proposes we use LLM chatbots as a tool for thought; as a sparring partner that helps us think through different ideas and topics.
Amelia puts forward some good points in favour of this suggestion, like the fact that LLM chatbots will remember the context of our conversation regardless of whether I take 5 minutes to reply or 5 weeks, which means I can stick to the cadence that is most convenient to me. This, and other arguments in favour of using LLM chatbots as a tool for thought, are accompanied by small interactive widgets that help the author make their points.
A stunning piece and a wonderful read.
UV tricks - Bite code! on 12-02-2025 11:56
In this short article the author shares some tips on using uv. Since I'm starting to really lean on uv and trying to learn how to use it best in my workflows, I appreciated going through some of the common commands that uv provides and some example use cases.
I was particularly happy with the fact that the author shared my blog article on how to use uv to install globally-available Python CLIs.
Truchet images by Ned Batchelder on 11-02-2025 11:07
This article by Ned shows us what Truchet tiles are. Tiles that can be placed randomly to tile a rectangular area and that yet produce beautifil smooth patterns.
A basic example of a Truchet tiling, taken from the linked article:
Ned goes on to share the code he wrote to produce Truchet tilings of all sorts, going into multiscale Truchet tilings (where certain tiles are subdivided recursively) or using Truchet tiles to recreate pictures.
The article is great and Ned also links to his code and notebooks that you can use to generate your own multiscale or image-based Truchet tilings. Go read the article, or at the very least look at the pictures!
Atuin - Magical Shell History on 10-02-2025 16:58
Just found out about Atuin 5 minutes ago, I installed it 3 minutes ago, and I'm already sold. I don't even know all of the things that I can do with Atuin, but one thing is clear right off the bat: searching my console history with Ctrl+R is now something that looks intuitive and that has a great interface.
Before, I always struggled to search my shell history and the functionality is limited. Those days are long gone...
Python: re-creating async in 10 lines using generators (via) by Lucas Seiki Oshiro on 09-02-2025 15:26
In this article, Lucas reimplements asynchronous programming in Python using generators as a learning exercise. Using generators and threads, Lucas mimics the way promises work in JavaScript: when you call a generator function (or when you create a generator expression), you don't get the results right away. You get an object (the generator) that knows how to compute the result.
This is similar to a promise (in JS and other languages).
You get a promise that you'll get a result back.
With the generator, you also have this “promise” that you'll get the result, you just need to call next
on the generator.
The article is fairly short and straightforward and I just wanted to propose a different implementation that leans on generator functions instead of short-circuiting and generator expression “hacks”, so I rewore the final code in the article to both test my understanding and check if I could clean those “hacks”. On a second look, I realised I could write a decorator that turns any “normal” function into an “async” function of this generator-plus-threads flavour:
from threading import Thread
def into_async(callable):
def async_gen_function(*args, **kwargs):
return_value = []
thread = Thread(target=lambda: return_value.append(callable(*args, **kwargs)))
thread.start()
def gen():
thread.join()
yield return_value[0]
return gen()
return async_gen_function
into_async
used in the context of the code of the original post.from threading import Thread
def into_async(callable):
def async_gen_function(*args, **kwargs):
return_value = []
thread = Thread(target=lambda: return_value.append(callable(*args, **kwargs)))
thread.start()
def gen():
thread.join()
yield return_value[0]
return gen()
return async_gen_function
@into_async
def async_lines(path):
print("Reading file", path)
with open(path) as f:
return_value = list(f)
print("Finished reading", path)
return return_value
# NOTE: See the original link for these two files.
# (long1 has ints from range(50_000_000) and long2 has
# ints from range(0, 100_000_000, 2).)
async_lines1 = async_lines('long1.txt')
async_lines2 = async_lines('long2.txt')
def result_gen():
lines1 = next(async_lines1)
lines2 = next(async_lines2)
yield int(lines1[-2]) + int(lines2[-2])
result = result_gen()
print("Result generator created.")
print(next(result))
Dynamic table highlighting with CSS :has on 06-02-2025 17:42
In this BlueSky post the user shows some crazy CSS that allows for dynamic table highlighting. The CSS included in that post was this:
td:has(~ td:hover), /* previous sibling cells */
table:has(td:nth-of-type(3):hover) /* column cells */
tr:not(:first-of-type):has(~ tr:hover)
td:nth-of-type(3) {
background: var(--highlighted);
}
This CSS should highlight a row up to the cell that is hovered and it should also highlight a column up to the cell that is hovered.
After removing the :not(:first-of-type)
because I have proper table headers, the CSS seems to do the highlighting well for any row but only works for the 3rd column, as the example table below shows.
I'm not sure yet if there's a way to not hardcode the 3 in the CSS to work for any column independently or if I'd have to write selectors explicitly for all columns.
# | English | Portuguese | French | German | Italian |
---|---|---|---|---|---|
1 | January | Janeiro | Janvier | Januar | Gennaio |
2 | February | Fevereiro | Février | Februar | Febbraio |
3 | March | Março | Mars | März | Marzo |
4 | April | Abril | Avril | April | Aprile |
5 | May | Maio | Mai | Mai | Maggio |
6 | June | Junho | Juin | Juni | Giugno |
7 | July | Julho | Juillet | Juli | Luglio |
8 | August | Agosto | Août | August | Agosto |
9 | September | Setembro | Septembre | September | Settembre |
10 | October | Outubro | Octobre | Oktober | Ottobre |
11 | November | Novembro | Novembre | November | Novembre |
12 | December | Dezembro | Décembre | Dezember | Dicembre |
Why Bad AI Is Here to Stay by Orson Peters on 04-02-2025 14:15
In this article, Orson talks about how LLMs are likely here to stay and presents some scenarios in which LLMs are useful, despite the fact that they're bad. Orson provides an equation that formalises the usefulness of an LLM in a given context and it's through this equation that Orson presents typical use cases for LLMs and determines whether they are useful for that use case or not.
The equation is gradually refined through the blog post and in its final form it provides a measure of the risk of using an LLM in a given scenario based on the cost of querying the LLM, the cost to verify the LLM answer, the probability that the answer is both correct and relevant, and the risk/cost of using another method if the answer of the LLM is bad:
\[ \text{Cost}_\text{LLM} = \text{Cost}(\text{query}) + \text{Cost}(\text{verify}) + (1 - P(\text{correct}\cap\text{relevant})) \cdot \text{Cost}(\text{bad})\]
Although it's unlikely you'll be able to provide exact numbers for all the terms, this lets you look at different use cases with some rigour, since you can estimate some values in some scenarios, that Orson presents and that I copy verbatim:
The author then provides examples of queries that fall into each category.
Crafting a Winning Conference Talk: Lessons from a PyCon US Reviewer by Sydney Runkle on 04-02-2025 14:09
In this short article Sydney shares some of the lessons she learned as she reviewed talks for PyCon US 2025. The morale of the article seems to be that if you follow the instructions closely and carefully, and avoid spamming the proposals with LLM-generated trash, you're already doing quite well.
By the end of the article, Sydney shares that many proposals have one or more of the following issues:
This reinforces the idea that if you follow the instructions closely and show that you've thought about your proposal thoroughly, you're in good shape.
Auto-Renaming My Untitled.ipynb Files With Gemini 1.5 Flash by Audrey Roy Greefeld on 02-02-2025 13:57
In this short article Audrey shares how she used an LLM to automatically rename her dozens of Python notebooks that were untitled. This was a nice short read because it's always good to see how others use LLMs to make their lives easier.
Did she end up saving more time than if she had opened the notebooks and renamed them one by one? I can't know for sure. Probably not, since she only had to rename 32 notebooks.
But the coded approach was certainly more enjoyable and now she has a script she can rerun if needed in the future.
TIL: Every Jupyter notebook cell runs in an async loop by Daniel Roy Greenfeld on 02-02-2025 13:47
In this TIL article Daniel shares how he learned that if you're writing asynchronous code, you don't need to run an async loop inside the notebook. In fact, you can just paste the snippet below into a code cell and it will run directly:
import asyncio
async def f():
print("starting")
await asyncio.sleep(3)
print("done")
await f()
In a regular Python script, you can't write await f()
just like that, outside of an asynchronous function.
Solving Logic Problems with Python Decorators – Chelsea Troy (via) by Chelsea Troy on 31-01-2025 11:57
In this article, Chelsea states a logic problem:
“Baker, Cooper, Fletcher, Miller, and Smith live on different floors of an apartment house that contains only five floors. Baker does not live on the top floor. Cooper does not live on the bottom floor. Fletcher does not live on either the top or the bottom floor. Miller lives on a higher floor than does Cooper. Smith does not live on a floor adjacent to Fletcher’s. Fletcher does not live on a floor adjacent to Cooper’s. Where does everyone live?”
Chelsea then proceeds to writing a couple of suboptimal functions that solve this and then converges on a more efficient version of brute forcing.
Then, because of the way the code is formulated, Chelsea introduces a decorator that solves logic problems like these.
The decorator solve
must be used around a function that checks the requirements and produces a function that accepts the possible values for each variable.
Something like this:
def all_combinations(**kwargs):
"""Produce all combinations of the variables and their possible values,
respectively the keys and values of the kwargs dictionary."""
...
def solve(reqs_function):
def solver(**kwargs):
for comb in all_combinations(**kwargs):
if reqs_function:
return comb
raise RuntimeError("Couldn't solve.")
return solver
@solve
def reqs_function(**kwargs):
"""Checks the reqs of the problem statement."""
return kwargs["baker"] != 1 and ...
Three problems by David Beazley on 29-01-2025 23:14
In this article David shows how to use parser combinators and lambda functions to define a small but powerful set of parsers that are highly modular and composable. The parsers and parser combinators in the article are mostly implemented with anonymous functions in a style that would be frowned upon by most, but I think David did that on purpose. I'm just not insightful enough to understand why.
I remember reading this article some time ago and not understanding a single thing. This time, I understood some things. Hopefully, next time I read it, I will understand even more.
Either way, here's some of the parsers that Dave defines:
# Copied from the linked article.
shift = lambda inp: bool(inp) and (inp[0], inp[1:])
nothing = lambda inp: (None, inp)
filt = lambda predicate: (
lambda parser:
lambda inp: (m:=parser(inp)) and predicate(m[0]) and m)
literal = lambda value: filt(lambda v: v == value)
char = lambda v: literal(v)(shift)
fmap = lambda func: (
lambda parser:
lambda inp: (m:=parser(inp)) and (func(m[0]), m[1]))
digit = filt(str.isdigit)(shift)
def one_or_more(parser):
def parse(inp):
result = [ ]
while (m:=parser(inp)):
value, inp = m
result.append(value)
return bool(result) and (result, inp)
return parse
digits = fmap(''.join)(one_or_more(digit))
value = fmap(int)(digits)
def seq(*parsers):
def parse(inp):
result = [ ]
for p in parsers:
if not (m:=p(inp)):
return False
value, inp = m
result.append(value)
return (result, inp)
return parse
either = lambda p1, p2: (lambda inp: p1(inp) or p2(inp))
Now we can parse some basic mathematical expressions with additions, multiplications, exponents, and parens:
# Created by myself.
plus = char("+")
times = char("*")
exp = fmap("".join)(seq(char("*"), char("*")))
lparen = char("(")
rparen = char(")")
term = lambda s: either(
seq(lparen, addition, rparen),
value,
)(s)
exp = either(
seq(term, exp, term),
term,
)
mul = either(
seq(exp, times, exp),
exp,
)
addition = either(
seq(mul, plus, mul),
mul,
)
math_parser = addition
print(math_parser("3*2+(2+5)**8"))
# ([[3, '*', 2], '+', [['(', [2, '+', 5], ')'], '**', 8]], '')
What is an example of the Liskov Substitution Principle? - Stack Overflow on 27-01-2025 21:40
When working with typed Python code I get mypy complaining about the Liskov Substitution Principle quite frequently. I end up rereading an explanation of it and it looks absolutely obvious to me. So, I don't get how/why I keep messing it up.
A cat is an animal.
Therefore, if you have the class Animal
and want to create a class Cat
, you have to make sure that wherever you can use a class Animal
, you can replace that with Cat
and the code should still work.
For example, here's an easy way to break the LSP:
class Animal:
def eat(self, food: Animal) -> None:
pass
class Fish(Animal):
...
class Cat(Animal):
def eat(self, food: Fish) -> None: # <--
pass
This breaks the LSP because the current definition of Animal.eat
lets me write something like Animal().eat(Cat())
, and a cat is an animal, so wherever I can use a generic animal I should also be able to write a cat.
However, Cat().eat(Cat())
doesn't work because Cat.eat
expects fish.
Therefore, I conclude that there's something fishy with Animal.eat
/ Cat.eat
.
Using `any()` by Eric Matthes on 24-01-2025 14:56
In this article the author introduces the built-in any
.
However, this isn't really a “tutorial on how to use any
”; instead, Eric shares his experience with using any
and reflects on the fact that apparently he is never able to use it when first implementing something.
Eric only thinks of using it on a refactoring pass.
I liked this write-up because it's a very candid demonstration of what Eric considers to be a suboptimal behaviour of his, and then gets us to think about the simple things, like any
, that are not so simple if you think about the big picture.
For example, to use any
in the real world you will hardly ever be given a list of Boolean values to which you can apply any
.
In the context of making a decision based on whether any item in a collection satisfies a given predicate, you have to learn to recognise the pattern:
any(predicate(element) for element in iterable)
This line of code answers the question “does any element of the given iterable satisfy my predicate?”.
intellij 15 - VS Code Regex find and replace with lowercase, use \l or \L if possible - Stack Overflow on 24-01-2025 14:33
Sometimes I use regular expressions to do some mass text processing. Today I was working on a first version of my Python glossary and wanted to reformat a couple of things. In the process, I wanted to move some words around and one of the words would now become the first word in a new paragraph, so it needed to be turned into an uppercase letter.
I knew I could do this with regular expressions so I googled how to do it and this Stack Overflow answer was what I was looking for.
The sequences \l
, \L
, \u
, and \U
, can be used to modify the casing of the groups that are included after.
For example, using the search pattern (\w+)
and the replace pattern \u$1
on the text "bananas" will replace it with "Bananas".
Using \U
instead will convert all letters to uppercase instead of just the first one.
Flexoki — Steph Ango by Steph Ango on 23-01-2025 01:03
Steph Ango, the author of Obsidian, writes about Flexoki in this link, “an inky color scheme for prose and code. Flexoki is designed for reading and writing on digital screens. It is inspired by analog inks and warm shades of paper.”.
From time to time I like to give my website a fresh coat of paint and I'm wondering whether I'll be using the Flexoki colour scheme or not.
I included the base colour palette here, for reference:
PHP Markdown Extra – Markdown Inside HTML Blocks on 22-01-2025 20:33
This page documents “Markdown Extra”, an extension of Markdown that I use on my website. I'm blogging about this because the section “Markdown Inside HTML Blocks” shows how to tell the Markdown parser that I have Markdown nested inside HTML blocks.
This is particularly useful because sometimes I like to include code blocks inside the HTML tag <details>
.
The link shows that I have to add the attribute markdown="1"
to the HTML tag that will contain nested Markdown and the parser takes care of the rest (and removes the attribute).
Here's a tag <details>
that uses the attribute in the source code:
print("Hello, world!")
Here's what the same HTML + Markdown combo will look like without the correct Markdown Extra attribute:
Rules for Writing Software Tutorials · Refactoring English by Michael Lynch on 22-01-2025 19:12
In this article the author puts forward 16 rules for writing good software tutorials:
All of these rules made perfect sense to me and some of them I already try to enforce in my articles. The suggestions that resonated particularly well with me were those related to making your tutorial as easily reproducible and as easy to follow along as possible. To this end, Michael suggests several tweaks I can make to my code samples that make life much easier for the reader, which should be my end goal any way.
I'm happy to say that I have already been doing things in this direction. For example, I used to include lots of snippets of Python REPL sessions, like this:
>>> x, y = 1, 2
>>> x
1
>>> y
2
However, this was hard to work with if you wanted to copy my code and run it yourself.
A small change I made was to start writing everything as Python scripts and use the print
function instead:
x, y = 1, 2
print(x) # 1
print(y) # 2
This is much easier to copy and run for yourself. Not to mention the “copy to clipboard” button I added to all code snippets!
Webring - Wikipedia on 21-01-2025 10:50
Today I learned about webrings, which were popular in the 1990s and 2000s. A webring is a collection of websites that are linked cyclically.
using Linear Programming to find optimal builds in league of legends - annieversary by Annie Versary on 21-01-2025 10:45
In this post, the author uses linear programming to solve an optimisation problem in League of Legends, a computer game. This post is a great example of how one can use a problem from “real life” (at least, for those who play the game) to introduce technical topics or concepts.
The problem being solved has to do with the fact that a champion needs to buy items that increase three of their stats so that the champion's abilities evolve. What is the optimal build to achieve this? In other words, what are the cheapest items to buy that grant enough of these stats for the evolved abilities?
The author proceeds to use Rust and a linear programming package to compute the solution and then goes on to discuss whether the optimal solution really is optimal, because when buying items you want to consider the various stages of the game, and not just the single moment when your abilities might evolve because of the items you bought. The author then poses relevant follow-up questions and possible ways of answering those solutions but doesn't answer the questions, leaving them “as an exercise for the reader”.
ChatGPT conversation to automate testimonials on 17-01-2025 22:14
Today I interacted with ChatGPT to create a page on my website where anyone can leave a testimonial for my work. When you submit the form, a custom Grav plugin runs to convert the form replies into a suitable format that I can display in the wall of testimonials.
Since I don't know PHP, I got ChatGPT to help me with this and in the end we got a working solution. Just head on over to the testimonials page and you'll see what I'm talking about.
More search, less feed (via) by Austin Kleon on 17-01-2025 14:10
This short article gets you to think about the differences between browsing a feed, like a news feed or the feed of a social media app, versus browsing search results.
When browsing a feed, you browse random stuff that was pushed to you by the people, companies, and organisations that published those pieces of information. Typically, you didn't ask for that info on those topics; an algorithm just decided to present it to you.
On the other hand, when you are searching, you make a concrete decision of what to search for. You browse results of your search. You decide what to read and what not to read. You played a part in what information is shown to you.
“Livewired” book on Goodreads on 16-01-2025 23:45
I enjoyed learning more about the way the brain works and how it adapts and evolves. As an example, I enjoyed learning about all of the different ways in which people tried to overcome sensorial shortcomings they had, and how some tried to enhance their own senses, and the work that the brain puts in to start processing these new inputs and to make sense of them. As I understood, it looks like you can just “plug in” new inputs to your brain and your brain will learn to process them, much in the way it learned to process the input from your eyes, from your ears, from your skin, etc. It receives signals and as you interact with the world those signals change, so you learn useful associations, like hitting the door hurts or that petting an animal is nice. That's how I understood it, at least...
Welsh rarebit - Wikipedia on 15-01-2025 00:25
In Portugal there is a typical dish called “francesinha”, and the literal translation of the name “francesinha” means “little French woman”, which is a bit of a weird name for a dish. When I commented about this with a group of Frenchmen, and when I explained what the dish consisted of, they remarked “Oh, that sounds like the Portuguese version of a Welsh”.
After Googling for a Welsh and after finding out it's kind of similar to a francesinha, I find it amusing that the Brits and the French eat a dish called “Welsh” and we eat a vaguely similar dish called “little French woman”.
Masonry layout - MDN web docs on 14-01-2025 23:50
I was trying to implement a pure-CSS masonry layout for a page of my site where I'd display reviews and testimonials and I found the this masonry layout page, but apparently it's a very experimental feature. At least, at the time of writing this. You can get this in Firefox by manually enabling a flag and Safari has experimental support for it, but it looks like all other major browsers don't even support this in any way, shape, or form.
Jupytext documentation on 13-01-2025 20:56
Jupytext is a brilliant tool that I've used in the past to keep jupyter notebooks in sync with plain-text versions of those same notebooks. If I recall correctly, I used jupytext to keep Jupyter notebooks in sync with Markdown files that contained the same content.
I plan on using this again in the future to write a couple of books. For some of them, it's easier to write them as jupyter notebooks but then I need to convert those into markdown files so that pandoc is able to do its job converting the files into an ebook.
ELIZA effect - Wikipedia (via) on 12-01-2025 13:35
The ELIZA effect, named after the ELIZA chatbot, is the “tendency to project human traits — such as experience, semantic comprehension or empathy — onto rudimentary computer programs having a textual interface”.
With LLMs on the rise and with their usage spreading among non-technical people, I have a feeling that fighting this ELIZA effect will be both crucial and impossible. If the ELIZA chatbot was as basic as it was and it managed to affect its users in such a way that they named the effect after the chatbot, I can't imagine what LLMs will do to the general population...
#!/usr/bin/env -S uv run (via) by Simon Willison on 10-01-2025 15:43
I started using uv recently and I keep getting impressed by everything I can do in such a convenient way with uv.
I've been using uv to manage scripts and script dependencies but using the shebang #!/usr/bin/env -S uv run
in scripts and then making them executable (with chmod 755
) is on a whole new level.
Essentially, you want your scripts' header to look like this:
#!/usr/bin/env -S uv run
# /// script
# requires-python = ">=3.13"
# dependencies = [
# ...,
# ]
# ///
# code here...
If you think about it, what this means is that you get shell scripts written in Python with self-contained dependencies that uv manages for you...
Regex Chess: A 2-ply minimax chess engine in 84,688 regular expressions (via) by Nicholas Carlini on 10-01-2025 15:25
At the top of this article you are presented with a very basic rendering of a chess board and an input field where you're supposed to type chess moves:
Although this chess engine isn't very smart, since it fell for the Scholar's mate after checking me with a rogue bishop, the part of the engine that is computing what move to play is a series of 84,688 regular expressions... The full explanation of how the engine works is brilliant and is available immediately under the chessboard. For reference, I did beat the engine when I played 5. Qxf7#:
Never Split The Difference | Chris Voss | TEDxUniversityofNevada - YouTube (via) on 10-01-2025 11:16
This short TED talk by Chris Voss, author of “Never Split the Difference”, renewed my interest in his book. In this TED talk, he mostly talks about what he calls “tactical empathy”, the act of listening to others, trying to understand their feelings, and making them feel heard, without necessarily agreeing with what they are saying.
In this talk, Chris Voss tells two or three stories that show the value of practicing tactical empathy, whether with a terrorist – Chris Voss was an FBI hostage negotiator – or with someone from your family.
Reflecting on 2024: My Year in Books by Mia Bajić on 10-01-2025 11:12
I met Mia in a Python conference – possibly EuroPython – and was quite interested in seeing what she had read. My interest in her article increased when I realised she read some books that are in my "to read" list, like “Never Split the Difference” by Chris Voss or “How to Win Friends and Influence People” by Dale Carnegie. Reading her reviews also brought to my attention a couple of other books, like “TED Talks: The Official TED Guide to Public Speaking” by Chris Anderson.
Link blog in a static site (via) on 07-01-2025 17:02
One more “meta link” in this link blog, Redowan shares his approach to link blogging. Since he's using a static site, he has a markdown file where he blogs about all of the links for a given year. Then, somehow, the theme/tools he uses also turn that page into a nicer, shorter “feed” that allows to easily glance over all the links he blogged about.
This approach is different from mine. Since I have a dynamic website, I have a small markdown file per link and then the CMS I'm using (Grav, at the time of writing) takes all those short snippets and puts them together.
“Talking to Strangers” book on Goodreads on 07-01-2025 15:58
I picked this book up randomly in a Canadian bookstore thinking it was about the act of starting to interact with random strangers on the street or how to maintain conversations with people you barely know. The book isn't literally about that, but by the time my wife made her way back to me I was already hooked and I bought the book.
In my own words, and as far as my understanding goes, the book focuses on three main topics, namely
I enjoyed learning a bit more about human psychology and I found that most of the stories and examples shared of these principles in action, or of the rare counter-examples, were quite powerful... In the sense that they illustrate how things can go terribly wrong when we don't take into account the limitations we have when interacting with people we don't know.
Your Name in Landsat (via) on 06-01-2025 23:55
This page from NASA lets you type any word (they suggest you type your name) and the page will then spell out your name with satellite imagery from the Earth.
I gave it a spin with my name (Rodrigo) and with this website's name (mathspp):
Ready Player One book on Goodreads on 06-01-2025 23:50
“Ready Player One” came out as a movie directed by Steven Spielberg in 2018 and ignorant me thought it was just a movie. A friend told me it was inspired by a book and since I enjoyed the movie, he thought I'd enjoy the book as well.
I read the book and I enjoyed it even more than I enjoyed the movie. There were some clear differences, especially when it came to the progression of the Easter Egg hunt, which the whole book/movie revolves around. I preferred the challenges as written on the book, which appealed more to the geek in me, but I totally understand why they made the changes they made for the movie, which I think worked out quite well.
Next up on my reading list: “Ready Player Two”.
Can you prompt LLMs to admit when they don't know the answer? (via) on 06-01-2025 09:11
In this piece, Anthony Shaw talks about his attempts to make LLMs recognise their inability to answer certain questions and how, by default, LLMs will output a response that might look helpful even if it is complete gargabe.
The main example given was that of a game of Set where Anthony and his kid needed help determining whether there was a match or not, given a picture of the game. The LLMs prompted were very keen on creating garbage output, with most (if not all) mentioning cards that weren't even in play in the photo shown.
In the end, Anthony did manage to get better outputs by instructing LLMs to reply with a shrugging emoji in case they could not compute the answer reliably. (There is also a bonus snippet of Python code in the end that looks for matches programmatically. Maybe prompting the LLMs to write such piece of code would've been easier and more reliable.)
Duck Typing in Python (via) on 03-01-2025 17:35
I was preparing a webinar on typing (for the Python Mastery Guild) and I was thinking about duck typing and how to explain it. I had come to the realisation – which is kind of obvious in hindsight – that dunder methods are for duck typing. It's through dunder methods that you add the duck-like behaviours that matter to your own classes. Not surprisingly, Trey's article on duck typing presents the same conclusion in a later section of the article.
Write your Own Virtual Machine (via) on 03-01-2025 17:29
I have come to understand that I really enjoy learning about parses, compilers, VMs, and other things along these lines. For example, I really like implementing parsers. (I'm not sure why, though...)
I have very limited knowledge of C but it looks like the final program is simple and short enough (250 lines of code) that I'd be able to follow the full tutorial and implement it in C. I started reading it and the prose looks quite accessible, so if you're into lower-level stuff, give this a read!
Genuary 2025 (via) on 02-01-2025 13:56
The TL;DR is that this is a friendly challenge to get you to write computer programs that create generative art. They give you a guiding prompt for each day of January – which you are free to ignore – and then you share your creations online. I'm “pinning” it here as something I'd love to do but at the same time I don't consider essential enough to actually carve out the time to do it during January... Maybe I'll get to one or two...
Squared triangular number on 31-12-2024 19:05
With 2025 almost starting, I've seen a number of people talking about the fact that \(2025 = 45^2\), and since \(45\) is a triangular number, that gives rise to two fun formulas to compute \(2025\). First, since \(45\) is a triangular number, you get
\[ 2025 = 45^2 = (1 + 2 + 3 + \cdots + 8 + 9)^2 ~ .\]
The link to the Wikipedia page about squared triangular numbers also gives a beautiful geometrical demonstration that the formula above is equal to the sum of the cubes of the same integers:
\[ 2025 = 1^3 + 2^3 + 3^3 + \cdots + 8^3 + 9^3 ~ .\]
MacOS Setup Guide (via) on 30-12-2024 10:37
I've been using a Macbook for 2 or 3 years and there are things in this guide I'm doing/using already, but there are also other tips that I want to take a better look at and ponder about. In particular, the list of apps recommended and the customisation of iTerm2 look like sections I want to devote some time to.
Bron-Kerbosch algorithm (via) on 24-12-2024 17:39
This year I've been solving Advent of Code consistently and for day 23 I had to implement a small algorithm that finds clicks in a graph. My recursive function isn't particularly clever but stands at 5 lines of code:
def find_clicks(click, nodes, edges):
for idx, node in enumerate(nodes):
if click <= edges[node]:
yield from find_clicks(click | {node}, nodes[idx + 1 :], edges)
yield click
nodes
is a list of all the vertices in the graph and edges
is a mapping from vertex to set of neighoubrs.
Initially, call it with find_clicks(set(), nodes, edges)
.
The generator yields sub-maximal clicks but this was good enough for my purposes.
I was pleasantly surprised (but not too surprised) to find later that there is an algorithm that finds maximal clicks in a graph.
Link blogging with Grav on 24-12-2024 17:22
Keeping in line with the “meta” link blogging, this link should point to a series of interactions I had with ChatGPT to help me set up a new type of page that was suitable for link blogging.
My approach to running a link blog on 24-12-2024 17:14
I enjoy the stuff that Simon writes and in his newsletter he introduced me to a concept I didn't even know: “link blogging”. I decided to give it a try and so I thought it was only fitting to start by blogging about this link of his.
At least for now, I think I'll stick to a simpler workflow to see if I enjoy link blogging and in the future I might extend the way I go about this...