Clarity on Extensible Record Type? #197
Replies: 5 comments 8 replies
-
Extensible records are a poorly documented feature in Elm so your questions are very valid. Here's what I learned so far:
Since you mentioned type inference I think it's easier to understand if you look at them from that perspective. Let's say you define this simple function: foo a =
a.bar + 1.5 Since type annotations are optional in Elm it needs to be able to infer the type of And that's where extensible records come in. When you say foo : { a | bar : Float } -> Float
foo a =
a.bar + 1.5 To understand why you need the variable name in there, you just need to consider the record update syntax: foo2 a =
{ a |
bar = a.bar + 1.5
} In this case, we are returning the same type that came in, but the only thing we know about it is that it should have at least a foo2 : { a | bar : Float } -> a
foo2 a =
{ a |
bar = a.bar + 1.5
} Without the type variable we wouldn't be able to express the relationship between the input and output types. I think this is all pretty logical. Things start to fall apart when you are using them in type aliases similar to generic types. As you pointed out the semantics there become blurry. In my opinion Elm should just ban that type of usage as it has no practical applicability and it's very confusing. But even if Elm doesn't we should probably ban it in Morphir. The only reason we haven't done so yet is that people never use it in business models, but banning it explicitly would be a much better approach. |
Beta Was this translation helpful? Give feedback.
-
Are you implementing type inference for the Morphir IR in Scala? If so, I think we should coordinate. We do have a type inferencer in Elm and to set expectations it took several months of effort to build it and it involved getting deep into understanding how the Haskell type inference works. It uses an optimized version of Hindley-Milner type inference and it took quite an effort to get it right. Also important to note that it's very different from how the Scala type inference works for example (which is why the Scala compiler often fails to infer the types for the generated code that we already type-checked on the Morphir side). Given the complexity I think it would worth investigating what effort it would take to port the Elm implementation rather than building one from scratch. Given that it's simple Elm code we might be able to use Morphir itself to do the porting for us. |
Beta Was this translation helpful? Give feedback.
-
I think the closest thing on the Scala side is existential types which were dropped in Scala 3. |
Beta Was this translation helpful? Give feedback.
-
First, I want to (vigorously!) second banning extensible record types in morphir-code (not sure if you mean only banning them there, or also on the back-end, but I'd support either.) The fact that no one uses them currently would argue in favor of banning them sooner rather than later, to me (i.e., before anyone starts.) The inferencer I'm working on really only has trouble with some particular niche cases around inferring extensible record types, and they seem to not fit the pattern of the type system in general. (The fact that one of my examples above breaks elm's compiler makes me think that.) I'm still unclear why in the typeIR ExtensibleRecords only take a name, rather than an actual type . At least in intermediate states, you might want to resolve that variable to an actual type, and have an ExtensibleRecordType representing that). For instance, if you have
And then somewhere in your code you recognize something as being a |
Beta Was this translation helpful? Give feedback.
-
I've been working on a design for such... I have a particular approach in mind that I've sketched out on paper, but I want to actual code it before over-promising anything (and between it not being a super high priority, and me being out on theoretical limb with the design, that's almost certainly an "In my own time" consideration.) I'll let you know if that process produces any good results. |
Beta Was this translation helpful? Give feedback.
-
Extensible Record Type has some oddities I'd like to better understand:
That
Full
isBase
extended byExtension
(i.e., the record type{name : String, number : Int}
, and that in general, when an ExtensibleRecord type is applied to a Record type it creates a Record type equal to the base type extended by the specified fields?If not, what is a better explanation?
If so, can someone explain why the IR wraps a
Name
rather than an actualType
? It seems like it should be structurally similar toList
,Tuple
, etc, where it has an "Inner" type (which might be aVariable
with aName
), but that generic could have concrete instantiations bound to a particular type. (The documentation also seems unclear on this, ashttps://package.elm-lang.org/packages/finos/morphir-elm/latest/Morphir-IR-Type#extensibleRecord
seems to describe exactly what I'd expect on the RHS of the==
, but all the code I've found only refers to ExtensibleRecord as wrapping a Name...)I'd also like to confirm my understanding that extensible record type does NOT imply that any actual polymorphism exists in Morphir - e.g., you cannot have a list of extensible records which all share a
name
field but have different other fields. Is that correct?Finally, I've had some issues exploring the semantics both in elm and morphir-elm (see finos/morphir-elm#1094 ). I want to check if my understanding of the following specific edge cases is correct:
someField
is an Int inFull
(This case is interesting because it means that Extension Record does not fit the pattern of other generics, i.e., being truly generic across any type... this case also behaves oddly in Elm, causing the Ellie compiler to break (it does not compile, but does not report an error), and gives a poorly-formed error in native elm:
For context, I'm working on a design for a type inferencing mechanism in morphir-scala, and most of where that hits stormy waters is around extensible records.
Beta Was this translation helpful? Give feedback.
All reactions