I realized a design problem with having one Arithmetic ability covering everything, instead of individual abilities like Addition and Division: backwards compatibility
if there's an Arithmetic ability, and all the functions are expressed in terms of Num (which is an alias for a | a supports Arithmetic) then that means the ability's required functions must not only be the basic arithmetic ones, but also others like mulChecked : Num a, Num a -> Result (Num a) [ Overflow ]*
that in turn means that if we want to add a new function like that to Num in the future, it has to be added to the ability too, which means every custom numeric type will become invalid because they won't implement that
(unless we also introduce the possibility of abilities having default implementations, but even then, that only works if the new operation happens to be expressible in terms of existing ones)
actually I guess there could still be Arithmetic, but maybe it only covers the basic arithmetic and comparison ops that have infix operators, like +, -, >, <, etc.
but then all the others, like addSaturated : Num a, Num a -> Num a would live in Num but outside the ability
so that would mean if I added a Complex type for complex numbers, I'd call Complex.addSaturated instead of Num.addSaturated, but I could still use +
and then if in the future Num introduced a new top-level function intended to be called fully-qualified (e.g. Num.whatever), that wouldn't affect the Arithmetic ability
so nothing would break
that might mean Num would have to become an opaque type, and Int an alias for it
and add would have to become Num.add : a, a -> a | a supports Arithmetic
Hmm, I guess this has something to do with why Haskell has a hierarchy of typeclasses that are based on mathematical features that different categories have (semiring, ring, monoid etc)
I think that's unrelated :big_smile:
a better example might be Rust's Add trait for addition
it's very granular!
ok, I figured out a design that seems nice - basically in order to support any of the arithmetic infix operators, you have to support (roughly) all of them, but you don't have to support any other operations.
the Num and Int types work the same way they do today, but the type signatures for the functions that infix operators desugar to look different - e.g. Num.add becomes add : a, a -> a | a supports Arithmetic, which seems reasonable since the docs for Arithmetic explain that Num is compatible with it
Last updated: Jun 16 2026 at 16:19 UTC