Vladimir Keleshev's Avatar

Vladimir Keleshev

@keleshev.com

OCaml programmer, author of Compiling to Assembly from Scratch: https://keleshev.com/cas Copenhagen

783
Followers
436
Following
55
Posts
15.08.2024
Joined
Posts Following

Latest posts by Vladimir Keleshev @keleshev.com

Onfim’s drawing of two people

Onfim’s drawing of two people

He was no Rafael, but look at this piece, could have been a banger punk rock cover!

18.08.2025 09:59 👍 2 🔁 0 💬 0 📌 0

I appreciate the idea, but the picture is good enough for me, thanks for that!

23.05.2025 18:09 👍 1 🔁 0 💬 0 📌 0
Post image

@keleshev.com not sure whether you already saw, but Compiling to Assembly from Scratch got a review in c't 9/25 (the largest German IT magazine)

21.05.2025 16:09 👍 5 🔁 1 💬 1 📌 0

Oh, wow! Thanks for noting!

22.05.2025 06:14 👍 1 🔁 0 💬 1 📌 0
A probable self portrait by Rafael, drawn when he was around the same age (1499), Ashmolean Museum, Oxford, UK.

A probable self portrait by Rafael, drawn when he was around the same age (1499), Ashmolean Museum, Oxford, UK.

Onfim was not the greatest artist, but why do you have to rub it in like that?!

15.05.2025 21:09 👍 2 🔁 0 💬 1 📌 0

Basically ‘class Parser[T]: pass’ is same as what used to be (from memory):

from typing import Generic, TypeVar
T = TypeVar(“T”)
class Parser(Generic(T)): pass

03.05.2025 16:39 👍 2 🔁 0 💬 0 📌 0
@dataclass
class Parser[T]:
    parse: Callable[[Source], ParseResult[T] | None]

    @staticmethod
    def regexp(regexp: Pattern) -> Parser[str]:
        return Parser(lambda source: source.match(regexp))

    @staticmethod
    def constant[U](value: U) -> Parser[U]:
        return Parser(lambda source: ParseResult(value, source))

@dataclass class Parser[T]: parse: Callable[[Source], ParseResult[T] | None] @staticmethod def regexp(regexp: Pattern) -> Parser[str]: return Parser(lambda source: source.match(regexp)) @staticmethod def constant[U](value: U) -> Parser[U]: return Parser(lambda source: ParseResult(value, source))

Like, what language is this?

03.05.2025 10:21 👍 2 🔁 0 💬 0 📌 0
@dataclass
class Parser[T]:
    _parse: Callable[[Source], ParseResult[T] | None]

    def parse(self, s: Source) -> ParseResult[T] | None:
        return self.__dict__['_parse'](s)
    
    @staticmethod
    def regexp(regexp: Pattern) -> Parser[str]:
        return Parser(lambda source: source.match(regexp))

    @staticmethod
    def constant[U](value: U) -> Parser[U]:
        return Parser(lambda source: ParseResult(value, source))

@dataclass class Parser[T]: _parse: Callable[[Source], ParseResult[T] | None] def parse(self, s: Source) -> ParseResult[T] | None: return self.__dict__['_parse'](s) @staticmethod def regexp(regexp: Pattern) -> Parser[str]: return Parser(lambda source: source.match(regexp)) @staticmethod def constant[U](value: U) -> Parser[U]: return Parser(lambda source: ParseResult(value, source))

Glad to see that Python finally got more dedicated syntax for type annotations in 3.12. Now it looks quite decent. So I updated the Python version of the book's compiler to use the new syntax: github.com/keleshev/com...

02.05.2025 19:52 👍 3 🔁 0 💬 2 📌 0
Advanced Error Handling in OCaml

I have a contrarian urge to reply "that's just easy!", which it's not; however, here's a bunch of techniques that I found very helpful:

keleshev.com/advanced-err...

But it relies on polymorphic variants, which is an OCaml-only feature, as far as I know.

21.03.2025 14:20 👍 3 🔁 0 💬 0 📌 0

How to reconcile that the standard says:

prog [-xyz] == prog [-x] [-y] [-z]
prog [options] == prog [-x] [-y] [-z]

but at the same time,

prog [<x> <y>] != prog [<x>] [<y>]

06.01.2025 22:18 👍 1 🔁 0 💬 0 📌 0
cal

Found this counter-example from the standard:

cal [[<month>] <year>]

(which is clearly not the same as [<month>] [<year>])

pubs.opengroup.org/onlinepubs/9...

06.01.2025 22:16 👍 1 🔁 0 💬 1 📌 0

My only problem that makes me keep returning to this is that in EBNF the square brackets don't work this way ([<x> <y>] != [<x>] [<y>]), and the POSIX utility convention notation is clearly inspired by EBNF…

04.01.2025 22:33 👍 2 🔁 0 💬 1 📌 0

Then there's the `[options]` shortcut. If we assume that the `options` from the options shortcut stands for all the options in the `Options:` section, then the original behavior also makes more sense:

[options] => [-x -y -z] => [-x] [-y] [-z]

04.01.2025 22:26 👍 1 🔁 0 💬 1 📌 0

But maybe the right way is to say that this is only the case for these short option strides, and not for anything else?

[-xyz] => [-x] [-y] [-z]
[-x -y -z] => [(-x -y -z)]

04.01.2025 22:24 👍 1 🔁 0 💬 1 📌 0

That's because the POSIX standard has examples like `prog [-xyz]` where it is clear that this means the same as `prog [-x] [-y] [-z]`.

04.01.2025 22:20 👍 1 🔁 0 💬 1 📌 0

In original docopt, square brackets mean each item is optional. For example, `prog [<x> <y>]` is the same as `prog [<x>] [<y>]`. Weird or not? To make both-or-nothing you need to group them like `prog [(<x> <y>)]`. You know why this was the design decision?

04.01.2025 22:18 👍 2 🔁 0 💬 1 📌 0

😲

02.01.2025 11:11 👍 1 🔁 0 💬 0 📌 0

Exactly. At my desk I have two USB-C connectors, one for Raspberry Pi, and another one for laptops, and it doesn't work if you plug in the wrong one.

01.01.2025 21:13 👍 0 🔁 0 💬 0 📌 0

My LG monitor (32UN880-B) is advertised at 60W PD, but at 5V it gives my Pi 400 low voltage warnings and crashes at high loads.

Another BenQ monitor I have (PD3205U) advertises 90W PD and works just fine powering Pi 400.

01.01.2025 20:21 👍 1 🔁 0 💬 0 📌 0

Pi 5 and Pi 500 require 27W at 5V, and almost certainly no device will provide that via USB-C other than the official power supply.

01.01.2025 20:18 👍 1 🔁 0 💬 2 📌 0

Power new Raspberry Pis is tricky nowadays, isn't it?

Pi 4 needs 15W at 5V, but normally hubs/screens/power supplies advertise their max power delivery at a higher voltage, so there's no way to know without trying.

01.01.2025 20:17 👍 3 🔁 0 💬 2 📌 1

Everyone know shat 3840 × 2160 divided by two gives 1920 × 1080, but did you know that 3840 × 2160 divided by *three* gives 1280 × 720!

So, 720p looks crisp (but pixelated) on 4K, but horribly scaled on an 1080p panel.

22.12.2024 16:31 👍 1 🔁 0 💬 0 📌 0

Pinebook Pro has a 1080p panel, and downscaling looks horrible. On the other hand, Pi 400 used with 4K monitor can be downscaled, to 1080p or 720p without scaling issues.

22.12.2024 16:28 👍 0 🔁 0 💬 1 📌 0

Originally my plan was to get two Pinebook Pro for kids. I got one to test out, but could not get Minecraft running with a good frame rate (neither Bedrock, nor Java).

22.12.2024 16:21 👍 0 🔁 0 💬 1 📌 0

Of course, ever since Pi 400 came out it was obvious that there will be a Raspberry Pi laptop at some point in time, and the new Raspberry Pi screen is also an obvious stepping stone to that, but it's surprising how long it takes, considering what PINE64 folks done with Pinebook Pro long ago.

22.12.2024 16:18 👍 0 🔁 0 💬 2 📌 0

I remember it took me several evenings to tweak Minecraft with different plugins to get a good frame rate, but I got it working. With new Pi 500, I assume you can just use stock Minecraft Java without issues, since it performs 3x on video benchmarks.

22.12.2024 16:14 👍 0 🔁 0 💬 1 📌 0
Two Raspberry Pi 400 wrapped in Minecraft gift paper.

Two Raspberry Pi 400 wrapped in Minecraft gift paper.

I got two Pi 400 originally as Minecraft devices for kids on Christmas, but since then they are not using it much for Minecraft, more for Math Academy and school stuff. We got Nintendo Switch since then, so most gaming moved there.

22.12.2024 16:10 👍 1 🔁 0 💬 1 📌 0

It's 2–3 times faster, and has a real power button, and that's the complete list of improvements.

Everybody seems to be disappointed about the missing NVME slot, but I don't care much about it.

22.12.2024 15:50 👍 0 🔁 0 💬 1 📌 0

Not going to upgrade kids to Raspberry Pi 500 (from their Pi 400). Waiting for the next Pi X00 series for four years, of course it's a disappointment.

22.12.2024 15:46 👍 0 🔁 0 💬 1 📌 0

Did exactly that a few years back and after few days someone tried to use my card details to withdraw 300 bucks in Chile… 😬

19.12.2024 20:20 👍 0 🔁 0 💬 0 📌 0