I know very little about compilers and type-checkers, so this might be obvious, but would it be possible for the compiler to check this pattern match for exhaustiveness without the user supplying the default case _ -> crash
? I believe a U8 can only contain numbers 0 to 63 and there's no other values like a NaN
value like for floats. I admit this is a pretty rare situation, so I understand if it's not in scope, and I imagine it's the kind of thing that could kill compiler performance.
# Convert a byte, represented as a U8 to a list of (big-endian) bits, represented as a list of bools.
byteToBits : U8 -> List Bool
byteToBits = \byte ->
when byte is
0 -> [Bool.false, Bool.false, Bool.false, Bool.false, Bool.false, Bool.false]
1 -> [Bool.false, Bool.false, Bool.false, Bool.false, Bool.false, Bool.true]
2 -> [Bool.false, Bool.false, Bool.false, Bool.false, Bool.true, Bool.false]
3 -> [Bool.false, Bool.false, Bool.false, Bool.false, Bool.true, Bool.true]
4 -> [Bool.false, Bool.false, Bool.false, Bool.true, Bool.false, Bool.false]
5 -> [Bool.false, Bool.false, Bool.false, Bool.true, Bool.false, Bool.true]
6 -> [Bool.false, Bool.false, Bool.false, Bool.true, Bool.true, Bool.false]
7 -> [Bool.false, Bool.false, Bool.false, Bool.true, Bool.true, Bool.true]
8 -> [Bool.false, Bool.false, Bool.true, Bool.false, Bool.false, Bool.false]
9 -> [Bool.false, Bool.false, Bool.true, Bool.false, Bool.false, Bool.true]
10 -> [Bool.false, Bool.false, Bool.true, Bool.false, Bool.true, Bool.false]
11 -> [Bool.false, Bool.false, Bool.true, Bool.false, Bool.true, Bool.true]
12 -> [Bool.false, Bool.false, Bool.true, Bool.true, Bool.false, Bool.false]
13 -> [Bool.false, Bool.false, Bool.true, Bool.true, Bool.false, Bool.true]
14 -> [Bool.false, Bool.false, Bool.true, Bool.true, Bool.true, Bool.false]
15 -> [Bool.false, Bool.false, Bool.true, Bool.true, Bool.true, Bool.true]
16 -> [Bool.false, Bool.true, Bool.false, Bool.false, Bool.false, Bool.false]
17 -> [Bool.false, Bool.true, Bool.false, Bool.false, Bool.false, Bool.true]
18 -> [Bool.false, Bool.true, Bool.false, Bool.false, Bool.true, Bool.false]
19 -> [Bool.false, Bool.true, Bool.false, Bool.false, Bool.true, Bool.true]
20 -> [Bool.false, Bool.true, Bool.false, Bool.true, Bool.false, Bool.false]
21 -> [Bool.false, Bool.true, Bool.false, Bool.true, Bool.false, Bool.true]
22 -> [Bool.false, Bool.true, Bool.false, Bool.true, Bool.true, Bool.false]
23 -> [Bool.false, Bool.true, Bool.false, Bool.true, Bool.true, Bool.true]
24 -> [Bool.false, Bool.true, Bool.true, Bool.false, Bool.false, Bool.false]
25 -> [Bool.false, Bool.true, Bool.true, Bool.false, Bool.false, Bool.true]
26 -> [Bool.false, Bool.true, Bool.true, Bool.false, Bool.true, Bool.false]
27 -> [Bool.false, Bool.true, Bool.true, Bool.false, Bool.true, Bool.true]
28 -> [Bool.false, Bool.true, Bool.true, Bool.true, Bool.false, Bool.false]
29 -> [Bool.false, Bool.true, Bool.true, Bool.true, Bool.false, Bool.true]
30 -> [Bool.false, Bool.true, Bool.true, Bool.true, Bool.true, Bool.false]
31 -> [Bool.false, Bool.true, Bool.true, Bool.true, Bool.true, Bool.true]
32 -> [Bool.true, Bool.false, Bool.false, Bool.false, Bool.false, Bool.false]
33 -> [Bool.true, Bool.false, Bool.false, Bool.false, Bool.false, Bool.true]
34 -> [Bool.true, Bool.false, Bool.false, Bool.false, Bool.true, Bool.false]
35 -> [Bool.true, Bool.false, Bool.false, Bool.false, Bool.true, Bool.true]
36 -> [Bool.true, Bool.false, Bool.false, Bool.true, Bool.false, Bool.false]
37 -> [Bool.true, Bool.false, Bool.false, Bool.true, Bool.false, Bool.true]
38 -> [Bool.true, Bool.false, Bool.false, Bool.true, Bool.true, Bool.false]
39 -> [Bool.true, Bool.false, Bool.false, Bool.true, Bool.true, Bool.true]
40 -> [Bool.true, Bool.false, Bool.true, Bool.false, Bool.false, Bool.false]
41 -> [Bool.true, Bool.false, Bool.true, Bool.false, Bool.false, Bool.true]
42 -> [Bool.true, Bool.false, Bool.true, Bool.false, Bool.true, Bool.false]
43 -> [Bool.true, Bool.false, Bool.true, Bool.false, Bool.true, Bool.true]
44 -> [Bool.true, Bool.false, Bool.true, Bool.true, Bool.false, Bool.false]
45 -> [Bool.true, Bool.false, Bool.true, Bool.true, Bool.false, Bool.true]
46 -> [Bool.true, Bool.false, Bool.true, Bool.true, Bool.true, Bool.false]
47 -> [Bool.true, Bool.false, Bool.true, Bool.true, Bool.true, Bool.true]
48 -> [Bool.true, Bool.true, Bool.false, Bool.false, Bool.false, Bool.false]
49 -> [Bool.true, Bool.true, Bool.false, Bool.false, Bool.false, Bool.true]
50 -> [Bool.true, Bool.true, Bool.false, Bool.false, Bool.true, Bool.false]
51 -> [Bool.true, Bool.true, Bool.false, Bool.false, Bool.true, Bool.true]
52 -> [Bool.true, Bool.true, Bool.false, Bool.true, Bool.false, Bool.false]
53 -> [Bool.true, Bool.true, Bool.false, Bool.true, Bool.false, Bool.true]
54 -> [Bool.true, Bool.true, Bool.false, Bool.true, Bool.true, Bool.false]
55 -> [Bool.true, Bool.true, Bool.false, Bool.true, Bool.true, Bool.true]
56 -> [Bool.true, Bool.true, Bool.true, Bool.false, Bool.false, Bool.false]
57 -> [Bool.true, Bool.true, Bool.true, Bool.false, Bool.false, Bool.true]
58 -> [Bool.true, Bool.true, Bool.true, Bool.false, Bool.true, Bool.false]
59 -> [Bool.true, Bool.true, Bool.true, Bool.false, Bool.true, Bool.true]
60 -> [Bool.true, Bool.true, Bool.true, Bool.true, Bool.false, Bool.false]
61 -> [Bool.true, Bool.true, Bool.true, Bool.true, Bool.false, Bool.true]
62 -> [Bool.true, Bool.true, Bool.true, Bool.true, Bool.true, Bool.false]
63 -> [Bool.true, Bool.true, Bool.true, Bool.true, Bool.true, Bool.true]
_ -> crash "This can never happen because I have listed every possible U8 value."
U8 is 0 to 255
I think if you listed all 256 values, it should be exhaustive and not need _ ->
, but I have never tested
Ah! Thank you! Had a lapse of memory there!
Hannes has marked this topic as resolved.
By the way, I just added the missing cases, so now the pattern match is on all integers from 0 to 255 and it still asks me to add the default case
Brendan Hansknecht said:
I think if you listed all 256 values, it should be exhaustive and not need
_ ->
, but I have never tested
I think in theory that's true, but in practice I don't think we actually check this at the moment :big_smile:
Richard Feldman has marked this topic as unresolved.
I'm pretty sure for string and number literals we just treat them as "can never be exhaustive"
If you want this kind of behaviour you would have to create a tag union with 256 tags.
If I wanted to do that, I'd probably open up some REPL and get it to print out all of those numbers, then copy it into a .roc file and do some multi-cursor editing.
It feels like this could be a slippery slope, specially with the concept of Nat
which as far as I understand it is CPU-architecture dependent :thinking:
If I understand correctly, if you find yourself doing when someNumber is 1 -> this; 2 -> that; 3 -> otherThing
then you might be in need of domain-oriented tags which give meaningful domain names to what 1
, 2
or 3
mean.
Anything that is working in the realm of having to exaustive pattern match U8
or I8
seems to be more of a formula/function waiting to be discovered
hmm, so in rust they have 1..24
patterns, which make it much easier to match exhaustively on numeric types
Do we have such a pattern in roc?
(my statement above about a function waiting to be discovered did make me curious "okay, so how would I implement such function in roc?"
I came up with this, I wonder if there are more ideomatic ways to accomplish what I am doing here. I feel awkward about the {} |> List.repeat bitsToReturn
but I'm not sure of a better way to accomplish a "while loop")
byteToBits : U8 -> Str
byteToBits = \byte ->
bitsToReturn = 8
{}
|> List.repeat bitsToReturn
|> List.walk
(List.withCapacity bitsToReturn, byte)
(\(bits, remaining), {} -> (bits |> List.append (remaining % 2), remaining // 2))
|> (\(bits, _) -> bits |> List.reverse |> List.map Num.toStr |> Str.joinWith "")
## ── TESTS ────────────────────────────────────────────────────────────────────
## Tests for byteToBits
expect
expected = [
(0u8, "00000000"),
(1u8, "00000001"),
(10u8, "00001010"),
(255u8, "11111111"),
]
actually = expected |> List.map (\(byte, _) -> (byte, byte |> byteToBits))
expected == actually
Fábio Beirão said:
Do we have such a pattern in roc?
we don't currently, but it seems like a reasonable thing to bring up in #ideas!
Last updated: Jul 06 2025 at 12:14 UTC