I have a project with a lot of very similar but slightly different data types, so I’ve been making a lot of use of extensible records so that, for example, if I have several record types all of which have ids, I can use the same function (with a signature like List {record | id = Id } -> List {record | id = Id }
) for all of them for ordering them by id.
Sometimes stuff gets more complicated than that, though, and I’ve recently realized that a lot of the weird errors I’ve struggled with relating to extensible records have been connected to using them in type aliases. I’ve occasionally gotten bewildering errors where I pass something with a type of CoolType
that I think is something like { info : Info, otherStuff: OtherStuff }
but I get errors that look like:
This value is a:
CoolType
But `myFunction` needs the 1st argument to be:
{ otherStuff: OtherStuff }
And I find myself thinking, “But CoolType
is { info : Info, otherStuff: OtherStuff }
, not just { otherStuff: OtherStuff }
???”
For example, there’s a type in my code that looks like this:
type alias MoveConfig creation =
{ moving : { creation | info : InfoFields }
, destination : Position { creation | info : InfoFields }
, startingList : List { creation | info : InfoFields }
}
and my instinct in writing it was "this is saying that the creation
type should have a field called info
with a type of InfoFields
. That is, if I then declare a function of type moveItem : MoveConfig MyType -> List MyType
, then MyType
is required to have an info
field of type InfoFields
. But with errors like the above, I’m thinking maybe there’s something more subtle going on.
I’m not sure if I’m making this clear, because I don’t understand it well enough myself to narrow it down to a working SSCCE, but hopefully it’s clear enough for any other people who may have seen similar things?
I realized recently that I could solve most of the issues I’ve been having by restricting the use of extensible records to function signatures, and basically never using them in type aliases. So far, this has worked to eliminate the weird type errors I had been seeing.
Two questions:
First, has anyone else seen errors like the above and if so, are you able to explain what’s happening in them?
Second, does a practice of “just never use extensible records in anything other than function signatures” seem reasonable? Does it preclude any important or useful ways of being able to write code in Elm?