Open fmease opened 3 years ago
One thing to re-consider is the grammar: It might be worthwhile to parse field access as something "higher" than lower expressions
because requiring a Naked-Lower-Expression
instead of Lower-Expression
is odd and we'd need to parse it separately anyways (the parser for lower expressions automatically parses attributes i.e. no naked lower expressions).
The given example @A(@B hello)::field_
attaches @B
to the target and @A
to the lower expression field access. Weird.
With a different grammar, it might look like this: @A (@B hello::field_)
which is also kinda strange but at least consistent and
not an edge case anymore. But thinking about this, that one is even less intuitive. Hmm :/
Proposal accepted. Parsing implemented in 57fec137519eb98a443b75ba8c2c738f56141cc3.
Depends on/relates to #18.
Instead of the very verbose field projections which are namespaced under record constructors which in turn are namespaced under data types, utilize type-directed namespaces in the language.
This proposal adds a new syntactic and semantic form called a (field) projection or field access. Its grammar rule is
Naked-Lower-Expression "::" Identifier
(or#
instead of::
) and it is a lower expression. Examples:some.path.to::field_
,0::field_
(ill-typed),@A(@B hello)::field_
.Marking parameters of constructors as fields with the reserved symbol
::
makes this projection available for values created with this constructor. Example:Counter-example:
Initially, I did not want to add this feature (because of "m i n i m a l i s m") but I recognized that the current way of doing this is horrendous! I really like that we use a different symbol for this instead of "re-using"
.
for "static" name resolution. This allows us to provide better error messages for both invalid uses of.
and::
.The question remains if we should remove the old way of accessing fields or keep it as an alternative. I think we should throw it away as we cannot lower either one to the other, meaning more unnecessary complexity.
For reference, the current design dictates generating functions namespaced under the constructor. Taking the example from above, there would exist
Person.person.name
of typePerson -> Text
andPerson.person.age
of typePerson -> Nat
. So you'd have to write (oruse
)Person.person.name jane
forjane::name
.The advantage of the previous field projection design was that it enabled point-free style. Now, we need to write an explicit lambda to turn the projection into a first-class function:
(\p => p::name)
of typePerson -> Text
. That's not a big problem however: Just provide more syntactic sugar:(::field_)
to(\x => x::field_)
.Example: