I’ve just discover the GHC2021, which set a few more extension than I normally do.
Is anyone using it, or would recommend against it ?
I’ve just discover the GHC2021, which set a few more extension than I normally do.
Is anyone using it, or would recommend against it ?
My very personal opinion is it sets some extensions I wouldn’t touch with a barge-pole. I’d rather leave them unset, then get the compiler to yell at me if some unfamiliar piece of code uses them, so I can eyeball that code. (The most insidious are extensions which don’t enable different syntax, but change the meaning of syntax that’s been familiar since ~2006.)
So no, I don’t set it. OTOH I’ve always been happy enough with a long list of extensions at the top of a module, so that doesn’t seem a burden.
You’re likely to find many libraries/sample code/code discussions expect those settings without making explicit mention. Indeed even if they don’t actually need all of them.
Are there any particular extensions you were surprised to see? Is it that you didn’t know of those/don’t feel a need to use them; or that you’d rather avoid them?
It’s enabled by default if you don’t set it (but cabal init
still defaults to Haskell2010). I personally like many of the extensions. The only two extensions I find annoying sometimes are PolyKinds
and ExistentialQuantification
. The former causes errors due to ambiguity where things would just default to Type
before, and the latter means you can define (and, since GHC 9.4, pattern match on) GADTs without actually enabling the GADTs
extension.
But it does have many great extensions: all the deriving extensions, Flexible*
, BangPatterns
, TypeApplications
, StandaloneKindSignatures
, NumericUnderscores
.
I’m also relatively happy it includes ScopedTypeVariables
because you have to use it to write some programs, but 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.
All in all, I’m pretty happy with all of them. There of course the ones I never heard of like ConstrainedClassMethod
or RelaxedPolyRec
, the ones I never have the opportunity likee GADTSyntax
. The one I definitely use TupleSections
, NamedWildCards
.
The most interesting one are the ones I don’t use yet but will use them if they are enabled like ImportQualifiedPost
or NumericUnderscore
and even ScopedTypedVarialbles
etc … I don’t use not because I can’t be bothered but more because it feels like I am not writting orthodox code. If they are part of GHC 2021 then it becomes official and so orthodox.
For the same reason, I was expecting LambdaCase
(which I don’t use, because I find it ugly, but would were enabled by default), BlockArguments
(which I have been waiting for 20 years …) and possibly PatternSynonyms
and 'ViewPatters`.
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.