Haskell Report 2024?

Does the following have any legs as an idea? If it is misconceived, please say so!

The Haskell Report 2010 is (a) authoritative (b) all in one place and (c) acts as a ‘landmark’ (something that other things are described by reference to).

The GHC language edition GHC2024 appears to be (a) the result of community input (what should be included and excluded was debated) and (b) relatively mature (in that it built on the prior experience of creating GHC2021 - GHC’s default ‘language’ since GHC 9.2.1). It also acts as a sort of landmark. The GHC User’s Guide says it is recommend for new code.

For each of the language extensions that are in GHC2024, there is good documentation - e.g. in the debated and adopted proposals that led to the extension, in the latest GHC User’s Guide itself etc., in other documents included in the User’s Guide ‘by reference’ - but not necessarily ‘all in one place’.

‘All in one place’ may be valued: some people interested in Haskell say they look wistfully at The Rust Programming Language book, for example.

Some AI tools seem reasonably good at tasks that involve taking information in one form and recasting it into another form (including following the style/tone of something that already exists) - at least, they seem to get part of the way there before a knowledgable person steps in to finish the job.

Could AI tools be used to help create the better part of a ‘Haskell Report 2024’, which would be (essentially) Haskell Report 2010 plus additional extensions in GHC2024, recasting the style/tone/form/scope so that the end product is consistent with the earlier report?

The intent being not to set anything in stone but to create a new landmark that is (a) authoritative and (b) all in one place.

I can imagine a process:

  1. For each extension, asking does it have a natural ‘home’ in the 2010 report structure, or does it need something ‘brand new’? You could ask AI that, and then ask the community to critique its suggestions.

  2. Once the ‘structural’ questions are settled, for each extension, you could ask AI to recast existing documentation into something consistent with the style/tone/conventions etc of the 2010 report. There would then be an open (and human) process to get from that output to something that met the desired quality theshold of the community. (The Haskell 2010 Report providing an example of quality.)

I am assuming that:

(a) this would involve only ‘recasting’ of what already exists in a well-defined way, not ‘origination’ (and so avoiding the sorts of debates that origination brings);

(b) the parts of the community interested in language design (at least, for the most part) does not look at any GHC2024 language extension and say “No, no, no! That has no place in a point of reference for modern Haskell!”; and

(c) AI tools can take out most of the ‘chore’ (unattractive to volunteers) leaving activities that are interesting to volunteers.

EDIT1: Below is a (hand-made) table that compares GHC2024 to Haskell2010 (and GHC2021) (implied language extensions are in brackets):

Haskell2010 GHC Guide Section GHC2024
Syntax EmptyCase
Syntax LambdaCase
Syntax PostfixOperators
Syntax TupleSections*
Import/export ImportQualifiedPost
Types DataKinds**
Types ExistentialQuantification (ExplicitForAll)
Types GADTs (GADTSyntax, MonoLocalBinds)
Types PolyKinds (KindSignatures)
Types RankNTypes (ExplicitForAll)
Types RoleAnnotations***
CUSKs: REPLACED BY Types StandaloneKindSignatures
Types TypeApplications
Types TypeOperators (ExplicitNamespaces)
Records DisambiguateRecordFields
Records NamedFieldPuns
Records NamedWildCards
Deriving DeriveDataTypeable
Deriving DeriveGeneric**
Deriving DeriveLift
Deriving DeriveTraversable (DeriveFoldable, DeriveFunctor)
Deriving DerivingStrategies
Deriving EmptyDataDeriving
Deriving GeneralisedNewtypeDeriving
Deriving StandaloneDeriving
Class/instance FlexibleInstances (TypeSynonymInstances)
Class/instance InstanceSigs
Class/instance MultiParamTypeClasses (ConstrainedClassMethods)
Literals BinaryLiterals
Literals HexFloatLiterals
Literals NumericUnderscores
Constraints ConstraintKinds
Constraints FlexibleContexts
Type sigs ScopedTypeVariables (ExplicitForAll)
Bang patterns BangPatterns*
DatatypeContexts REMOVED
DeepSubsumption REMOVED

