Open-source project
ghc-proposals/ghc-proposals avatar
ghc-proposals/ghc-proposals

ghc-proposals: how a change to the Haskell language gets written down

Proposed compiler and language changes for GHC and GHC/Haskell

708 stars279 forksPythonLicense varies

At a glance

What is it?
The ghc-proposals repository holds the formal proposals that change the Glasgow Haskell Compiler and the language it accepts, each one reviewed by a shepherd and decided by the GHC Steering Committee. It suits Haskell developers who want to see why a language change exists, and it is not a place to propose changes casually.
Who is it for?
ghc-proposals is the place to read before writing Haskell code that depends on a language feature, because it holds the specification of a change from the moment it is proposed to the moment it is implemented, including the reasoning and the objections, and a proposal is the only route to a decision on a language or compiler change. It is the wrong tool for a bug fix, a core library change or a plugin API change, all of which the project documentation routes elsewhere.
Can I use it commercially?
Not without permission. GitHub finds no licence file in the repository, and without a licence all rights are reserved by default: you may read the code but not reuse it. Check the README, or ask the authors, before using it.
Is it still maintained?
Yes. The repository last received commits 10 days ago.
What is it written in?
Mainly Python, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 20, 2026, and from our analysis. They are not legal advice.

Editorial analysis

A proposal is a document with a formal life, not a forum post

The ghc-proposals repository contains specifications for proposed changes to the Glasgow Haskell Compiler, to the specification of the language it accepts, or to the surrounding ecosystem. The stated purpose of the proposal process and of the GHC Steering Committee is to broaden the discussion of the evolution of GHC.

A proposal is defined as a document describing such a change, and the examples given are a change to the syntax or semantics of the Haskell language, a major change to the user-visible behaviour of the compiler, and the addition of major features to the compiler. The examples are concrete enough to be useful: the ShortImports proposals, do expressions without a dollar sign, a change in super-class solving, a change in -Wall behaviour, -XTypeInType, new GHCi commands, and type-indexed Typeable representations.

That definition does a lot of work. It is the reason the repository is worth reading even if you never propose anything. A language feature that ships in a GHC release has a proposal here, and the proposal contains the discussion that produced it, which is often the only written record of why a design was chosen over the alternatives.

The process is a state machine expressed through GitHub pull requests and labels. The README links to filtered pull request lists for every stage: proposals under discussion, proposals waiting for a shepherd recommendation, proposals waiting for a committee decision, accepted proposals, rejected proposals, proposals needing revision, proposals pending implementation, and implemented proposals. A separate list covers all proposals, excluding the ones labelled as not proposals.

The repository is written in reStructuredText, with README.rst as the entry point, an index.rst, and separate files for the acceptance criteria, the committee process, the GHC Steering Committee itself, and the principles that proposals are evaluated against. The Python in the tree is the Sphinx configuration, and there is a shell.nix and a build.sh for the documentation build, plus a .readthedocs.yaml.

The stage table, with the time each stage is allowed to take

The life cycle section of the documentation is a table, and the table is the most useful thing in the repository for anyone trying to understand where a proposal sits.

Creation has no time limit and belongs to the author, who opens a pull request. Community discussion also has no time limit, still belongs to the author, and ends in one of two ways: the author submits it to the committee, which triggers a shepherd appointment, or the author closes the request, which makes it withdrawn.

From there the stages have deadlines. Shepherd appointment has a maximum duration of one week and belongs to the secretary, whose action is to assign a shepherd. Shepherd review is capped at two weeks and belongs to the shepherd, who either makes a recommendation, moving the proposal to committee discussion, or sends it back for revision, which moves it to the needs-revision stage. Committee discussion is capped at four to five weeks and belongs to the shepherd, whose action is to accept.

Three things stand out. First, the two stages with the most uncertainty, creation and community discussion, are the ones with no deadline, which is a deliberate choice: a proposal should not be rushed to a decision. Second, the shepherd does the work at every stage after appointment, including presenting the proposal to the committee and making the recommendation. Third, the shepherd is a person, not a queue, and that is a bottleneck worth naming.

The documentation states that the table shows all stages of the reviewing process, and each entry links to a detailed description of that stage and to the list of proposals carrying that label.

What does not belong here, and who owns it instead

The scope boundaries are as important as the scope. The documentation lists changes that are not necessarily within the scope of the committee.

Changes to declarations in base should be addressed to the Core Libraries Committee. Changes to other core libraries should go to the relevant library maintainers. Changes to the GHC API, the plugin API, or to compiler internals can be contributed following the usual GHC merge request review workflow, which is a much lighter process than a proposal. Bug fixes and other minor changes that do not warrant additional overheads are also out of scope.

That is a good structure, and it is the reason the proposal process can be expensive. The heavyweight path is reserved for changes that alter the language or the compiler's observable behaviour, which are the changes where a written specification and a public discussion are worth the cost.

