Stream: beginners

Topic: Errors that highlight source of unification failure


view this post on Zulip Jonathan (Aug 21 2026 at 16:37):

I was scratching my head at the following error

The method execute! has the type:

    Query(sqlite, path), Str, List(Binding) => Try({}, err)
      where [
        sqlite.execute! : { bindings: List(Binding), path: path, query: Str } => Try({}, err),
        sqlite.i64 : Str -> Decoder(cols, stmt, I64, derr),
        sqlite.query_many! : { bindings: List({ name: Str, value: Value }), path: path, query: Str, rows: Decoder(cols, stmt, I64, derr) } => Try(List(I64), err),
      ]

But I need it to have the type:

    Query(sqlite, path), Str, List({ name: Str, value: [Bytes(List(U8)), Integer(I64), Null, Real(F64), String(I64)] }) -> _ret
      where [
        sqlite.execute! : { bindings: List(Binding), path: path, query: Str } => Try({}, err),
        sqlite.i64 : Str -> Decoder(cols, stmt, I64, derr),
        sqlite.query_many! : { bindings: List({ name: Str, value: Value }), path: path, query: Str, rows: Decoder(cols, stmt, I64, derr) } => Try(List(I64), err),
      ]

It took some time to realise that the cause for the error was that the list of bindings I supplied gave an I64 where the contents should have been a string:

    Query(sqlite, path), Str, List(Binding) => Try({}, err)
                                   ^^^^^^^
    ...

    Query(sqlite, path), Str, List({ name: Str, value: [Bytes(List(U8)), Integer(I64), Null, Real(F64), String(I64)] }) -> _ret
                                   ----------------------------------------------------------------------------^^^----
    ...

Having read roc errors for a bit, this case is a bit easier because the "need the type" side doesn't use the Bindings alias, writing List({ name: Str, value: [Bytes(List(U8)), Integer(I64), Null, Real(F64), String(I64)] }) instead, and so there must be at least one problem there. But in general I find it can be an interesting game of spot the difference, especially if you are relying on inference - and you tend to rely on inference when the signature gets too annoying to write, compounding the problem!

view this post on Zulip Jonathan (Aug 21 2026 at 16:38):

I seem to remember there might have been some errors that do add this, but it might have been nice if the core differences could be highlighted in the errors, in colours, bold, and/or underlined, whatever works.

view this post on Zulip Jonathan (Aug 21 2026 at 16:43):

It could take the form of a hint too:

Hint: at XXX:YY I was expecting a Str but got I64

Or some other method that shows the difference at a higher level of granularity, such as the difference between the type aliased to Binding and the record I supplied, rather than the zoomed in difference between the contents of my String(I64) and the expected String(Str). I'm not sure what the heuristic would be to determine that level, because it could be misleading.

view this post on Zulip Anton (Aug 21 2026 at 16:57):

I will make an issue for this, can you provide the source code that triggered the error @Jonathan?

view this post on Zulip Jonathan (Aug 21 2026 at 17:01):

I can provide a more minimal example unless you want the noise to test how it looks in practice?

view this post on Zulip Anton (Aug 21 2026 at 17:21):

unless you want the noise to test how it looks in practice

Full code is fine, it's mainly to check that the fix does what it needs to

view this post on Zulip Jonathan (Aug 21 2026 at 17:29):

Will do, thank you!

view this post on Zulip Jonathan (Aug 21 2026 at 17:47):

That should reproduce the same error.
PastedText.txt


Last updated: Sep 03 2026 at 15:16 UTC