EDIT2: Supported by (and always enabled with) MicroHs, according to its Wiki. (* With limitations.) (** Not supported, but on the ‘wish list’.) (*** Supported, but not documented in the Wiki.) MicroHs supports/enables other language extensions. MicroHs enables NoStarIsType (unlike Haskell2010 and GHC2024).

EDIT3: Language extensions in bold are also in GHC2021. The omission of ExplicitNamespaces from GHC2021 is documented as an oversight.

  1. Mentioning AI/LLMs may trigger an endless debate.
  2. I don’t think a new language report should just adopt a set of extensions.
  3. Other implementations, like MicroHs, may not agree with GHC2024.
  4. I’m not sure the community currently has enough resources for this.

On your point 2. “A new language report should not just adopt a set of extensions”, may I ask what you consider it should seek to do in addition to that?

(Something I had in mind myself was perhaps resolving at least some of the points where GHC’s Haskell2010 and the Haskell 2010 Report differ - Section 16.1 of the GHC User’s Guide. For each difference, it is possible to ask “Which is better: what GHC in fact does or what the Haskell 2010 Report provides?” In some cases, the answer to that question may be ‘clear cut’.)

EDIT: Below is an attempt to summarise Section 16.1 tersely:

Ref Topic Haskell 2010 Report GHC
1.1 <module>.<reservedop> Two lexemes Single qualified operator
1.1 forall Always a reserved keyword
1.1 (!) operator Bang pattern
1.1 irrefutable patterns Must be in prefix form
1.1 Strictness annotations in data declarations Must be in prefix form
1.1 As-patterns Must not be surrounded by whitespace
1.1 Decimal literals Unicode Decimal Number Only ASCII numbers
1.1 Unicode Other Letters Considered to be small letters
1.1 Digit class Decimal Numbers All Unicode numbers
1.1 Non-Spacing Marks Can appear in tail of identifiers
1.1 Redundant parantheses in funlhs Allowed
1.3 Expressions and patterns Makes some programs slightly more defined
1.4 do blocks with failable patterns Need MonadFail constraint
1.5 Typechecking of recursive binding groups A more general scheme
1.6 module Main(main) where Assumed -main-is option
1.8 Num superclasses Not Show or Eq
1.8 Bits superclass Not Num
1.8 Read methods Extra: readPrec and readListPrec
1.8 Monad superclass Has Applicative
1.8 Functor, Monad instances Have extra instances
1.8 Array checking Multiply-defined array elements not checked
1.9 Data.List.splitAt More strict
1.9 Show Unnecessary parantheses around records
1.10 FFI: Reinitialising after shutdown Not supported

Haha, you have scooped me by about 1 week :slight_smile: I am about to announce a project which will hopefully lead to a new Haskell report pretty soon, you just have to wait a few more days.

I think trying to bring GHC 2021 or GHC 2024 into report form is way too hard to consider as a single step. The user documentation in the GHC user guide and the GHC proposals is nowhere near precise enough to serve as language specification. One of the reasons the current Haskell 2010 language report can be somewhat concise is that it “cheats” by handwaving a lot of technical details and by referring to “standard techniques from Hindley-Milner type inference”. If we want the language report to cover features such as GADTs, type families etc. then we can no longer rely on this shortcut and have to rewrite large amounts of the report from scratch and explain all the technical details. The result would probably look much more like the papers Practical type inference for arbitrary-rank types or OutsideIn(X): Modular type inference with local assumptions - Simon Peyton Jones than the current report.

(Something I had in mind myself was perhaps resolving at least some of the points where GHC’s Haskell2010 and the Haskell 2010 Report differ - Section 16.1 of the GHC User’s Guide. For each difference, it is possible to ask “Which is better: what GHC in fact does or what the Haskell 2010 Report provides?” In some cases, the answer to that question may be ‘clear cut’.)

That is more or less precisely what I plan to do: A revised version of the Haskell 2010 language report that takes account of how the language has changed in the intervening years is a feasible project that can be achieved in a limited amount of time. GHC currently can’t compile any non-trivial Haskell 2010 programs, which is really a quite unfortunate situation. I think we can try to fix this problem first.

a) i’m not so sure all the extensions in GHC2024 are engineered or specified to the standard i’d expect for a Language Standard.

b) i’m absolutely certain there’s extensions in GHC2024 I would never switch on, and I regard as a code smell.

