New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Linear types #111
Linear types #111
Conversation
With great inputs from @facundominguez, @mboes, and @jyp
The rendered link should point to https://github.com/tweag/ghc-proposals/blob/linear-types2/proposals/0000-linear-types.rst. It currently points at the previous proposal. |
@cocreature fixed. Thanks! |
This proposal points out the annoyance of CPS when arguing against affine types, but then forces CPS on us (as before) for many use-cases by not doing linear kinds. |
The removal of the zero multiplicity seems problematic because it basically forces the situation where type variables cannot stand for zeroes to preserve backward compatibility when a zero multiplicity gets added. I see this behavior as surprising and inconsistent with how type variables behave in general. Also, it prevents one from doing things one might expect to be able to do like composing functions with zero multiplicity. It seems better to me to take the extra complexity now for better future compatibility. |
i'm not sure how this revision actually resolves the concerns and issues raised in the previous discussion, especially if the only substantive technical change is the dropping of the zero multiplicity... likewise, i see zero mention of how to handle possibly mixed multiplicity fields in data type definitions, which is lacking from the associated popl paper too :( |
On glance, I think it does resolve the issues I raised. It acknowledges the issues with exceptions, describes a semantics that is correct with regards to the proposed behavior (which the old one was not), and provides a discussion of the tradeoffs. So on a technical front I see it as an advance. People may disagree with the proposal for a variety of reasons, but it appears "correct" in the sense that it describes accurately a change, its semantics, and its consequences, so it is a much improved starting point for discussion. |
Some of the discussion around record types confuses me, because it seems to ONLY allow single field records as linear. I actually have a large number of resource modeling examples where I want mixed multiplicity records. In my own work, the way to reconcile the tension here is to have unboxed tuples be enriched with per position multiplicity consider data LinearFileHandle = LH {myHandle ::_1 C_Handle, filePath ::_omega String} this describes a perfectly reasonable pattern where i want to be able to share the path info throughout a computation, but guarantee linearity (errrm, affinity in this proposal i suppose) for the underlying handle. with unboxed tuples i can uniformly describe both the Direct style unpacking AND the cps eliminator (i'll pretend for now that unboxed tuples are also telescopes so i can use type annotation notation to indicate multiplicities) directUnpackHandle :: (# _ ::_1 LinearFileHandle #) -> (# _ ::_1 C_Handle , ::_omega String #)
let (# ch, filepathName #) = directUnpackHandle myLinearHandle
in
-- stuff using ch and file handle
the cps version is even simpler/worse :)
you really really need unboxed tuples with varying multiplicities if you want to directly write these things instead of pushign them into case. Likewise.... I dont see a clean treatment / clear exposition of how to define any nontrivial datatypes, even records or tuples, which have mixed multiplicities in this proposal... and I think those are very important for usability. Perhaps i'm overlooking something, but this does seem to be a serious gap :( |
an alternative (but I think ultimately more fragile / complicated approach) to mixed linearity records is whats done in the cogent language out of nicta/data61, where they keep track of the partial projected-ness of a linear record and its fields. I also think this expressivness in datatypes is crucial for actually supporting meaningful direct / monadic style APIs a good example of this {edit: this point of expressivness} from another source is the discussion in pages 8 and 9 of this paper https://people.mpi-sws.org/~dg/papers/aff-know.pdf by deepak garg which uses linear typed programs to describe authorization, and the underlying issue there is the lack of such "tuples", so they circumvent the issue by making the troubling operation a primitive in their logic/programming language. |
I would like to make sure that i can model something like that example from deepak garg in a linear logical haskell programming tool |
Thanks for getting out a more comprehensive version of this proposal. I am glad to see the zero multiplicity gone. I agree with the concerns @cartazio expressed about not being able to express tuples of mixed multiplicity. Changing unboxed tuples to somehow linearity-polymorphic would be a heavy-handed, breaking change since it would endow unboxed tuples with additional type arguments for multiplicities. I would like to suggest a simpler solution: adding an additional unary unboxed tuple whose data constructor is non-linear. This is a little hard to discuss because GHC currently doesn't have an exposed name for this data constructor, but it's internally called
Now, consider the example that @cartazio wrote with the fictitious multiplicity designations as:
If I understand the intent of this correction, I believe it could be expressed with
Maybe |
~~~~~~~~~~ | ||
|
||
We say that a function ``f`` is *linear* when ``f u`` is consumed | ||
exactly once implies that ``u`` is *consumed exactly once* (defined |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
repetition of "consumed exactly once"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry. I must have missed something. But I don't see a repetition here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
NM, I misread it.
1 * x = x | ||
x * 1 = 1 | ||
ω * ω = ω | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These rules imply x * y = y
, surely this is wrong?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right. The second one was supposed to be x*1=x
(1 is neutral).
- Fix this.
@andrewthad your proposed encoding would be at least spiritually, in that you're adding the linear logical exponential as but this actually raises an important point: unboxed tuples do not exist after type erasure, and to quote the runtime rep data type thats now part of the kind system https://hackage.haskell.org/package/ghc-prim-0.5.1.1/docs/GHC-Types.html TupleRep [RuntimeRep] -- | An unboxed tuple of the given reps we could easily enrich this to TupleRep [(Usage,RuntimeRep)] -- An unboxed tuple of the given reps and their Usage (linear/omega) and have a typing rule that an unboxed tuple is a "linear" value wrt how you're allowed to eliminate it if it has any linear fields. this would greatly improve the expressivity of the current proposal I think. my point about erasure is perhaps a subtle one: unboxed tuples are exactly the calling convention / abi for haskell function calls and returns wrt register placement, they never exist on the heap! (@andrewthad so i guess i'm ultimately disagreeing with you somewhat :) ) |
@cartazio the "usage" thing looks good, but if we do that, lets just go full linear kinds (so that the type of the list elements once again matches the (uncurried) parameter type of Contrary to the proposals and paper, Rust also has a linear (sub)kinds, and not uniqueness types. (It's immutable and mutable reference types exhibit a uniqueness-types-like subsumption relation, but this is a library/axiom phenomenon, not a fundamental property of the language itself.) I'm very used to the full power of this in Rust, and it would be shame to have something inferior in Haskell. We can still perhaps do linear arrows as a sugar / convenience on top if we really want. I don't buy the integrating-with-existing-code argument. Many of use want to make unlifted/unboxed code more idiomatic and ergonomic, so we're already going to fight analogous battles related to other possible additional parameters of TYPE. |
@cartazio What you describe is the more heavy-handed approach that I was wary of. I don't particularly like the idea of redefining
Side note: my intent was that |
With great inputs from @facundominguez, @mboes, and @jyp
Thanks for all your comments! Let me try to provide answers to every question. @gbaz "correct" is good. But let's aim for "complete" as well. Don't hesitate to point out to what's missing or unclear. And if you have ideas to fill in the unresolved bits: please share! @Saagar-A Dropping the 0 multiplicity was suggested by @andrewthad in #91 and after internal discussion, we dropped it from the proposal because it adds significant complexity, the "right way" to add to add the 0 multiplicity is still unclear, and we don't actually know for sure that we will need the 0. So what happens if we add it now, in a clunky way, and discover later that it was never useful in the first place? I would be uncool. If we need to add the 0 multiplicity later, all the strategies which were proposed in #91 would still apply, maybe some of them would feel less palatable after the fact, but we would have concrete examples to work from! @cartazio @andrewthad The proposal specifically adds data types with mixed-multiplicity constructor. Also the paper. There is no syntax for non-purely linear record constructors. But they are also discussed in the proposal. There is no technical difficulty, we simply don't have a syntax yet. (though thank you for bringing this up, I just realised that I didn't specify record patterns in the proposal) I believe the the proposal also mentions mixed-multiplicity unboxed tuples: I believe them to be needed in the implementation (for the interested parties: I appear to need them to properly perform the worker/wrapper split for strict functions), but I don't have a syntax for them in the surface language. This could be solved elegantly by the UnliftedDataTypes proposal. In the meantime, a single unlifted 1-uple of multiplicity ω (a consistent name for which would be
|
@aspiwack Thanks for the response. I agree that the proposal is already clear on data types with mixed-multiplicity constructors. I had missed the discussion of mixed multiplicity unboxed tuples in the proposals in the proposal. For the interested parties, it reads:
It would be helpful if this were reiterated in Section 1.2.8 Unboxed Data Types. Also, the UnliftedDataTypes proposal that you reference doesn't actually give us what we want here. It allows users to define more inhabitants of kind
|
the only two mentions i see are a)
which i assume is a typo and should instead b e
b)
What is the semantics of the case (a) in the notation of case (b) my expectation is that would be equivalent to something along the lines of (with currying removed to clarity)
phrased differently, for
I do think that putting the linearity info on the arrows of the data types instead of the fields of the datatype constructors does confuse reading them, since its how you construct the datatype determines its ultimate usage in the application, right? i guess i'm just really really wanting user visible unboxed tuples with use annotations (which maintaining well typed worker wrapper will apparently need?) and a cleaner / more explicit notation for how to read mixed usage annotations per field in datatypes. in purely linear / linear logical code, this doesn't matter, because linearity just composes everything! but our programming languages/reality live in world of both eternal mathematical truths and resources, and making sure talking about those cleanly is important for end users. |
for clarity i'm attaching the remarks from the depak garg paper that I think are relevant and the full paper |
Also, the paper implies we'd need to use GADT syntax for virtually all data types to support the linear kind, but I don't see why we can't just infer it for non-GADT syntax (again as Rust does) Code without -XLinearKinds would see any linear types, and would see all multiplicity-polymorphism specialized away (to Omega). |
.... you totally dont need GADT syntax, at least if you allow record field style annotations on the fields, as in their strawman syntax that they indicated isn't currently planned. (but is also a good example of not needing linear function spaces to define the types) |
@Ericson2314 i agree, gadt syntax shouldn't/needn't be required, it seems like a case of pushign the complexity into a small corner, which I think actually increases the complexity. In my experiences, a curried linear function arrow is actually one of the most complex approaches you can do for linear logic. in the following notation i use
lets call this pattern of linear function LinearFunctionSpaceNotation (and assume i can specialize this to LinearConstructorNotation (which kinda looks like a multi category?)
to exactly and CLEARLY describe the typing rules/type behavior of a single data constructor explicitly and for a record or other constructor with multiple fields, i can do the opposite (lets call this LinearProjectionNotation)
how do i write / encode these in the proposal today, or what syntax would be needed to be able to write general things of the pattern of LinearFunctionSpaceNotation . With that level of expressivity (ignoring the fact that this in its full generality requires some handling of type quantifiers/generics such as perhaps seen in the age old TypesAreCallingConventions paper https://www.microsoft.com/en-us/research/publication/types-are-calling-conventions/ https://www.microsoft.com/en-us/research/wp-content/uploads/2016/08/tacc-hs09.pdf), I can actually encode ALL the standard connectives of classical linear logic in a functional programming setting, and do some really cool modelling. TL;DR with the current proposal,how would i encode/emulate what i'm calling LinearFunctionSpaces? this has serious impacts on modeling expressivity Is the datatype facility flexible enough to allow me to model Authorization data types with delegation?This actually raises in turn an interesting/challenging question: can / should users be able to define sum type with arbitrarily varying usage choices per constructor that come up with describing interesting resources? consider using linear logic to model some sort of enterprise / business authorization where you have "X is approved to do Y", "X can approve their choice of Z to do Y" and "X can delegate to new people Z (who may or may not be able to delegate futher) approving their choice of person A to do Y " this is a pretty simple example of more complicated authorization systems that come up in practice, and does require some support from the data type facility. This post is getting a tad long so i'll write up some modelling examples and share them later today. :) |
Just reading through the proposal and comments now. Several thoughts:
|
proposals/0000-linear-types.rst
Outdated
0 * _ = 0 | ||
_ * 0 = 0 | ||
1 * x = x | ||
x * 1 = 1 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as above, should be x * 1 = x
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indeed
- Fix this
to build on @goldfirere 's point: things i'd like to see this proposal address
what I can provide to help clarify my asks
|
Callan: any pattern guard expression on a nontrivial data structure that’s
linear will consume it. It gets consumed by the guard and then it can’t be
used in the body.
Dup in the desugaring is like “borrowing” in rust. But a semantics that
actually allows tail calls and or bottoms.
…On Fri, Feb 14, 2020 at 2:15 PM Callan McGill ***@***.***> wrote:
@cartazio <https://github.com/cartazio> : Would you mind giving an
explicit example for what could go wrong with pattern guards or where you
envision needing a safe dup operation here?
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#111?email_source=notifications&email_token=AAABBQS3W6WNINYHC2KVEUTRC3UV5A5CNFSM4EQO6C2KYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEL2DNCY#issuecomment-586430091>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AAABBQUWV2VXQYJ463INCR3RC3UV5ANCNFSM4EQO6C2A>
.
|
Just to check I am following, if I were to have the following code: data Nat where
Zero :: Nat
Succ :: Nat .-> Nat
isEven :: Nat .-> Bool
isEven Zero = True
isEven (Succ n) = not . isEven $ n
roundUpToEven :: (Nat .-> Nat)
roundUpToEven n | isEven n = n
| otherwise = Succ n The claim is that because |
That’s also true about ordinary guards, or plain I’m sorry, but this line of discussion is absurd. When you initially started complaining about this, you made some very serious claims, apparently believing this proposal was fundamentally flawed in some deep way. Now, a week later, the best explanation you can provide is a vague allusion to something wrong with pattern guards? You posted your complaints on this proposal, on the libraries and ghc-devs mailing lists, on r/haskell, and on twitter. You’ve made an awful lot of noise for a quibble about technical minutia that belongs nowhere except as a comment (with concrete examples!) on this proposal. If you can’t back your (frankly rather insulting) claims up, then this incident is so unprofessional that I question whether your membership on the CLC is appropriate. |
@Boarders exactly! thanks for helping explicate. a desugaring from pattern guards into core's case would need to put a |
@lexi-lambda, with all due respect, it would be most professional to keep this discussion purely technical and refrain from personal attacks. It is already heated enough. I do believe that whenever people raise questions (whatever stupid) or make claims (whatever bold), we should discuss their technical merits and not persons themselves or their membership in third-party organisations. |
Isn't this is the expected behavior of a linear type system? To preserve the linear use property, you would want Having some sort of convenience for using guards might be useful down the line, but that seems like a separate issue. |
Most systems people use allow some form of “borrow ”
Or auto generated dupe to allow predicates. I’ll dig up references on the
latter. I’m not sure if they’re written out in any thing aside from folk
lore / private communications in this area.
For vanilla ifs you can kinda do this rewriting partially by hand with an
extra let to help out with the dupe , but pattern guards in pattern
matching either via function definition or in case expressions basically
would need to be hand desugared and these extra let’s between the case and
the pattern guard predicates that check the rhs would be needed.
Needing to manually desugar pattern guards to get nontrivial programs /
libraries adapted to the extension seems like a huge amount of work.
Pattern guards a very common / core part of Haskell programming.
For those who want really meticulous rigorous expositions that spell out
choices , is that’s gonna take some time to finish cause it’s not my day
job, and my style of thinking requires my friendly collaborators to give me
a good feedback look for what most folks consider clear and concrete. I
tend to find abstraction concrete and concrete abstruse. So be patient.
Everyone here wants nice things. It’s just we’re not agreeing on the path
and consequences of choices to a goal. Not all of us have mutually
compatible communication styles but have overlapping long term interests we
aggressively care about but think about differently. Sometimes this can
feel like conflict. But at the end we should always to assume good faith
in the assumption that we all want a nice end state that makes our tools
and ability to build great software / software tools
I get very impassioned and aggressive sometimes around ideas and goals I
care about. I like to think I’ve gotten more constructive about directing
that in recent years.
Likewise, people literally think differently. (Allegedly there are people
who are unable to have an internal monologue of words without actually
vocalizing their thoughts?!). I generally have a style of wholes systems
thinking where I see a path to an end state and or the consequences of
different paths , but it takes a long time for me to translate that into
the communication styles that other folks digest easily. Which makes me
really appreciate the folks with who I can collab with because then the
whole process happens much much faster.
For those who want me to explain and concretize some of my points in the
ways they best engage with, I respect that but then you need to respect
that it’s gonna happen In a time scale That isn’t some slap fight. The
goal here is nice things and mutual education. And compiler patches. And
examples. And maybe a cool paper or two. For fun or for professional
reasons.
Happily I have some lovely collaborators who wind up helping me translate
These things into clearer forms.
…On Fri, Feb 14, 2020 at 5:50 PM David Menendez ***@***.***> wrote:
Callan: any pattern guard expression on a nontrivial data structure that’s
linear will consume it. It gets consumed by the guard and then it can’t be
used in the body.
Isn't this is the expected behavior of a linear type system? To preserve
the linear use property, you would want T .-> (Bool, T) rather than T ->
Bool.
Having some sort of convenience for using guards might be useful down the
line, but that seems like a separate issue.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#111?email_source=notifications&email_token=AAABBQSBMR5NM6NLZJVCG6LRC4N4VA5CNFSM4EQO6C2KYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEL2WYNA#issuecomment-586509364>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AAABBQUOMK7AXON6SR4HJJDRC4N4VANCNFSM4EQO6C2A>
.
|
I can give a good motivation for
This forces the handler to free exactly the resources that occur as free variables in the action. It might free (or try to use) already freed resources but since they have to be tracked globally anyway it's simple to make that idempotent and raise a new exception respectively. I did actually try to make this work using the More generally this sort of function type fills a similar role to laziness - it lets you write control flow as functions. Losing this capability in linear code really hurts usability in my experience. |
@Tarmean well said and thanks for saying it in your own words (better than I have tried in the past on this family of proposals) theres also a realted issues that totally valid linear logical analogues of the Exactly! This is one example I was thinking of but explaining poorly. Thank you for helping articulate this!
|
@monoidal #111 (comment) was the typing rule i mentioend a while ago for sketching out Choice/Generalized join points, will have to stare at it again to make sure its the correct one (it and other design feedbacks / discussions got lost in githubs "hide all the things") |
Currently, a join point is simply a If I understand you correctly, you have an alternative vision and would like to change join points in Haskell to have more branches. Fine, but in that case please prepare a document with specific changes you'd like to make. The comment you have linked to is by your own admission not in a workable state ("fuzzy type rules", "are reachable patterns from a common type t? -- not sure about this side condition here", "will have to stare at it again to make sure its the correct one"). Perhaps, we could add codata declarations to Haskell in the future, and then we could have e.g. |
Co-Authored-By: Max Desiatov <max@desiatov.com>
I have merged this proposal, given that it is conditionally accepted (and has been for some time: #111 (comment)). All remaining conditions (now written in the proposal itself, so they are not lost) are implementation oriented and should not affect the text of the proposal. Any changes one might want to present against this proposal should be in the form of a new PR, either as an amendment to this proposal or a fresh proposal. |
This is the first step towards implementation of the linear types proposal (ghc-proposals/ghc-proposals#111). It features * A language extension -XLinearTypes * Syntax for linear functions in the surface language * Linearity checking in Core Lint, enabled with -dlinear-core-lint * Core-to-core passes are mostly compatible with linearity * Fields in a data type can be linear or unrestricted; linear fields have multiplicity-polymorphic constructors. If -XLinearTypes is disabled, the GADT syntax defaults to linear fields The following items are not yet supported: * a # m -> b syntax (only prefix FUN is supported for now) * Full multiplicity inference (multiplicities are really only checked) * Decent linearity error messages * Linear let, where, and case expressions in the surface language (each of these currently introduce the unrestricted variant) * Multiplicity-parametric fields * Syntax for annotating lambda-bound or let-bound with a multiplicity * Syntax for non-linear/multiple-field-multiplicity records * Linear projections for records with a single linear field * Linear pattern synonyms * Multiplicity coercions (test LinearPolyType) A high-level description can be found at https://ghc.haskell.org/trac/ghc/wiki/LinearTypes/Implementation Following the link above you will find a description of the changes made to Core. This commit has been authored by * Richard Eisenberg * Krzysztof Gogolewski * Matthew Pickering * Arnaud Spiwack With contributions from: * Mark Barbone * Alexander Vershilov Updates haddock submodule.
This is the first step towards implementation of the linear types proposal (ghc-proposals/ghc-proposals#111). It features * A language extension -XLinearTypes * Syntax for linear functions in the surface language * Linearity checking in Core Lint, enabled with -dlinear-core-lint * Core-to-core passes are mostly compatible with linearity * Fields in a data type can be linear or unrestricted; linear fields have multiplicity-polymorphic constructors. If -XLinearTypes is disabled, the GADT syntax defaults to linear fields The following items are not yet supported: * a # m -> b syntax (only prefix FUN is supported for now) * Full multiplicity inference (multiplicities are really only checked) * Decent linearity error messages * Linear let, where, and case expressions in the surface language (each of these currently introduce the unrestricted variant) * Multiplicity-parametric fields * Syntax for annotating lambda-bound or let-bound with a multiplicity * Syntax for non-linear/multiple-field-multiplicity records * Linear projections for records with a single linear field * Linear pattern synonyms * Multiplicity coercions (test LinearPolyType) A high-level description can be found at https://ghc.haskell.org/trac/ghc/wiki/LinearTypes/Implementation Following the link above you will find a description of the changes made to Core. This commit has been authored by * Richard Eisenberg * Krzysztof Gogolewski * Matthew Pickering * Arnaud Spiwack With contributions from: * Mark Barbone * Alexander Vershilov Updates haddock submodule.
This is the first step towards implementation of the linear types proposal (ghc-proposals/ghc-proposals#111). It features * A language extension -XLinearTypes * Syntax for linear functions in the surface language * Linearity checking in Core Lint, enabled with -dlinear-core-lint * Core-to-core passes are mostly compatible with linearity * Fields in a data type can be linear or unrestricted; linear fields have multiplicity-polymorphic constructors. If -XLinearTypes is disabled, the GADT syntax defaults to linear fields The following items are not yet supported: * a # m -> b syntax (only prefix FUN is supported for now) * Full multiplicity inference (multiplicities are really only checked) * Decent linearity error messages * Linear let, where, and case expressions in the surface language (each of these currently introduce the unrestricted variant) * Multiplicity-parametric fields * Syntax for annotating lambda-bound or let-bound with a multiplicity * Syntax for non-linear/multiple-field-multiplicity records * Linear projections for records with a single linear field * Linear pattern synonyms * Multiplicity coercions (test LinearPolyType) A high-level description can be found at https://ghc.haskell.org/trac/ghc/wiki/LinearTypes/Implementation Following the link above you will find a description of the changes made to Core. This commit has been authored by * Richard Eisenberg * Krzysztof Gogolewski * Matthew Pickering * Arnaud Spiwack With contributions from: * Mark Barbone * Alexander Vershilov Updates haddock submodule.
The proposal has been accepted; the following discussion is mostly of historic interest.
This proposal introduces a notion of linear function to GHC. Linear functions are regular functions that guarantee that they will use their argument exactly once. Whether a function f is linear or not is called the multiplicity of f. We propose a new language extension,
-XLinearTypes
. When turned on, the user can enforce a given multiplicity for f using a type annotation.rendered
This proposal has already been through one round of review. If you are new to this, you don't need to read the conversation there: it has been integrated into this newer version of the proposal. For a full understanding of the proposal, reading the companion article is recommended. For a bird's eye view of the proposal, you can browse the wiki page.
If you already read the previous version of the proposal, here is a summary of the main changes:
By @aspiwack, @facundominguez, @mboes, @jyp and @simonpj
Ongoing discussion with the committee