Alice ✨'s Avatar

Alice ✨

@welltypedwit.ch

There’s no sense crying over every mistake. You just keep on trying ’til you run out of cake - GLaDOS https://welltypedwit.ch

2,696
Followers
337
Following
5,414
Posts
19.05.2023
Joined
Posts Following

Latest posts by Alice ✨ @welltypedwit.ch

it goes well with the spaghetti

06.03.2026 13:28 👍 6 🔁 0 💬 1 📌 0

that's out of date actually! it used to do that but these days ImpredicativeTypes exists and ($) is representation polymorphic so it doesn't need to

06.03.2026 08:03 👍 2 🔁 0 💬 0 📌 0

btw, did I mention that because vega doesn't have references, fields don't have to be contiguous? I.e. the compiler could totally represent ((a,b), c) like (a, c, b)
(although it doesn't do anything like that yet because non-contiguous fields kind of complicate the compiler ^^)

05.03.2026 18:30 👍 3 🔁 0 💬 1 📌 1

i'm pretty sure ghc can even optimize one into the other because they *are* semantically equivalent! (but don't quote me on that)

05.03.2026 17:34 👍 1 🔁 0 💬 0 📌 0

well, `f x = if blah x then g else h` isn't (in a pure, lazy/total setting) any different than `f x y = if blah x then g y else h y` though. you know just as much about what's being executed.

05.03.2026 17:34 👍 1 🔁 0 💬 2 📌 0

okay great! that's what i'm doing in vega and i got worried for a second that i'd have to rewrite the layout generation code again ^^

05.03.2026 17:24 👍 2 🔁 0 💬 1 📌 0

However, their endgame isn't to eliminate human labor (I doubt they would for software engineering). The final outcome of this general trend is them inserting themselves as a gratuitous extra step in the process where people babysit agents and pretend the agents did all the work

05.03.2026 16:43 👍 23 🔁 1 💬 0 📌 0

hmm interesting! does it make sense to have a separate stride value though? like, are there cases where stride isn't just size rounded up to the next multiple of alignment?

05.03.2026 16:23 👍 3 🔁 0 💬 1 📌 0

(so: i guess "feature" although i think currying is kind of silly in general)

05.03.2026 15:32 👍 1 🔁 0 💬 0 📌 0

in a pure setting there is (almost) no meaningful difference between those! (that's kind of the idea behind currying ^^)
in an impure setting it could be bad because the function could do something before returning the function for the next argument but in practice noone does that

05.03.2026 15:31 👍 1 🔁 0 💬 2 📌 0

well that doesn't apply in rust though because in rust `Puppy` will have size 16, not 9 *because* of alignment. it only has size 9 if you give it `repr(packed)` but in that case you would probably also want it to be stored unaligned (but packed more tightly) in an array wouldn't you?

05.03.2026 15:21 👍 0 🔁 0 💬 1 📌 0

what is the reason to want a different stride?

05.03.2026 14:56 👍 2 🔁 0 💬 2 📌 0

like, you know that thing about how rust iterator loops are faster than for loops because they skip the bounds check? in vega, the for loop can skip the bounds check as well! (as long as you iterate over the indices as `Index(n)`s)

04.03.2026 21:32 👍 1 🔁 0 💬 0 📌 0

in particular, what's really cool about this is that this is safer, often more convenient *and* more efficient than regular bounds checked arrays!

04.03.2026 21:32 👍 1 🔁 0 💬 1 📌 0

maybe enforcing a `!` on aliases helps with that, maybe not. but i'm really happy with this API either way

04.03.2026 21:29 👍 2 🔁 0 💬 1 📌 0

it will probably be less noisy than having the full existential, but my concern is that the difference between `Array` and `AnyArray` might be a bit confusing if you don't know how it works. especially since `AnyArray!(Int)` will still show up as `Array(n, Int)` in error messages.

04.03.2026 21:29 👍 2 🔁 0 💬 1 📌 0

the only thing i'm still not 100% sure of is if i want an alias `type AnyArray!(a) = exists (n : Nat). Array(n, a)`. (possibly with a different name...)

04.03.2026 21:29 👍 2 🔁 0 💬 1 📌 0

this literally has exactly the same representation as a concrete `Array(..., a)` and because vega supports full implicit existentials, you can just use the regular array functions (and in particular `checkBounds`) on existentials over arrays!
(this is like 90% of why i wanted existentials in vega)

04.03.2026 21:29 👍 3 🔁 0 💬 1 📌 0

if you don't statically know the length (like in most cases really), you can just use an existential, as in

filter : forall (n : Nat) a. (Array(n, a), a -> Bool) -> exists (m : Nat). Array(m, a)

04.03.2026 21:29 👍 3 🔁 0 💬 1 📌 0

but if you statically know that your indices are in bounds, you don't need a bounds check! (for example with `mapWithIndex : forall (n : Nat) a b. (Array(n,a), (Index n, a) -> b) -> Array(n, b)`

04.03.2026 21:29 👍 2 🔁 0 💬 1 📌 0

and where you can index it with a *total* function `index : forall (n : Nat) a. (Array(n, a), Index(n)) -> a`. (with Index(n) as [0,n) )
In the most general case, this moves the bounds check from the array to the index (with `checkBounds : forall (n : Nat). Int -> Array(n, a) -> Maybe (Index n)`).

04.03.2026 21:29 👍 2 🔁 0 💬 1 📌 0

i mostly thought of this in the context of vega's array API (that isn't implemented yet).
what's pretty unique about vega is that the default array is going to be a size indexed array where `[1,2,3]` has type `Array(3, Int)`...

04.03.2026 21:29 👍 9 🔁 0 💬 1 📌 0

and if something is *not* visibly a type alias, you can assume that it's generative! (as long as it's not a type family or similar i guess but you'd probably want the same syntax for those anyway)

04.03.2026 21:12 👍 6 🔁 0 💬 0 📌 0

if you see `sum : IntArray -> Int`, that doesn't tell you anything about what exactly you can pass in (e.g. an `Array(Int)`) or not, but if you see `sum : IntArray! -> Int` you at least know that you need to look up the definition of `IntArray` to find out!

04.03.2026 21:12 👍 5 🔁 0 💬 1 📌 0

the main problem with type aliases is that in order to understand code that uses them, you need to know what they're defined as.
but usually you don't even know that that's something you need to know because you don't know that your type is an alias.

04.03.2026 21:12 👍 5 🔁 0 💬 1 📌 0

weird PL syntax idea: maybe type aliases should have some special syntax to distinguish them from regular types? (something like `sum : IntArray! -> Int` with `type IntArray! = Array(Int)`)

04.03.2026 21:12 👍 9 🔁 0 💬 3 📌 1

oh that's a good point! java people sometimes spell out the type though (like `List#addAll(Collection)` vs `List#addAll(int, Collection)`)

03.03.2026 21:09 👍 3 🔁 0 💬 1 📌 0

it's so wild how i got into elm just after 0.19 released when everyone was still worried about the language changing too much too quickly and yet it's still in exactly the same state today

03.03.2026 14:27 👍 3 🔁 0 💬 1 📌 0

with text/bytesting the real issue (imo) is that Lazy{Text,ByteString} are just incorrectly named.
they're not just lazy versions of the regular types (whatever that even means), they're specifically pure Text/Byte *streams*.
like, they have wildly different complexities than the strict versions!

03.03.2026 11:04 👍 1 🔁 0 💬 1 📌 0

that's arguably HLS's (and Haddock's) fault though because ghc will always disambiguate them in error messages

idk I don't really mind it with vector (where I always use it as `Unboxed.Vector` or `Storable.Vector` anyway) but it's annoying with other libraries

03.03.2026 11:04 👍 1 🔁 0 💬 1 📌 0