Recommended set of language extensions?
snoyberg opened this issue · 15 comments
And should we advise setting these in the package.yaml
file vs LANGUAGE pragmas.
I think I’m a minority opinion, but I always enable those I consider “safe” package-wide:
NoImplicitPrelude
(withclassy-prelude
,classy-prelude-conduit
,foundation
etc)OverloadedStrings
OverloadedLists
LambdaCase
GADTSyntax
RankNTypes
ScopedTypeVariables
DeriveGeneric
TupleSections
BangPatterns
MultiParamTypeClasses
FlexibleInstances
FlexibleContexts
MultiWayIf
TypeFamilies
TypeOperators
FunctionalDependencies
DisambiguateRecordFields
MonadComprehensions
BinaryLiterals
RecursiveDo
ParallelListComp
PartialTypeSignatures
RecordWildCards
PatternSynonyms
EmptyCase
InstanceSigs
KindSignatures
DeriveFunctor
DeriveFoldable
DeriveTraversable
ConstraintKinds
ExplicitNamespaces
Once there is a rio
template on stack new
, any selected choices could probably go immediately there, and a recommendation is to just stack new PACKAGE rio
.
I like the idea of not writing many language pragmas as well.
Afterall, not having to manually add dependencies is very similar..
In addition to the question of which language extensions, is whether it's acceptable to put the language extensions in the package.yaml
/cabal file instead of in each module. There's been tooling pushback on this in the past (I think from @nh2, but I'm not sure I'm remembering correctly).
Yes that would be me.
haskell-source-exts
(and tools built on it) and ghci
do not understand cabal files.
If you put pragmas into cabal files, you cannot trivially use some of these tools (e.g. for generating simpe ctags, you only need to parse, which you can do per-file without having to implement any support for cabal), or quickly load a couple of different modules from different packages into one ghci by using the -i
flag (because -X
flags to ghci are global).
Without the haskell-source-exts
programs I could live, or force them to implement support by depending on the Cabal
package (and the extra maintenance effort to keep up with the changes in that), but the no-manual-ghci problem is a real killer.
I guess I should also bring in some form of bold statement:
I would happily choose spending a few seconds at the creation of each .hs
file (and forcing coworkers and community members to do so) over manually re-creating this work each time I have to do some ghci based surgery, and then not commit this work (of putting the pragmas in each file).
Then we can put something like this on the template, and provide for some editors a snippet for the few seconds mentioned:
{-# LANGUAGE NoImplicitPrelude, OverloadedStrings, OverloadedLists,
LambdaCase, GADTSyntax, RankNTypes, ScopedTypeVariables,
DeriveGeneric, TupleSections, BangPatterns, MultiParamTypeClasses,
FlexibleInstances, FlexibleContexts, MultiWayIf, TypeFamilies,
TypeOperators, FunctionalDependencies, DisambiguateRecordFields,
MonadComprehensions, BinaryLiterals, RecursiveDo, ParallelListComp,
PartialTypeSignatures, RecordWildCards, PatternSynonyms, EmptyCase,
InstanceSigs, KindSignatures, DeriveFunctor, DeriveFoldable,
DeriveTraversable, ConstraintKinds, ExplicitNamespaces #-}
module SomeModule
(
) where
import RIO
Yeah I guess that'd do.
One might debate whether it should be like that or one-per-line which makes diffs look better, but for the purpose of ghci, that doens't matter.
We should also consider that some of these proposed ones might be controversial. For example, some consider RecordWildCards
an antipattern that makes things less readable (though that is about the usage of the {..}
, not of the language extension being enabled; it could still be enabled but one might recommend against using it in many cases), and OverloadedLists
mght be too (it can make code compile that you don't want to compile).
I’d say aggregate for the “commonly agreed-upon subset” and one per line for others, then you have the most compact representation that is amenable to good workflow.
In theory there would never be a diff for the topmost value that defines what Haskell201X
would.
Oops, I didn't have a watch set on this repo yet, so only just saw this issue. Until ghci can properly load multiple packages at once, we should not recommend any default extensions that are known to cause some code to no longer compile. There's a list here: https://github.com/commercialhaskell/stack/blob/864831f8f2d4c91e5989f2cbfbe3769c03946e0d/src/Stack/Ghci.hs#L635
So, this would mean removing OverloadedStrings
, NoImplicitPrelude
, and also GADTs
and TypeFamilies
(anything that implies MonoLocalBinds
). Ugly I know, hopefully https://ghc.haskell.org/trac/ghc/ticket/10827 gets addressed sometime. Even addressing it only for extensions would be nice.
I guess the alternative approach would be to convert libraries to using these, but that's hard if you ever want to load older packages into your ghci along with newer.
Another reason to not include OverloadedStrings
/ OverloadedLists
is that they break Paths_ modules, and hpack includes them automatically: commercialhaskell/stack#3789
For what it's worth, I've also run into stylish-haskell
choking on files that use an extension's syntax without declaring it at the top (when invoked via vscode+Haskero, anyway).
Would a middle ground be to include in the stack new PACKAGE rio
template, a .ghci
which sets the same extensions that would be set in package.yaml/cabal? Similarly .stylish-haskell.yaml
also supports setting default language extensions—or is it too much to assume people would setup projects using the stack templates?
I would personally hate to have that long list of extensions in the top, but I don't know if the other tooling, such as haskell-source-exts
, would be able to use that?
Would a middle ground be to include in the stack new PACKAGE rio template, a .ghci which sets the same extensions that would be set in package.yaml/cabal?
I don't think so, because .ghci
files don't reliably work inside version control. E.g. git resets the permissions of it on checkout, and ghci refuses to use .ghci
files if the permissions are not as it likes.
I think we're stuck with language pragmas in the modules themselves for now. The list is already documented, and in the future we can include that list in a template. Closing as complete.