There is also an entry point for people who did not start at the top. The documentation says the GHC maintainers may, at their discretion, involve the GHC Steering Committee and ask the contributor to write a formal proposal, if they deem a change significant or controversial enough. So a proposal can be requested rather than initiated, and the committee's involvement is discretionary rather than automatic.

The evaluation criteria live in a separate file, principles.rst, and the documentation says proposals are evaluated against them and that the principles cover both language design and language stability. That pairing is the substantive position of the whole process. A proposal that improves expressiveness but destabilises existing code is not automatically a good one, and the principles file is where that trade is argued out in public.

Reading a proposal, and reading the ones that were rejected

For a reader, the label filters are the navigation. The lists of accepted and implemented proposals give the historical record of the language, and the list of rejected proposals is arguably the more instructive of the two, because a rejection with a stated reason is a design argument that a reader can disagree with on the record.

The proposals themselves live in a proposals/ directory, one document per change, and each is evaluated against the principles and by a named shepherd. A reader who has followed a feature from discussion to implementation can trace the same document back through the stages, because the state is carried by the pull request and its labels rather than by a separate tracker.

The one thing to be careful about is that a proposal in this repository is not a promise. The list of proposals pending implementation is a separate filter from the list of implemented proposals, and the gap between acceptance and implementation is where a feature can sit for a long time. A language feature that is accepted is not yet a language feature you can rely on in production code, and the distinction matters when you are making dependency decisions.

The documentation also makes clear that a proposal covers a change, not a feature set. Reading a proposal tells you the intended behaviour and the reasoning; it does not tell you how the implementation will behave in the corner cases the proposal did not consider, which is a question only the compiler source and its tests answer.

Why the process is worth the trouble, and where it falls short

The strongest argument for this repository is that it makes language evolution legible. When a compiler change alters how existing code behaves, the question everyone asks is why, and having a written proposal with a public discussion attached to the change is a better answer than a release note. The examples in the documentation are exactly the controversial cases, super-class solving and -Wall behaviour, and having those decisions argued in the open is the point of the exercise.

The weakness is the same thing seen from the other side. The path from an idea to a shipped feature goes through a volunteer shepherd, a committee with its own calendar, and an implementation backlog, and the stages with deadlines are the ones after a volunteer has taken an interest. A proposal that nobody wants to shepherd can sit in community discussion indefinitely, with no maximum duration and no mechanism in the documentation for moving it along. A language with a long-lived compatibility promise needs that kind of care, and the cost of that care is that the process is slow.

The second weakness is discoverability for the ordinary user. The navigation is by GitHub label and pull request query, which is excellent for someone who already knows the process and poor for someone looking for a plain explanation of why a feature exists. The reStructuredText source and the Sphinx site mitigate this, but a reader arriving at a single proposal document has to find their own way to the surrounding discussion.

The third is that proposals are not the implementation. A proposal states intended behaviour; a bug in the implementation, or an interaction with an existing feature that nobody considered, is resolved elsewhere, in the compiler's issue tracker and its test suite. Treating a proposal as a specification of what your code will do is a category error, and an expensive one in a language where code tends to live for a long time.

Editorial conclusion

ghc-proposals is the place to read before writing Haskell code that depends on a language feature, because it holds the specification of a change from the moment it is proposed to the moment it is implemented, including the reasoning and the objections, and a proposal is the only route to a decision on a language or compiler change. It is the wrong tool for a bug fix, a core library change or a plugin API change, all of which the project documentation routes elsewhere. Before reading it with an expectation of a stable answer, look at the stage tables, since a proposal can sit in community discussion indefinitely and a shepherd review can end in a request for revision, and note that the repository was last pushed on 2026-10-13, so the accepted list grows over time and carries no fixed release cadence.

Frequently asked questions

What is a GHC proposal?

A document describing a proposed change to the compiler, to the specification of the language it accepts, or to the surrounding ecosystem, such as a change to the syntax or semantics of Haskell, a major change to compiler behaviour, or a new major compiler feature.

What is a shepherd in the GHC proposal process?

A person appointed by the secretary to review the proposal. The shepherd gets up to two weeks to make a recommendation or send it back for revision, and then presents it for committee discussion, which has a maximum duration of four to five weeks.

Which changes do not need a GHC proposal?

Changes to declarations in base, which go to the Core Libraries Committee, changes to other core libraries, changes to the GHC API, the plugin API or compiler internals, which follow the usual GHC merge request workflow, and bug fixes and other minor changes that do not warrant the overhead.

How are GHC proposals evaluated?

Against the principles set out in principles.rst, which the documentation says cover both language design and language stability.

How do I find the proposals that were already accepted or implemented?

The repository links to filtered pull request lists for accepted proposals, proposals pending implementation, implemented proposals, rejected proposals, and proposals needing revision, each of which is a GitHub query on the proposal labels.

Official sources

  1. ghc-proposals/ghc-proposals on GitHub
  2. Issues
  3. Project website
  4. README
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/ghc-proposals-ghc-proposals.svg)](https://hysenlabs.com/projects/ghc-proposals-ghc-proposals)

Was this useful?