I didn’t realize that. I use stack which seems to leave it to cabal default.
I agree, it’s a pain when you have to enable it to make something just work.
TypeAbstractions looks interesting indeed.
I didn’t realize that. I use stack which seems to leave it to cabal default.
I agree, it’s a pain when you have to enable it to make something just work.
TypeAbstractions looks interesting indeed.
Good to hear that, as that is the motivation for the exercise: Remove the anxiety and mental overhead of deciding whether a certain feature is “normal part of contemporary Haskell”. It doesn’t mean everyone has to use them, or that we can’t have opt-in warnings or linters that help you stick to a particular subset if you want to (to address AntC’s concerens), but otherwise they are no more “special”.
Me too! I think LambdaCase
didn’t make it because there was discussion around the n-ary \cases
. Similar for ViewPatters
where an arguably “better” design has been floating around for a long while, although so far no one has picked it up and brought it to life.
Personally, I hope we will get GHC2024 with a few additions (I argued unsuccessfully for having 2023), also to show that this is really a continuous process, with regular updates, that new editions are nothing to be afraid of, and that code declared to use GHC2021 doesn’t break because of a new release.
Is there an ongoing discussion about this?
It seems silly but “anxiety” is the exact word
You were expecting it or you find it ugly (or both :-)?
Is there an ongoing discussion about this?
I will kick it off in the fall, like last year.
You were expecting it or you find it ugly (or both :-)?
Expecting :-). I am not using it myself, but I find the foo a b = \case …
idiom rather nice sometimes. And inline \case
even more. Maybe partly influenced from Ocaml’s function
.
I also really like all the deriving ones.
I use it, I love it, its only shortcoming is that it doesn’t include enough stuff, but the next extension will certainly fix this
With Stack, Hpack defaults to default-language: Haskell2010
, which is why that ends up in Cabal files. It can be overridden by adding language: GHC2021
to the package.yaml
and, in fact, the Stack project itself moved to GHC2021
a while ago.
In the case of Stack’s code base, the remaining LANGUAGE
pragmas that get repeated at the top of many modules are: OverloadedStrings
, RecordWildCards
, LambdaCase
, ViewPatterns
, DataKinds
and TypeFamilies
.
Thanks for the clarification.
We use it at work on all libraries/executables. Haven’t really looked back since turning it on as it reduces the number of LANGUAGE
pragmas we need to write (as we don’t use default-extensions
in Cabal). It’s generally been pain free except:
hlint.yaml
to know about extensions that are on by default:# We disable all extensions by default, as a bunch are implied by using GHC2021. For any other
# extension that needs to be explicitly enabled, add the extension below.
- extensions:
- default: false
- name:
- AllowAmbiguousTypes
- ApplicativeDo
- BlockArguments
- CPP
- DataKinds
- DefaultSignatures
- DeriveAnyClass
- DerivingStrategies
- DerivingVia
- DisambiguateRecordFields
- DuplicateRecordFields
- ExplicitNamespaces
- FieldSelectors
- FunctionalDependencies
- GADTs
- ImplicitParams
- ImpredicativeTypes
- IncoherentInstances
- LambdaCase
- LexicalNegation
- MagicHash
- MonadComprehensions
- MonoLocalBinds
- MultiWayIf
- NegativeLiterals
- NoFieldSelectors
- NoImplicitPrelude
- NoMonomorphismRestriction
- NoStarIsType
- OverloadedLabels
- OverloadedLists
- OverloadedRecordDot
- OverloadedStrings
- PackageImports
- PartialTypeSignatures
- PatternSynonyms
- QualifiedDo
- QuantifiedConstraints
- QuasiQuotes
- RebindableSyntax
- RecordWildCards
- RecursiveDo
- StrictData
- TemplateHaskell
- TemplateHaskellQuotes
- TypeFamilies
- UndecidableInstances
- UndecidableSuperClasses
- ViewPatterns
I’m using it a lot, at least for new code, and think it’s a very pleasant default in practice. It doesn’t enable all the extensions I frequently use, but the remaining ones I’m usually quite happy to enable selectively.
Remove the anxiety and mental overhead of deciding whether a certain feature is “normal part of contemporary Haskell”.
For the record, and/or for the planning GHC2024
, there’s one particular extension in GHC2021
that adds to my anxiety and mental overhead [**]. (And a couple others that I find annoying but would put up with.) @jaror and @maxigit upthread are also lukewarm:
I don’t like that it means namespaces in signatures and term definitions are shared. I’d rather just use type abstractions on the term level.
The ‘it’ is ScopedTypeVariables
. If I count type abstractions
, that’s three better ways we could achieve the same thing: ResultTypeSignatures
is an accepted proposal, work has started but seems to be stalled. (§7.14.3 at that link which shows it used to be in GHC but got taken out.) I’d use GHC202n
if it included ResultTypeSignatures
but not ScopedTypeVariables
. And there’s an accepted not implemented proposal (? at least I think not/I’ve lost track) to tame GHC’s over-enthusiasm for scoping. (He he Which mentions @nomeata’s own hankering after PatternSignatures
.)
So if that proposal gets released, is that going to upset programs currently silently setting ScopedTypeVariables
because GHC2021
? I don’t know/it’s all too hard/I prefer to name extensions individually and not use ScopedTypeVariables
in its current dangerous form.
[**] It’s the only place in Haskell where explicit forall
changes the meaning of a program. Its effect is module-wide, so if I need to switch it on, I’d better check all my declarations for accidental scope-capture. The type sig might be textually a long way from the function body (say I have several equations with different pattern matches). The claim in the docos "without which [that is, the ‘it’] some type signatures are simply impossible to write. " I find just not true – especially for the sort of code newbies are writing/who are the ones most likely to get confounded by a non-obvious effect. I guess what’s making this especially nasty is that tutorial code samples use a, b, c
for tyvars everywhere – both signatures and within-body annotations.
I personnaly think that type variables should have been scoped without the need of any forall or extension. That is the only thing in Haskell (and probably all programming language) that is not scoped. Why ?
Do people really write code where the same name in the same function is used to represent two different things ?
The only two extensions I find annoying sometimes are
PolyKinds
andExistentialQuantification
. […] The latter means you can write and use GADTs without actually enabling theGADTs
extension, it just gives a small warning that pattern matching might lead to unexpected results.
I thought you cannot write/use GADTs
in GHC2021?
It sounds like you are mistakenly ascribing the effects of GADTSyntax
to ExistentialQuantification
?
The language extensions GADTSyntax
and ExistentialQuantification
are both enabled in GHC2021, but the GADTs
language extension is not enabled in GHC2021.
The distinction between generalized and ordinary algebraic data types is orthogonal to whether a data type is an existential data type. GADTSyntax
only enables a different syntax and changes how pattern matching works for certain ordinary algebraic data types.
From the documentation of GADTSyntax
:
Any datatype (or newtype) that can be declared in standard Haskell 98 syntax, can also be declared using GADT-style syntax. The choice is largely stylistic, but GADT-style declarations differ in one important respect: they treat class constraints on the data constructors differently. Specifically, if the constructor is given a type-class context, that context is made available by pattern matching. For example:
and
The result type of each data constructor must begin with the type constructor being defined. If the result type of all constructors has the form
T a1 ... an
, wherea1 ... an
are distinct type variables, then the data type is ordinary; otherwise is a generalised data type (Generalised Algebraic Data Types (GADTs)).
According to this the following data type is an ordinary algebraic data type, an OADT if you like.
data Foo a where
Bar :: Ord b => a -> b -> Foo a
, whereas
data Foo a where
Bar :: Foo Int
data Foo a b where
Bar :: a -> Foo a a
are both generalized algebraic data types (GADTs).
To make it more confusing (but not really) the documentation also states:
Notice that GADT-style syntax generalises existential types (Existentially quantified data constructors)
I guess this is why GADTSyntax
and ExistentialQuantification
are easily conflated.
I thought you cannot write/use
GADTs
in GHC2021?
Try it:
{-# LANGUAGE GHC2021 #-}
data T a where
T :: T Int
foo :: T a -> a
foo T = 5
You’ll find that GHC only gives a warning when you try to pattern match:
T.hs:5:5: warning: [-Wgadt-mono-local-binds]
Pattern matching on GADTs without MonoLocalBinds is fragile.
Suggested fix:
Enable any of the following extensions: GADTs, TypeFamilies
|
6 | foo T = 5
| ^
If you disable ExistentialQuantification
:
{-# LANGUAGE GHC2021 #-}
{-# LANGUAGE NoExistentialQuantification #-}
data T a where
T :: T Int
foo :: T a -> a
foo T = 5
Then it gives a real error:
T.hs:4:3: error:
• Data constructor ‘T’ has existential type variables, a context, or a specialised result type
T :: T Int
(Enable ExistentialQuantification or GADTs to allow this)
• In the definition of data constructor ‘T’
In the data type declaration for ‘T’
|
4 | T :: T Int
| ^^^^^^^^^^
I think I’ve heard about this from one of @rae’s videos for Tweag, but I don’t remember which one.
Note that this is actually new behavior in GHC 9.4: In 9.2, you get an actual error instead of a warning when trying to pattern match on a GADT with GHC2021
:
Test.hs:7:5: error:
• A pattern match on a GADT requires the GADTs or TypeFamilies language extension
• In the pattern: T
In an equation for ‘foo’: foo T = 5
|
7 | foo T = 5
| ^
This was changed in !7042, see the linked #20485 for the motivation.
But it is indeed surprising that you can now use GADTs
without enabling them, ie this compiles without any warnings or errors in GHC >=9.4:
{-# LANGUAGE Haskell2010 #-}
{-# LANGUAGE ExistentialQuantification #-}
{-# LANGUAGE GADTSyntax #-}
{-# LANGUAGE MonoLocalBinds #-}
{-# OPTIONS_GHC -Wall #-}
data T a where
T :: T Int
foo :: T a -> a
foo T = 5
I wonder whether this is actually intended EDIT: I commented on the issue linked above: #20485: Pattern matching on GADT pattern synonyms · Issues · Glasgow Haskell Compiler / GHC · GitLab
EDIT 2: I got pointed to this upstream ticket discussing whether it should be changed that one can define arbitrary GADTs without GADTs
: #21102: GADT accepted without -XGADTs · Issues · Glasgow Haskell Compiler / GHC · GitLab
Yes, enabling GADTSyntax
and ExistentialQuantification
is enough to define and use GADTs. I regard it as a bug in GHC2021
that it included both but not GADTs
. Unfortunately it’s not obvious of the best way to fix it since MonoLocalBinds
isn’t included either, and enabling it is non-backwards-compatible.
I’m hoping we can resolve this in the next GHC20xx revision (see https://github.com/ghc-proposals/ghc-proposals/blob/51a0c9c4467f9cf3173ba06a987cce501ea242f0/proposals/0000-ghc2023.rst#why-add-gadts-and-monolocalbinds although GHC2023 didn’t happen).
I don’t think GADTs are stable enough to be in the next GHC202X
. There have been breaking changes as recently as 9.6.1: 2.1. Version 9.6.1 — Glasgow Haskell Compiler 9.6.2 User's Guide
Edit: I guess it is just the combination of GADTs and Type Families, so perhaps the Type Families are the unstable part:
Record updates for GADTs and other existential datatypes are now fully supported.
[…]
A side-effect of this change is that GHC now rejects some record updates involving fields whose types contain type families (these record updates were previously erroneously accepted).
The next most recent breaking change was in 9.0.1:
GADT constructor types now properly adhere to The forall-or-nothing rule.
2.1. Version 9.0.1 — Glasgow Haskell Compiler 9.0.2 User's Guide, which is also not that long ago yet.
If it had been up to me, I might have included GADTSyntax
but not ExistentialTypes
/GADTs
in GHC2021
. But given that the de facto situation is that GADTs are supported in GHC2021
, I would be tempted to continue to include them, because it would send a misleading signal to remove them now. I don’t think inclusion in GHC20XX
should mean that the extension is necessarily completely stable.