c) I wouldn’t trust an LLM to adequately document the caveats that Haskellers should beware of with some of those extensions.

d) GHC2024 doesn’t include several extensions I use regularly (and indeed without which GHC2024 alone doesn’t amount to a coherent language).

For example, we may want to revisit the standard library.

@DavidB, your 2026 HIW talk (“Is There a Future for a Formally Specified Haskell Report?”):

was one of the triggers for my pondering. However, my ambition was humbler than what I understood you were describing (which I understood to be a specification in a form that would allow a machine to check - perhaps even to create, like the Web Assembly Specification ). My ambition was only a document that a reasonably-minded person would find useful (with the Haskell 2010 Report providing a benchmark, in that regard).

I’ve added a table to my original post, to make it easier for people to identify any “No, no, no!” language extensions in GHC2024.

It seemed to me unlikely that the GHC User’s Guide would recommend something that was widely considered to be ‘actively bad practice’ - but I acknowledge that missteps can happen: one part of Haskell 98 was considered a misstep in Haskell2010 and two parts of Haskell 2010 are considered a misstep in GHC2024.

It seemed to me that a landmark that is incomplete is still useful and tolerable. That is what we currently have, when people declare (in their code): “I am using Haskell 2010 Report plus X, Y and Z language extensions”.

However, it seems to me that a landmark that contains missteps is something (like success) that one should aim to avoid at all costs.

My “secret” project that I am going to announce soon is different from the formalized report that I presented at HIW. But they are related: It doesn’t make much sense for me to write a formal specification of the existing Haskell 2010 report if existing compilers don’t follow that report anymore, so I want to update the Haskell 2010 report to a “revised” Haskell 2010 language report that GHC and MicroHS would then actually adhere to, and my formalization as well.

I think the report, even in its informal textual variant, does have higher requirements than just being useful. It needs to be precise enough to allow a compiler writer to independently implement the features that it describes without referring back to GHC and how GHC implements them. This is a much higher mark than what we require of the User guide or even GHC proposals.

The main problem is that the features of GHC2021 and GHC2024 were chosen according to the criteria: “Are they widely used?” and “Are they stable?”, and not according to the question “Can they easily be specified in a future report?”. If we set them as goals for ourselves, i.e. if we define success as specifying all the features in those two language editions in the report, then we are setting us up for failure because it might be too hard to achieve.

The other part that we might miss if we focus on just language extensions is the concurrency story: Haskell 2010 does not contain anything about concurrency, but it probably should become part of a future report. In particular, it would be quite important to find, as a community, an answer to which memory model we want Haskell to use. (* The memory model specifies, essentially, how forkIO and IORef interact, i.e. what freedom the compiler has to interleave IORef reads and writes between different threads).

I think it would be valuable to document Haskell2024 (say) “all in one place”, including things like concurrency, STM, FFI, that are not much covered in GHC proposals.

The main reason that no one has done so is simply that no one has done so … it’s quite a lot of work. It’s great that David (and maybe Mike?) are actively thinking about doing so.

I am agnostic about whether using AI would speed up the process or slow it down. LLMs can generate reams of plausible sounding text, but there is a big difference between an impenetrable explanation of X that has no obvious mistakes, and a limpidly clear explanation of X that obviously has no mistakes (to paraphrase Hoare). The latter is much, much harder.

David’s work to fully-formalise the spec is excellent, but it sets a very high bar, and it is utterly useless for most readers (too hard). I think there is a real role for a well-structured English language specification. The original Haskell Report informal in this sense, and definitely included hand-waving; but it was also the result of an truly enourmous amount of effort and iteration, and has served us reasonably well. It’s a compromise, certainly, but a honourable one.

So thumbs-up from me; but be clear-eyed about how much it might cost; and perhaps look for intermediate (i.e. cheaper) milestones that are valuable in themselves.

Having read the Haskell 2010 report quite intensly in the last few months, here are my guesses of how difficult individual extensions of GHC2024 would be to specify:

Extension Difficulty to Specify
BangPatterns Doable
BinaryLiterals Easy
ConstrainedClassMethods Doable
ConstraintKinds ???
DataKinds Doable
DeriveDataTypeable ???
DeriveFoldable Doable
DeriveFunctor Doable
DeriveGeneric Very very hard (Requires type families)
DeriveLift Probably doable?
DeriveTraversable Doable
DerivingStrategies ???
DisambiguateRecordFields ???
DoAndIfThenElse Part of Haskell 2010
EmptyCase Easy
EmptyDataDecls Part of Haskell 2010
EmptyDataDeriving Easy
ExistentialQuantification Potentially very hard
ExplicitForAll ???
ExplicitNamespaces Doable
FieldSelectors Part of Haskell 2010
FlexibleContexts ???
FlexibleInstances ???
ForeignFunctionInterface Part of Haskell 2010
GADTs Potentially very very hard
GADTSyntax Easy
GeneralisedNewtypeDeriving Doable
HexFloatLiterals Easy
ImplicitPrelude Part of Haskell 2010
ImportQualifiedPost Easy
InstanceSigs Harder than it looks!
KindSignatures Doable
LambdaCase Easy
MonoLocalBinds Doable, but not trivial
MonomorphismRestriction Part of Haskell 2010
MultiParamTypeClasses Doable, but not trivial
NamedFieldPuns Doable
NamedWildCards ???, probably hard
NumericUnderscores Easy
PatternGuards Part of Haskell 2010
PolyKinds Doable, easier than it looks!
PostfixOperators Doable, but might be tricky
RankNTypes Potentially very hard
RelaxedPolyRec Part of Haskell 2010
RoleAnnotations Potentially very hard
ScopedTypeVariables Potentially very hard and contentious
StandaloneDeriving Easy
StandaloneKindSignatures ???
StarIsType Part of Haskell 2010
TraditionalRecordSyntax Part of Haskell 2010
TupleSections Doable
TypeApplications Potentially very hard
TypeOperators Doable
TypeSynonymInstances ???
ImplicitStagePersistence Very very hard

Reasons why I think some of these are hard:

  • GADTs: They are just very hard to specify in general. See the “OutsideIn” and the “Let should not be generalized” papers for details on what the difficult edge cases are. (Mainly: How let bound variables are generalized in the presence of unsolved constraints.)

  • TypeApplications, ScopedTypeVariables, ExplicitForAll, ExistentialTypes, RankNTypes:
    They all kind of belong to the same group. The type inference system of Haskell 2010 is essentially textbook Hindley-Milner + type classes. This makes it quite easy to handwave technical details and to refer to the literature. With any of these extensions we deviate from the basic assumptions of Hindley-Milner type inference and have to describe the deviations in sufficient technical detail.

  • ImplicitStagePersistence: Involves specification of staged compilation etc.

  • RoleAnnotations, FlexibleContexts, FlexibleInstances, MultiParamTypeClasses: It is very hard to estimate how much of the text would have to be rewritten to account for the specification of the constraint solving for these extensions to typeclasses.

Reasons why I think some of these are simpler than thought:

  • PolyKinds, DataKinds: These are easier than might seem. PolyKinds just replaces kind defaulting by the standard rules of Hindley-Milner generalization of unsolved kind variables. DataKinds also mostly involve concepts from the simply-typed lambda calculus.

I feel it’s worth mention that you can keep the handwavy descriptions and still have higher rank types with PolymophicComponents (see FCP). If your unaware PolymorphicComponents limit the higher rank types to data types fields and this allows them to have perfect inference and to stay compatible with Hindley Milner.

DataKinds I agree, but are you sure PolyKinds are also easy? With PolyKinds your data types now extra parameters and all their constructors and methods carry those extra constructors. Consider this example:

data Poly a = MakePoly

-- generalized :: forall (k :: Type) (a :: k). Poly a
generalized = MakePoly

From the constructor’s point of view, Poly has two type parameters. MakePoly has to instanciate k then instantiate a with k’s type. Then to generalizing this, you have do some topological sorting.

Yes, but this is also already true for the Haskell 2010 report which specifies this topological sorting to find out the dependency order in section 4.5.1. Although currently the report only spells this out for terms and types, and not for data/class declarations and kinds. The details of how to do the topological sorting for types and kinds can be found in, e.g. section 3.1 of https://www.cambridge.org/core/services/aop-cambridge-core/content/view/9D90E0C7DE8DA7D6BAEAC5143E658E1D/S0956796802004380a.pdf/static_semantics_for_haskell.pdf which could easily be adapted and included into the report.

I have updated the table in my original post to identify what MicroHs does. With a few exceptions, it always enables all of GHC2024 … and more.

The main exception seems to me to be MonoLocalBinds. On 7 December 2025, @augustss wrote that it had ‘caused him grief’ and he planned to remove it.

DeriveLift relates to class Lift in template-haskell and MicroHs will not support Template Haskell (GHC2024 excludes Template Haskell). I assume that MicroHs does not have a principled objection to HexFloatLiterals.

Really great idea!!

This also fixes Haskell’s bootstrapping problem:

print "Write Haskell 2026 spec using AI. Use spec and AI to build a small haskell 
       interpreter that compiles ghc from its source"

spec = Haskell_2010 + otherDocs

repeat
    repeat 
        spec = AI_reviseSpec(spec, prompts, errors, etc)
        tinyHaskellInterpreter = AI_writeInterpreter(spec)
        phase1Errors = runTestSuite(tinyHaskellInterpreter, HaskellTestSuite)
    while phase1Errors

    ghcInterpreted = tinyHaskellInterpreter(ghcSource)
    ghcCompiled = ghcInterpreted(ghcSource)

    phase2Errors = runTestSuite(ghcCompiled, HaskellTestSuite)
while phase2Errors

print "GHC now bootstrapped from its specification"

Amusingly, tinyHaskellInterpreter can be in any convenient language that satisfies stakeholder needs for bootstrapping. If it were something ubiquitous like python or java, then Haskell now trivially runs everywhere.

As an experiment, this evening, I gave Claude Cowork (Opus 4.8) the .verb files of the Haskell 2010 Report and the .rst files of the GHC User’s Guide and, for GADTs only, asked it two things, sequentially:

– the structural question: if GADTs was within scope of the Haskell 2010 Report, what would be affected (its output was a Section 4.2.1 re-write and consequential changes)

– the editorial question: as a text file, to provide that Section 4.2.1 re-write and each of the consequential changes. (That output took a few minutes.)

I need to read the text file carefully but, at least superficially, it has the appearance of something that a knowledgable person (I am not that person!) would find a useful foundation in completing the task.

EDIT: I shared the file with @DavidB and he has explained that it is too superficial on the details that should matter to the compiler-writer that he is imagining. So, I continue to experiment …

I really like MonoLocalBinds, but parsec does not compile with this extension. There is local definition that needs a type signature for it to compile. I sent in a PR for parsec to make it compile, but the maintainer does not like microhs specific changes (as is his prerogative) and he never merged the patch. In the end, I disabled MonoLocalBindsand implemented MonomorphismRestriction instead. It was a sad moment.

I don’t mind HexFloatLiterals and I’ll add it.

ScopedTypeVariables is not an extension i’d ever use willingly, because it changes ExplicitForall to be more than a stylistic choice, and it puts tyvar(s) — which might be the same as a tyvar in an unrelated signature — into a kinda module-wide scope. I’d prefer TypeAbstractions as the way of the future, but they’re not in GHC2024.

You really can’t use those without overlaps. OverlappingInstances is deprecated [good!], so then you need to discuss the various OVERLAP* pragmas.

MPTCs make little sense without TypeFamilies or FunctionalDependencies. For example, OverloadedRecordDot uses FunDeps. But neither is in GHC2024.

In short, GHC2024 is not a coherent set of extensions. A learner is likely to need further extensions for much from Hackage (different extensions for each package).

On ScopedTypeVariables, GHC’s view that it should be part of the language seems to be long standing. It was added to -fglasgow-exts in GHC 4.04 (released in 1999).

It’s an old extension, sure, but I think many GHC developers (myself included) do not consider it to be a very good extension, especially now that we have type abstractions.

It’s also notable that ScopedTypeVariables has not been categorized yet, and is even still missing from the latest proposed categorization: Amend #669 to categorize more language extensions (under review) by telser · Pull Request #738 · ghc-proposals/ghc-proposals · GitHub.

I hope it will one day land in the Legacy extension list and we get a Stable type abstractions instead.

Edit: how could I forget linking the Modern Scoped Type Variables proposal (#448).