floskell 0.10.5 → 0.10.6
raw patch · 16 files changed
+6259/−100 lines, 16 filesdep ~aesondep ~attoparsecdep ~basePVP: major bump suggested
API removals or changes: PVP suggests a major version bump
Dependency ranges changed: aeson, attoparsec, base, bytestring, ghc-prim
API changes (from Hackage documentation)
+ Floskell.Config: [cfgOptionAlignLetBindsAndInExpr] :: OptionConfig -> !Bool
- Floskell.Config: OptionConfig :: !Bool -> !Bool -> !SortImportsRule -> !Bool -> !Bool -> !Bool -> !Bool -> !Set DeclarationConstruct -> OptionConfig
+ Floskell.Config: OptionConfig :: !Bool -> !Bool -> !SortImportsRule -> !Bool -> !Bool -> !Bool -> !Bool -> !Set DeclarationConstruct -> !Bool -> OptionConfig
Files
- CHANGELOG.md +6/−0
- README.md +8/−8
- TEST.md +9/−0
- floskell.cabal +14/−13
- src/Floskell/Config.hs +18/−16
- src/Floskell/ConfigFile.hs +14/−3
- src/Floskell/Pretty.hs +22/−25
- src/Floskell/Styles.hs +36/−32
- src/main/Test.hs +1/−1
- stack.yaml +1/−2
- styles/base.md +961/−0
- styles/chris-done.md +1027/−0
- styles/cramer.md +1007/−0
- styles/fundamental.md +1080/−0
- styles/gibiansky.md +997/−0
- styles/johan-tibell.md +1058/−0
CHANGELOG.md view
@@ -1,3 +1,9 @@+# Floskell 0.10.6 (2021-12-14)++* Add support for building with GHC-9.0.1, GHC-9.2.1+* Fix formatting of package-qualified imports+* Avoid inserting blank lines between comments and declarations+ # Floskell 0.10.5 (2020-09-21) * Fix indentation of nested list and tuple expressions
README.md view
@@ -18,29 +18,29 @@ ## Installation - $ git clone https://github.com/ennocramer/floskell- $ cd floskell- $ stack install+ git clone https://github.com/ennocramer/floskell+ cd floskell+ stack install ## Usage Floskell can be used to reformat Haskell source files in place - $ floskell path/to/sourcefile.hs+ floskell path/to/sourcefile.hs or as a pipeline processor - $ cat path/to/sourcefile.hs | floskell > outfile.hs+ cat path/to/sourcefile.hs | floskell > outfile.hs One of the predefined formatting styles can be selected with the `--style` option - $ floskell --style cramer path/to/sourcefile.hs+ floskell --style cramer path/to/sourcefile.hs Or the style can be read from a configuration file - $ floskell --config path/to/config.json path/to/sourcefile.hs+ floskell --config path/to/config.json path/to/sourcefile.hs If neither style nor configuration file is given on the command line, Floskell will try to find a configuration file in the current working@@ -238,7 +238,7 @@ The `--print-config` command line option can be used to create an initial configuration file. - $ floskell --style cramer --print-config > ~/.floskell.json+ floskell --style cramer --print-config > ~/.floskell.json This command will create a configuration file with all fields and the entire definition of the selected style in the `formatting` block.
TEST.md view
@@ -156,6 +156,7 @@ import qualified Data.ByteString (ByteString,pack,unpack) import qualified Data.ByteString as BS (pack, unpack) import Control.Monad hiding (forM)+import {-# SOURCE #-} safe qualified "foo" Foo as F ``` ## Decl@@ -860,6 +861,14 @@ where {-# INLINE_LATE step1 #-} step1 _ _ = undefined+```++Comments between declarations do not cause empty lines.++``` haskell+f :: ()+--+f = () ``` ## Indentation and Line Prefixes
floskell.cabal view
@@ -1,6 +1,6 @@ cabal-version: >=1.10 name: floskell-version: 0.10.5+version: 0.10.6 license: BSD3 license-file: LICENSE.md copyright:@@ -31,6 +31,7 @@ BENCHMARK.md TEST.md stack.yaml+ styles/*.md source-repository head type: git@@ -55,10 +56,10 @@ default-language: Haskell2010 ghc-options: -Wall build-depends:- base >=4.9 && <4.15,- aeson >=0.11.3.0 && <1.6,- attoparsec >=0.13.1.0 && <0.14,- bytestring >=0.10.8.1 && <0.11,+ base >=4.9 && <4.17,+ aeson >=0.11.3.0 && <2.1,+ attoparsec >=0.13.1.0 && <0.15,+ bytestring >=0.10.8.1 && <0.12, containers >=0.5.7.1 && <0.7, data-default >=0.7.1.1 && <0.8, directory >=1.2.6.2 && <1.4,@@ -79,12 +80,12 @@ -Wall -Wno-missing-home-modules -optP-Wno-nonportable-include-path build-depends:- base >=4.9 && <4.15,+ base >=4.9 && <4.17, floskell -any, aeson-pretty >=0.8.2 && <0.9,- bytestring >=0.10.8.1 && <0.11,+ bytestring >=0.10.8.1 && <0.12, directory >=1.2.6.2 && <1.4,- ghc-prim >=0.5.0.0 && <0.7,+ ghc-prim >=0.5.0.0 && <0.9, haskell-src-exts >=1.19 && <1.24, optparse-applicative >=0.12.1.0 && <0.17, text >=1.2.2.2 && <1.3@@ -97,9 +98,9 @@ default-language: Haskell2010 ghc-options: -Wall -threaded -rtsopts -with-rtsopts=-N build-depends:- base >=4.9 && <4.15,+ base >=4.9 && <4.17, floskell -any,- bytestring >=0.10.8.1 && <0.11,+ bytestring >=0.10.8.1 && <0.12, deepseq >=1.4.2.0 && <1.5, exceptions >=0.8.3 && <0.12, haskell-src-exts >=1.19 && <1.24,@@ -115,13 +116,13 @@ default-language: Haskell2010 ghc-options: -Wall -threaded -rtsopts -with-rtsopts=-N build-depends:- base >=4.9 && <4.15,+ base >=4.9 && <4.17, floskell -any,- bytestring >=0.10.8.1 && <0.11,+ bytestring >=0.10.8.1 && <0.12, criterion >=1.1.1.0 && <1.6, deepseq >=1.4.2.0 && <1.5, exceptions >=0.8.3 && <0.11,- ghc-prim >=0.5.0.0 && <0.7,+ ghc-prim >=0.5.0.0 && <0.9, haskell-src-exts >=1.19 && <1.24, text >=1.2.2.2 && <1.3, utf8-string >=1.0.1.1 && <1.1
src/Floskell/Config.hs view
@@ -221,26 +221,28 @@ deriving ( Eq, Ord, Generic ) data OptionConfig =- OptionConfig { cfgOptionSortPragmas :: !Bool- , cfgOptionSplitLanguagePragmas :: !Bool- , cfgOptionSortImports :: !SortImportsRule- , cfgOptionSortImportLists :: !Bool- , cfgOptionAlignSumTypeDecl :: !Bool- , cfgOptionFlexibleOneline :: !Bool- , cfgOptionPreserveVerticalSpace :: !Bool- , cfgOptionDeclNoBlankLines :: !(Set DeclarationConstruct)+ OptionConfig { cfgOptionSortPragmas :: !Bool+ , cfgOptionSplitLanguagePragmas :: !Bool+ , cfgOptionSortImports :: !SortImportsRule+ , cfgOptionSortImportLists :: !Bool+ , cfgOptionAlignSumTypeDecl :: !Bool+ , cfgOptionFlexibleOneline :: !Bool+ , cfgOptionPreserveVerticalSpace :: !Bool+ , cfgOptionDeclNoBlankLines :: !(Set DeclarationConstruct)+ , cfgOptionAlignLetBindsAndInExpr :: !Bool } deriving ( Generic ) instance Default OptionConfig where- def = OptionConfig { cfgOptionSortPragmas = False- , cfgOptionSplitLanguagePragmas = False- , cfgOptionSortImports = NoImportSort- , cfgOptionSortImportLists = False- , cfgOptionAlignSumTypeDecl = False- , cfgOptionFlexibleOneline = False- , cfgOptionPreserveVerticalSpace = False- , cfgOptionDeclNoBlankLines = Set.empty+ def = OptionConfig { cfgOptionSortPragmas = False+ , cfgOptionSplitLanguagePragmas = False+ , cfgOptionSortImports = NoImportSort+ , cfgOptionSortImportLists = False+ , cfgOptionAlignSumTypeDecl = False+ , cfgOptionFlexibleOneline = False+ , cfgOptionPreserveVerticalSpace = False+ , cfgOptionDeclNoBlankLines = Set.empty+ , cfgOptionAlignLetBindsAndInExpr = False } data Config = Config { cfgPenalty :: !PenaltyConfig
src/Floskell/ConfigFile.hs view
@@ -1,6 +1,8 @@+{-# LANGUAGE CPP #-} {-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE CPP #-} module Floskell.ConfigFile ( AppConfig(..)@@ -27,12 +29,21 @@ import Data.Aeson ( (.:?), (.=), FromJSON(..), ToJSON(..) ) import qualified Data.Aeson as JSON-import qualified Data.Aeson.Parser as JSON ( json' ) import qualified Data.Aeson.Types as JSON ( typeMismatch )+#if MIN_VERSION_aeson(2,0,0)+import qualified Data.Aeson.KeyMap as JSON ( unionWith )+#endif import qualified Data.Attoparsec.ByteString as AP import qualified Data.ByteString as BS import Data.Char ( isLetter, isSpace )-import qualified Data.HashMap.Lazy as HashMap++#if MIN_VERSION_aeson(2,0,0)+import qualified Data.Aeson.KeyMap as Map+#else+import qualified Data.Aeson.Parser as JSON ( json' )+import qualified Data.HashMap.Lazy as Map+#endif+ import Data.List ( inits ) import qualified Data.Text as T @@ -90,7 +101,7 @@ mergeJSON JSON.Null r = r mergeJSON l JSON.Null = l mergeJSON (JSON.Object l) (JSON.Object r) =- JSON.Object (HashMap.unionWith mergeJSON l r)+ JSON.Object (Map.unionWith mergeJSON l r) mergeJSON _ r = r parseJSON v = JSON.typeMismatch "AppConfig" v
src/Floskell/Pretty.hs view
@@ -392,12 +392,12 @@ go (col - correction) xs where go _ [] = return ()- go col [x'] = do+ go col [ x' ] = do printComments Before x' column col $ operator ctx sep prettyPrint x' printComments After x'- go col (x':xs') = do+ go col (x' : xs') = do printComments Before x' cut $ do column col $ operator ctx sep@@ -512,14 +512,6 @@ where prettyGroups = inter blankline . map (inter newline . map (cut . pretty)) -skipBlank :: Annotated ast- => (ast NodeInfo -> ast NodeInfo -> Bool)- -> ast NodeInfo- -> ast NodeInfo- -> Bool-skipBlank skip a b = skip a b && null (filterComments After a)- && null (filterComments Before b)- skipBlankAfterDecl :: Decl a -> Bool skipBlankAfterDecl a = case a of TypeSig{} -> True@@ -536,17 +528,17 @@ _ -> False skipBlankDecl :: Decl NodeInfo -> Decl NodeInfo -> Bool-skipBlankDecl = skipBlank $ \a _ -> skipBlankAfterDecl a+skipBlankDecl a _ = skipBlankAfterDecl a skipBlankClassDecl :: ClassDecl NodeInfo -> ClassDecl NodeInfo -> Bool-skipBlankClassDecl = skipBlank $ \a _ -> case a of+skipBlankClassDecl a _ = case a of (ClsDecl _ decl) -> skipBlankAfterDecl decl ClsTyDef{} -> True ClsDefSig{} -> True _ -> False skipBlankInstDecl :: InstDecl NodeInfo -> InstDecl NodeInfo -> Bool-skipBlankInstDecl = skipBlank $ \a _ -> case a of+skipBlankInstDecl a _ = case a of (InsDecl _ decl) -> skipBlankAfterDecl decl _ -> False @@ -767,12 +759,13 @@ instance Pretty ImportDecl where prettyPrint ImportDecl{..} = do- inter space . map write $- filter (not . BS.null)+ inter space . map string $+ filter (not . null) [ "import" , if importSrc then "{-# SOURCE #-}" else "" , if importSafe then "safe" else "" , if importQualified then "qualified" else ""+ , maybe "" show importPkg ] atTabStop stopImportModule space@@ -1618,18 +1611,22 @@ write "let " prettyOnside (CompactBinds binds) spaceOrNewline- write "in "+ nl <- gets psNewline+ alignP <- getOption cfgOptionAlignLetBindsAndInExpr+ write $ if nl && alignP then "in " else "in " prettyOnside expr - vertical = withIndentAfter cfgIndentLet- (do- write "let"- withIndent cfgIndentLetBinds $- pretty (CompactBinds binds))- (do- newline- write "in"- withIndent cfgIndentLetIn $ pretty expr)+ vertical = withIndentAfter+ cfgIndentLet+ (do+ write "let"+ withIndent cfgIndentLetBinds $+ pretty (CompactBinds binds))+ (do+ newline+ alignP <- getOption cfgOptionAlignLetBindsAndInExpr+ write $ if alignP then "in " else "in"+ withIndent cfgIndentLetIn $ pretty expr) prettyPrint (If _ expr expr' expr'') = withLayout cfgLayoutIf flex vertical where
src/Floskell/Styles.hs view
@@ -79,14 +79,15 @@ groupWsOverrides = [] - cfgOptions = OptionConfig { cfgOptionSortPragmas = False- , cfgOptionSplitLanguagePragmas = False- , cfgOptionSortImports = NoImportSort- , cfgOptionSortImportLists = False- , cfgOptionAlignSumTypeDecl = True- , cfgOptionFlexibleOneline = False- , cfgOptionPreserveVerticalSpace = False- , cfgOptionDeclNoBlankLines = Set.empty+ cfgOptions = OptionConfig { cfgOptionSortPragmas = False+ , cfgOptionSplitLanguagePragmas = False+ , cfgOptionSortImports = NoImportSort+ , cfgOptionSortImportLists = False+ , cfgOptionAlignSumTypeDecl = True+ , cfgOptionFlexibleOneline = False+ , cfgOptionPreserveVerticalSpace = False+ , cfgOptionDeclNoBlankLines = Set.empty+ , cfgOptionAlignLetBindsAndInExpr = False } cramerCfg :: Config@@ -192,14 +193,15 @@ ] cfgOptions =- OptionConfig { cfgOptionSortPragmas = True- , cfgOptionSplitLanguagePragmas = True- , cfgOptionSortImports = SortImportsByPrefix- , cfgOptionSortImportLists = True- , cfgOptionAlignSumTypeDecl = False- , cfgOptionFlexibleOneline = False- , cfgOptionPreserveVerticalSpace = True- , cfgOptionDeclNoBlankLines = Set.empty+ OptionConfig { cfgOptionSortPragmas = True+ , cfgOptionSplitLanguagePragmas = True+ , cfgOptionSortImports = SortImportsByPrefix+ , cfgOptionSortImportLists = True+ , cfgOptionAlignSumTypeDecl = False+ , cfgOptionFlexibleOneline = False+ , cfgOptionPreserveVerticalSpace = True+ , cfgOptionDeclNoBlankLines = Set.empty+ , cfgOptionAlignLetBindsAndInExpr = False } gibianskyCfg :: Config@@ -280,14 +282,15 @@ groupWsOverrides = [ (ConfigMapKey (Just "{") Nothing, Whitespace WsBoth WsAfter False) ] - cfgOptions = OptionConfig { cfgOptionSortPragmas = False- , cfgOptionSplitLanguagePragmas = False- , cfgOptionSortImports = NoImportSort- , cfgOptionSortImportLists = False- , cfgOptionAlignSumTypeDecl = False- , cfgOptionFlexibleOneline = False- , cfgOptionPreserveVerticalSpace = False- , cfgOptionDeclNoBlankLines = Set.empty+ cfgOptions = OptionConfig { cfgOptionSortPragmas = False+ , cfgOptionSplitLanguagePragmas = False+ , cfgOptionSortImports = NoImportSort+ , cfgOptionSortImportLists = False+ , cfgOptionAlignSumTypeDecl = False+ , cfgOptionFlexibleOneline = False+ , cfgOptionPreserveVerticalSpace = False+ , cfgOptionDeclNoBlankLines = Set.empty+ , cfgOptionAlignLetBindsAndInExpr = False } johanTibellCfg :: Config@@ -367,14 +370,15 @@ ) ] - cfgOptions = OptionConfig { cfgOptionSortPragmas = False- , cfgOptionSplitLanguagePragmas = False- , cfgOptionSortImports = NoImportSort- , cfgOptionSortImportLists = False- , cfgOptionAlignSumTypeDecl = True- , cfgOptionFlexibleOneline = True- , cfgOptionPreserveVerticalSpace = False- , cfgOptionDeclNoBlankLines = Set.empty+ cfgOptions = OptionConfig { cfgOptionSortPragmas = False+ , cfgOptionSplitLanguagePragmas = False+ , cfgOptionSortImports = NoImportSort+ , cfgOptionSortImportLists = False+ , cfgOptionAlignSumTypeDecl = True+ , cfgOptionFlexibleOneline = True+ , cfgOptionPreserveVerticalSpace = False+ , cfgOptionDeclNoBlankLines = Set.empty+ , cfgOptionAlignLetBindsAndInExpr = False } -- | Base style definition.
src/main/Test.hs view
@@ -10,7 +10,7 @@ import Data.ByteString.Lazy ( ByteString ) import qualified Data.ByteString.Lazy as L-import qualified Data.ByteString.Lazy.Builder as B+import qualified Data.ByteString.Builder as B ( toLazyByteString ) import qualified Data.ByteString.Lazy.UTF8 as UTF8 import Data.Maybe ( mapMaybe ) import qualified Data.Text as T
stack.yaml view
@@ -1,6 +1,5 @@-resolver: lts-16.3+resolver: lts-18.18 packages: - '.' extra-deps:-- haskell-src-exts-1.23.1 - monad-dijkstra-0.1.1.3
+ styles/base.md view
@@ -0,0 +1,961 @@+# Introduction++This file acts both as a presentation of the Floskell formatting+styles, as well as a set of regression tests.++You can see how a particular style will format Haskell source by+reading the matching Markdown file in the styles/ directory.++For regression testing, the canonical source, TEST.md in the root+directory, is parsed and each Haskell code block formatted according+to all predefined styles. The formatted output is then compared with+the corresponding, already formatted code block in the <style\>.md file+in the styles/ subdirectory.++The regression test will also verify that repeated invocations of the+pretty printer will not modify an already formatted piece of code.++The following code block acts as a quick presentation for the+different formatting styles, by presenting a mixture of common Haskell+constructs.++``` haskell+{-# OPTIONS_GHC -fno-warn-name-shadowing #-}++{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards #-}++{- |+Module: Style.Haskell.Example++Haskell Code Style Example.+-}+module Style.Haskell.Example (+ -- * Types+ Enum(..), Either(..), Point(..)+ -- * Functions+ , hello ) where++-- Module imports+import qualified Control.Monad.Trans.State+ ( State, evalState, execState, get, modify, put, runState )+import qualified Data.Map as Map+import qualified Data.Text as Text+import Prelude hiding ( map )++-- Data declarations+data Enum = CaseA | CaseB | CaseC+ deriving ( Eq, Enum, Show )++data Either a b = Left a | Right b+ deriving ( Eq, Show )++data Point = Point { pointX :: Float, pointY :: Float, pointLabel :: String }+ deriving ( Eq, Show )++-- Type classes+class Functor f => Applicative a where+ pure :: b -> a b+ ap :: a (b -> c) -> a b -> a c++class Fundep a b | a -> b where+ convert :: a -> b++instance Functor f => Functor (Wrap f) where+ fmap f (Wrap x) = Wrap $ fmap f x++-- Values+origin :: Point+origin = Point { pointX = 0, pointY = 0, pointLabel = "Origin" }++lorem :: [ String ]+lorem = [ "Lorem ipsum dolor sit amet, consectetur adipiscing elit."+ , "Curabitur nec ante nec mauris ornare suscipit."+ , "In ac vulputate libero."+ , "Duis eget magna non purus imperdiet molestie nec quis mauris."+ , "Praesent blandit quam vel arcu pellentesque, id aliquet turpis faucibus."+ ]++-- Functions+facs :: [ Int ]+facs = [ 1, 1 ] ++ zipWith (+) (tailfacs)++hello :: MonadIO m => m ()+hello = do+ name <- liftIO getLine+ liftIO . putStrLn $ greetings name+ where+ greetings n = "Hello " ++ n ++ "!"++letExpr :: Point -> String+letExp x = let y = 1+ z = 2 in if x > 0 then y else z++ifExpr :: Bool -> Bool+ifExpr b = if b == True then False else True++caseExpr :: [ a ] -> Maybe a+caseExpr xs = case xs of+ [] -> Nothing+ (x : _) -> Just x++guarded :: Int -> Int+guarded x+ | x == 0 = 1+ | x == 1 = 1+ | otherwise = guarded (x - 2) + guarded (x - 1)++someLongFunctionNameWithALotOfParameters :: ( MonadIO m, MonadRandom m )+ => String -> (String -> String) -> m ()+someLongFunctionNameWithALotOfParameters = undefined+```++# Unit Tests++## ModuleHead and ExportSpecList++Without exports++``` haskell+module Main where+```++With exports++``` haskell+module Main ( foo, bar, baz, main ) where+```++With exports and comments++``` haskell+module Main (+ -- * Main Program+ main+ -- * Functions+ , foo -- foo function+ , bar -- bar function+ , baz -- baz function+ ) where+```++With deprecation++``` haskell+module Main {-# DEPRECATED "no longer supported" #-} where+```++With warnings++``` haskell+module Main {-# WARNING "do not use" #-} where+```++## ImportDecl++``` haskell+import Prelude+import Data.Text ( Text )+import qualified Data.Text as T+import qualified Data.ByteString ( ByteString, pack, unpack )+import qualified Data.ByteString as BS ( pack, unpack )+import Control.Monad hiding ( forM )+import {-# SOURCE #-} safe qualified "foo" Foo as F+```++## Decl++### TypeDecl++``` haskell+type Name = String++type Pair a = ( a, a )++type Fun a b = a -> b+```++### DataDecl and GDataDecl++``` haskell+data Void++data Unit = Unit++data Maybe a = Nothing | Just a++data Num a => SomeNum = SomeNum a++newtype RWS r w s = RWS (ReaderT r (WriterT w (StateT s Identity)))+ deriving ( Functor, Applicative, Monad )++data Enum = One -- Foo+ | Two -- Bar+ | Three -- Baz++data Foo+ deriving ()++data Foo+ deriving Show++data Foo+ deriving ( Show )++data Foo+ deriving ( Eq, Ord )++data Expr :: * -> * where+ Const :: Int -> Expr Int+ Plus :: Expr Int -> Expr Int -> Expr Int+ Eq :: Expr Int -> Expr Int -> Expr Bool+ deriving ( Show )++data Term a where+ Lit :: { val :: Int } -> Term Int+ Succ :: { num :: Term Int } -> Term Int+ Pred :: { num :: Term Int } -> Term Int+ IsZero :: { arg :: Term Int } -> Term Bool+ Pair :: { arg1 :: Term a, arg2 :: Term b } -> Term ( a, b )+ If :: { cnd :: Term Bool, tru :: Term a, fls :: Term a } -> Term a+```++### TypeFamDecl, TypeInsDecl, and ClosedTypeFamDecl++``` haskell+type family Mutable v++type family Mutable v = (r :: *)++type family Mutable v = r | r -> v++type instance Mutable Int = MIntVector++type family Store a where+ Store Bool = [ Int ]+ Store a = [ a ]++type family Store a = (r :: *) where+ Store a = [ a ]++type family Store a = r | r -> a where+ Store a = [ a ]+```++### DataFamDecl, DataInsDecl, and GDataInsDecl++``` haskell+data family List a++data instance List () = NilList Int++data instance List Char = CharNil | CharCons Char (List Char)+ deriving ( Eq, Ord, Show )++data instance List Int :: * where+ IntNil :: List Int+ IntCons :: Int -> List Int+ deriving ( Eq, Ord, Show )++data instance List Int :: * where+ IntNil :: List Int+ IntCons :: { val :: Int } -> List Int+ deriving ( Eq, Ord, Show )++newtype Penalty = Penalty Int+ deriving ( Eq, Ord )+ deriving stock ( Read, Show )+ deriving newtype ( Num )+ deriving anyclass ( FromJSON, ToJSON )+ deriving ( Semigroup, Monoid ) via M.Sum Int+```++### ClassDecl and InstDecl++``` haskell+class Monoid a where+ mempty :: a+ mappend :: a -> a -> a++class Applicative m => Monad m where+ fail :: m a+ return :: a -> m a+ (>>=) :: a -> (a -> m b) -> m b++class Monad m => MonadState s m | m -> s where+ get :: m s+ put :: s -> m ()+ state :: (s -> ( a, s )) -> m a++class ToJSON a where+ toJSON :: a -> Value+ default toJSON :: ( Generic a, GToJSON (Rep a) ) => a -> Value+ toJSON = genericToJSON defaultOptions++instance ToJSON ()++instance Bounded Bool where+ minBound = False++ maxBound = True++instance Semigroup a => Monoid (Maybe a) where+ mempty = Nothing++ Nothing `mappend` m = m+ m `mappend` Nothing = m+ Just m1 `mappend` Just m2 = Just (m1 `mappend` m2)++instance Data () where+ type Base = ()++ newtype Wrapped = Wrapped { unWrap :: () }++ data Expr :: * -> * where+ Const :: Int -> Expr Int+ Plus :: Expr Int -> Expr Int -> Expr Int+ Eq :: Expr Int -> Expr Int -> Expr Bool+```++### DerivDecl++``` haskell+deriving instance Eq a => Eq (Sum a)++deriving instance {-# OVERLAP #-} Eq a => Eq (Sum a)++deriving stock instance {-# OVERLAPS #-} Eq a => Eq (Sum a)++deriving anyclass instance {-# OVERLAPPING #-} Eq a => Eq (Sum a)++deriving newtype instance {-# OVERLAPPABLE #-} Eq a => Eq (Sum a)+```++### InfixDecl++``` haskell+infix 4 ==, /=, <, <=, >, >=++infixr 0 $++infixl !!+```++### DefaultDecl++``` haskell+default ()++default ( Integer, Double )+```++### SpliceDecl++``` haskell+$foo++$( bar baz )+```++### TypeSig++``` haskell+id :: a -> a+sort :: Ord a => [ a ] -> [ a ]+long :: ( IsString a, Monad m ) => ByteString+ -> ByteString -> ByteString -> ByteString -> ByteString -> a -> m ()+mktime :: Int -- hours+ -> Int -- minutes+ -> Int -- seconds+ -> Time+transform :: forall a. St -> State St a -> EitherT ServantErr IO a+```++### PatSyn and PatSynSig++``` haskell+{-# LANGUAGE PatternSynonyms #-}++pattern MyJust :: a -> Maybe a+pattern MyJust a = Just a++pattern MyPoint :: Int -> Int -> ( Int, Int )+pattern MyPoint { x, y } = ( x, y )++pattern ErrorCall :: String -> ErrorCall+pattern ErrorCall s <- ErrorCallWithLocation s _+ where+ ErrorCall s = ErrorCallWithLocation s ""++pattern IsTrue :: Show a => a+pattern IsTrue <- ((== "True") . show -> True)++pattern ExNumPat :: () => Show b => b -> T+pattern ExNumPat x = MkT x++pattern Foo, Bar :: Show a => a+```++### FunBind and PatBind++``` haskell+{-# LANGUAGE UnboxedTuples #-}+{-# LANGUAGE UnboxedSums #-}+{-# LANGUAGE RecordWildCards #-}++pi = 3.14++id x = x++not False = True+not _ = False++head (x : _) = x++maybe x _ Nothing = x+maybe _ f (Some x) = f x++fst ( x, _ ) = x++fst' (# x, _ #) = x++fstPrism (# x | | #) = Just x+fstPrism (# | _ | #) = Nothing+fstPrism (# | | _ #) = Nothing++empty [] = True+empty _ = False++unSum (Sum { getSum = s }) = s++mag2 Point { x, y } = sqr x + sqr y+mag2 Point { .. } = sqr x + sqr y++strict !x = x++irrefutable ~x = x++(//) a b = undefined++a // b = undefined++main = do+ greet "World"+ where+ greet who = putStrLn $ "Hello, " ++ who ++ "!"+```++### ForImp and ForExp++``` haskell+{-# LANGUAGE ForeignFunctionInterface #-}++foreign import ccall sin :: Double -> Double++foreign import ccall "sin" sin :: Double -> Double++foreign import ccall "sin" sin :: Double -> Double++foreign import ccall unsafe exit :: Double -> Double++foreign export ccall callback :: Int -> Int+```++### Pragmas++``` haskell+{-# RULES #-}++{-# RULES "map/map" forall f g xs. map f (map g xs) = map (f . g) xs #-}++{-# RULES "map/append" [2] forall f xs ys. map f (xs ++ ys)+ = map f xs ++ map f ys #-}++{-# DEPRECATED #-}+{-# DEPRECATED foo "use bar instead" #-}+{-# DEPRECATED foo, bar, baz "no longer supported" #-}+{-# WARNING #-}+{-# WARNING foo "use bar instead" #-}+{-# WARNING foo, bar, baz "no longer supported" #-}+{-# INLINE foo #-}+{-# INLINE [3] foo #-}+{-# INLINE [~3] foo #-}+{-# NOINLINE foo #-}+{-# INLINE CONLIKE foo #-}+{-# INLINE CONLIKE [3] foo #-}+{-# SPECIALISE foo :: Int -> Int #-}+{-# SPECIALISE [3] foo :: Int -> Int, Float -> Float #-}+{-# SPECIALISE INLINE foo :: Int -> Int #-}+{-# SPECIALISE NOINLINE foo :: Int -> Int #-}+{-# SPECIALISE instance Foo Int #-}+{-# SPECIALISE instance forall a. (Ord a) => Foo a #-}+{-# ANN foo (Just "Foo") #-}+{-# ANN type Foo (Just "Foo") #-}+{-# ANN module (Just "Foo") #-}+{-# MINIMAL foo | bar, (baz | quux) #-}+```++## Exp++### Var, Con, Lit, Tuple, UnboxedSum, List, and ExpTypeSig++``` haskell+{-# LANGUAGE TupleSections #-}+{-# LANGUAGE UnboxedTuples #-}+{-# LANGUAGE UnboxedSums #-}++foo = foo++foo = Nothing++foo = 123++foo = 'x'++foo = ""++foo = "Lorem Ipsum Dolor Amet Sit"++foo = ()++foo = ( 1, 2 )++foo = ( 1 -- the one+ , 2+ )++foo = ( 1, )++foo = ( , 2 )++foo = ( , 2, )++foo = (# #)++foo = (# 1, 2 #)++foo = (# 1 -- the one+ , 2+ #)++foo = (# 1 #)++foo = (# | 1 | | #)++foo = (# | 1 -- the one+ | |+ #)++foo = []++foo = [ 1 ]++foo = [ 1, 2 ]++foo = [ 1 -- the one+ , 2+ ]++foo = 1 :: Int+```++### App, InfixApp, NegApp, LeftSection, RightSection++``` haskell+foo = foldl fn init list++foo = foldl fn -- reducer+ init -- initial value+ list++foo = 1 + 2++foo = fn `map` list++foo = -3++foo = (+ arg)++foo = (`op` arg)++foo = (arg +)++foo = (arg `op`)+```++### EnumFrom, EnumFromTo, EnumFromThen, EnumFromThenTo, ParArrayFromTo, ParArrayFromThenTo++``` haskell+foo = [ 1 .. ]++foo = [ 1 .. 10 ]++foo = [ 1, 2 .. ]++foo = [ 1, 2 .. 10 ]++foo = [: 1 .. 10 :]++foo = [: 1, 2 .. 10 :]+```++### ListComp, ParComp, and ParArrayComp++``` haskell+{-# LANGUAGE TransformListComp #-}++foo = [ ( x, y ) | x <- xs, y <- ys ]++foo = [ ( x, y ) -- cartesian product+ | x <- xs -- first list+ , y <- ys -- second list+ ]++foo = [ ( x, y ) | x <- xs | y <- ys ]++foo = [ ( x, y ) -- zip+ | x <- xs -- first list+ | y <- ys -- second list+ ]++foo = [: ( x, y ) | x <- xs | y <- ys :]++foo = [: ( x, y ) -- zip+ | x <- xs -- first list+ | y <- ys -- second list+ :]++foo = [ ( x, y ) | x <- xs+ , y <- ys+ , then reverse+ , then sortWith by (x + y)+ , then group using permutations+ , then group by (x + y) using groupWith+ ]+```++### RecConstr and RecUpdate++``` haskell+{-# LANGUAGE RecordWildCards #-}++foo = Point { x = 1, y = 2 }++foo = Point { x = 1 -- the one+ , y, .. }++foo = bar { x = 1 }++foo = bar { x = 1 -- the one+ , y, .. }+```++### Let, If, MultiIf, and Case++``` haskell+{-# LANGUAGE MultiWayIf #-}++foo = let x = x in x++foo = let x = x -- bottom+ in + -- bottom+ x++foo = if null xs then None else Some $ head xs++foo = if null xs -- condition+ then None -- it's empty+ else Some $ head xs -- it's not++foo = if+ | null xs -> None+ | otherwise -> Some $ head xs++foo = if+ | null xs ->+ -- it's empty+ None+ | otherwise ->+ -- it's not+ Some $ head x++foo = case x of+ True -> False+ False -> True++foo = case xs of+ [] ->+ -- it's empty+ None+ x : _ ->+ -- it's not+ Some x++foo = case xs of+ _+ | null xs -> None+ _ -> Some $ head x+```++### Do and MDo++``` haskell+{-# LANGUAGE RecursiveDo #-}++foo = do+ return ()++foo = do+ return ()++foo = do+ this <- that+ let this' = tail this+ if this -- condition+ then that else those++foo = mdo+ return ()+```++### Lambda, LCase++``` haskell+{-# LANGUAGE LambdaCase #-}++foo = \x -> x++foo = \ ~x -> x++foo = \ !x -> x++foo d = \case+ Nothing -> d+ Some x -> x+```++### BracketExp, SpliceExp, QuasiQuote, VarQuote, and TypQuote++``` haskell+{-# LANGUAGE TemplateHaskell #-}++mkDecl :: Q Decl+mkDecl = [d| id x = x |]++mkType :: Q Type+mkType = [t| ( a, b ) -> a |]++mkPat :: Q Pat+mkPat = [p| ( a, b ) |]++mkExp :: Q Exp+mkExp = [| a |]++fst :: $( mkType )+fst $( mkPat ) = $( mkExp )++html = [html|<p>Lorem Ipsum Dolor Amet Sit</p>|]++foo = mkSomething 'id 'Nothing ''Maybe+```++# Regression Tests++## Do++Before comments and onside indent do not mix well.++``` haskell+foo = do+ -- comment+ some expression+```++## Types++Long types allow linebreaks.++``` haskell+newtype MyMonadT a b m+ = MyMonad { runMyMonad :: StateT ([ ( a, a -> b ) ])+ (ReaderT a (ExceptT [ IM.IntMap b ]) (WriterT [ IS.IntSet x ] m)) }+```++Promoted types.++``` haskell+type Foo = Bar 1 "foo" '() '( A, B ) '[ X, Y ]+```++## Patterns++Long function pattern matches allow linebreaks.++``` haskell+doThing (Constructor field1 field2 field3) (Constructor field1 field2 field3)+ (Constructor field1 field2 field3) = undefined+```++## Onside++Indent within onside started on non-empty line should still not stack.++``` haskell+foo = if cond then do+ this else do+ that+```++Before comments at the start of onside do not trigger onside.++``` haskell+foo = do+ -- comment+ some expression+```++Matche arms have individual onside.++``` haskell+foo True = some -- comment+ expression+foo False = some -- comment+ other expression+```++Where binds are considered outside of onside.++``` haskell+foo = some -- comment+ expression+ where+ expression = other+```++Align overrides onside.++``` haskell+foo = some expr [ 1 -- comment+ , 2+ ]+```++If-then-else must always indent in do blocks.++``` haskell+foo = do+ if condition -- comment+ then this else that+```++Lists must not suppress onside.++``` haskell+foo = case x of+ [ y -- comment+ , z+ ] -> bar++foo = do+ [ x -- comment+ , y+ ]+```++## Comments++Don't be too eager in assigning comments to the following AST node.++``` haskell+data Foo = Foo { fooBar :: Text+ -- ^A comment, long enough to end up on its own line, or at least I hope so.+ }+ deriving ( Eq )+```++Keep comments together and aligned.++``` haskell+-- block+-- one+data Foo = Foo -- some+ -- comments+ | Quux -- more+ -- comments+-- block+-- two+```++... even when haskell-src-exts has weird column span info.++``` haskell+module Main where++-- comment+instance Foo Bar where+ foo = undefined++bar = undefined+```++Only comments.++``` haskell+-- some comment+```++Make sure no comments are dropped from operators or argument.++``` haskell+foo = some -- comment 1+ -- comment 2+ %~ -- comment 3+ argument -- comment 4+```++Comments after `where` stay there.++``` haskell+consM :: Monad m => m a -> Stream m a -> Stream m a+consM m (Stream step state) = Stream step1 Nothing+ where+ {-# INLINE_LATE step1 #-}+ step1 _ _ = undefined+```++Comments between declarations do not cause empty lines.++``` haskell+f :: ()+--+f = ()+```++## Indentation and Line Prefixes++Preserving indentation and line prefixes so that Floskell can be run+on individual declarations and quoted haskell code.++``` haskell+ data Enum = One -- Foo+ | Two -- Bar+ | Three -- Baz+```++``` haskell+>+> data Enum = One -- Foo+> | Two -- Bar+> | Three -- Baz+>+```++## Module Exports++Long module exports don't force overlong line.++``` haskell+module SimpleFunctions ( identity, compose, append, firstElement+ , secondElem ) where+```
+ styles/chris-done.md view
@@ -0,0 +1,1027 @@+# Introduction++This file acts both as a presentation of the Floskell formatting+styles, as well as a set of regression tests.++You can see how a particular style will format Haskell source by+reading the matching Markdown file in the styles/ directory.++For regression testing, the canonical source, TEST.md in the root+directory, is parsed and each Haskell code block formatted according+to all predefined styles. The formatted output is then compared with+the corresponding, already formatted code block in the <style\>.md file+in the styles/ subdirectory.++The regression test will also verify that repeated invocations of the+pretty printer will not modify an already formatted piece of code.++The following code block acts as a quick presentation for the+different formatting styles, by presenting a mixture of common Haskell+constructs.++``` haskell+{-# OPTIONS_GHC -fno-warn-name-shadowing #-}++{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards #-}++{- |+Module: Style.Haskell.Example++Haskell Code Style Example.+-}+module Style.Haskell.Example+ (-- * Types+ Enum(..)+ ,Either(..)+ ,Point(..)+ -- * Functions+ ,hello) where++-- Module imports+import qualified Control.Monad.Trans.State+ (State,evalState,execState,get,modify,put,runState)+import qualified Data.Map as Map+import qualified Data.Text as Text+import Prelude hiding (map)++-- Data declarations+data Enum+ = CaseA+ | CaseB+ | CaseC+ deriving (Eq,Enum,Show)++data Either a b+ = Left a+ | Right b+ deriving (Eq,Show)++data Point =+ Point {pointX :: Float+ ,pointY :: Float+ ,pointLabel :: String}+ deriving (Eq,Show)++-- Type classes+class Functor f => Applicative a where+ pure :: b -> a b+ ap :: a (b -> c) -> a b -> a c++class Fundep a b | a -> b where+ convert :: a -> b++instance Functor f => Functor (Wrap f) where+ fmap f (Wrap x) = Wrap $ fmap f x++-- Values+origin :: Point+origin =+ Point {pointX = 0+ ,pointY = 0+ ,pointLabel = "Origin"}++lorem :: [String]+lorem =+ ["Lorem ipsum dolor sit amet, consectetur adipiscing elit."+ ,"Curabitur nec ante nec mauris ornare suscipit."+ ,"In ac vulputate libero."+ ,"Duis eget magna non purus imperdiet molestie nec quis mauris."+ ,"Praesent blandit quam vel arcu pellentesque, id aliquet turpis faucibus."]++-- Functions+facs :: [Int]+facs = [1,1] ++ zipWith (+) (tailfacs)++hello :: MonadIO m => m ()+hello =+ do name <- liftIO getLine+ liftIO . putStrLn $ greetings name+ where greetings n = "Hello " ++ n ++ "!"++letExpr :: Point -> String+letExp x =+ let y = 1+ z = 2+ in if x > 0+ then y+ else z++ifExpr :: Bool -> Bool+ifExpr b =+ if b == True+ then False+ else True++caseExpr :: [a] -> Maybe a+caseExpr xs =+ case xs of+ [] -> Nothing+ (x:_) -> Just x++guarded :: Int -> Int+guarded x+ | x == 0 = 1+ | x == 1 = 1+ | otherwise = guarded (x - 2) + guarded (x - 1)++someLongFunctionNameWithALotOfParameters+ :: (MonadIO m,MonadRandom m) => String -> (String -> String) -> m ()+someLongFunctionNameWithALotOfParameters = undefined+```++# Unit Tests++## ModuleHead and ExportSpecList++Without exports++``` haskell+module Main where+```++With exports++``` haskell+module Main (foo,bar,baz,main) where+```++With exports and comments++``` haskell+module Main+ (-- * Main Program+ main+ -- * Functions+ ,foo -- foo function+ ,bar -- bar function+ ,baz -- baz function+ ) where+```++With deprecation++``` haskell+module Main {-# DEPRECATED "no longer supported" #-} where+```++With warnings++``` haskell+module Main {-# WARNING "do not use" #-} where+```++## ImportDecl++``` haskell+import Prelude+import Data.Text (Text)+import qualified Data.Text as T+import qualified Data.ByteString (ByteString,pack,unpack)+import qualified Data.ByteString as BS (pack,unpack)+import Control.Monad hiding (forM)+import {-# SOURCE #-} safe qualified "foo" Foo as F+```++## Decl++### TypeDecl++``` haskell+type Name = String++type Pair a = (a,a)++type Fun a b = a -> b+```++### DataDecl and GDataDecl++``` haskell+data Void++data Unit = Unit++data Maybe a+ = Nothing+ | Just a++data Num a => SomeNum = SomeNum a++newtype RWS r w s = RWS (ReaderT r (WriterT w (StateT s Identity)))+ deriving (Functor,Applicative,Monad)++data Enum+ = One -- Foo+ | Two -- Bar+ | Three -- Baz++data Foo+ deriving ()++data Foo+ deriving Show++data Foo+ deriving (Show)++data Foo+ deriving (Eq,Ord)++data Expr :: * -> * where+ Const :: Int -> Expr Int+ Plus :: Expr Int -> Expr Int -> Expr Int+ Eq :: Expr Int -> Expr Int -> Expr Bool+ deriving (Show)++data Term a where+ Lit :: {val :: Int} -> Term Int+ Succ :: {num :: Term Int} -> Term Int+ Pred :: {num :: Term Int} -> Term Int+ IsZero :: {arg :: Term Int} -> Term Bool+ Pair :: {arg1 :: Term a+ ,arg2 :: Term b} -> Term (a,b)+ If :: {cnd :: Term Bool+ ,tru :: Term a+ ,fls :: Term a} -> Term a+```++### TypeFamDecl, TypeInsDecl, and ClosedTypeFamDecl++``` haskell+type family Mutable v++type family Mutable v = (r :: *)++type family Mutable v = r | r -> v++type instance Mutable Int = MIntVector++type family Store a where+ Store Bool = [Int]+ Store a = [a]++type family Store a = (r :: *) where+ Store a = [a]++type family Store a = r | r -> a where+ Store a = [a]+```++### DataFamDecl, DataInsDecl, and GDataInsDecl++``` haskell+data family List a++data instance List () = NilList Int++data instance List Char+ = CharNil+ | CharCons Char (List Char)+ deriving (Eq,Ord,Show)++data instance List Int :: * where+ IntNil :: List Int+ IntCons :: Int -> List Int+ deriving (Eq,Ord,Show)++data instance List Int :: * where+ IntNil :: List Int+ IntCons :: {val :: Int} -> List Int+ deriving (Eq,Ord,Show)++newtype Penalty = Penalty Int+ deriving (Eq,Ord)+ deriving stock (Read,Show)+ deriving newtype (Num)+ deriving anyclass (FromJSON,ToJSON)+ deriving (Semigroup,Monoid) via M.Sum Int+```++### ClassDecl and InstDecl++``` haskell+class Monoid a where+ mempty :: a+ mappend :: a -> a -> a++class Applicative m => Monad m where+ fail :: m a+ return :: a -> m a+ (>>=) :: a -> (a -> m b) -> m b++class Monad m => MonadState s m | m -> s where+ get :: m s+ put :: s -> m ()+ state :: (s -> (a,s)) -> m a++class ToJSON a where+ toJSON :: a -> Value+ default toJSON :: (Generic a,GToJSON (Rep a)) => a -> Value+ toJSON = genericToJSON defaultOptions++instance ToJSON ()++instance Bounded Bool where+ minBound = False++ maxBound = True++instance Semigroup a => Monoid (Maybe a) where+ mempty = Nothing++ Nothing `mappend` m = m+ m `mappend` Nothing = m+ Just m1 `mappend` Just m2 = Just (m1 `mappend` m2)++instance Data () where+ type Base = ()++ newtype Wrapped = Wrapped {unWrap :: ()}++ data Expr :: * -> * where+ Const :: Int -> Expr Int+ Plus :: Expr Int -> Expr Int -> Expr Int+ Eq :: Expr Int -> Expr Int -> Expr Bool+```++### DerivDecl++``` haskell+deriving instance Eq a => Eq (Sum a)++deriving instance {-# OVERLAP #-} Eq a => Eq (Sum a)++deriving stock instance {-# OVERLAPS #-} Eq a => Eq (Sum a)++deriving anyclass instance {-# OVERLAPPING #-} Eq a => Eq (Sum a)++deriving newtype instance {-# OVERLAPPABLE #-} Eq a => Eq (Sum a)+```++### InfixDecl++``` haskell+infix 4 ==,/=,<,<=,>,>=++infixr 0 $++infixl !!+```++### DefaultDecl++``` haskell+default ()++default (Integer,Double)+```++### SpliceDecl++``` haskell+$foo++$(bar baz)+```++### TypeSig++``` haskell+id :: a -> a+sort :: Ord a => [a] -> [a]+long :: (IsString a,Monad m)+ => ByteString+ -> ByteString+ -> ByteString+ -> ByteString+ -> ByteString+ -> a+ -> m ()+mktime :: Int -- hours+ -> Int -- minutes+ -> Int -- seconds+ -> Time+transform :: forall a. St -> State St a -> EitherT ServantErr IO a+```++### PatSyn and PatSynSig++``` haskell+{-# LANGUAGE PatternSynonyms #-}++pattern MyJust :: a -> Maybe a+pattern MyJust a = Just a++pattern MyPoint :: Int -> Int -> (Int,Int)+pattern MyPoint {x,y} = (x,y)++pattern ErrorCall :: String -> ErrorCall+pattern ErrorCall s <- ErrorCallWithLocation s _+ where ErrorCall s = ErrorCallWithLocation s ""++pattern IsTrue :: Show a => a+pattern IsTrue <- ((== "True") . show -> True)++pattern ExNumPat :: () => Show b => b -> T+pattern ExNumPat x = MkT x++pattern Foo,Bar :: Show a => a+```++### FunBind and PatBind++``` haskell+{-# LANGUAGE UnboxedTuples #-}+{-# LANGUAGE UnboxedSums #-}+{-# LANGUAGE RecordWildCards #-}++pi = 3.14++id x = x++not False = True+not _ = False++head (x:_) = x++maybe x _ Nothing = x+maybe _ f (Some x) = f x++fst (x,_) = x++fst' (# x,_ #) = x++fstPrism (# x | | #) = Just x+fstPrism (# | _ | #) = Nothing+fstPrism (# | | _ #) = Nothing++empty [] = True+empty _ = False++unSum (Sum {getSum = s}) = s++mag2 Point {x,y} = sqr x + sqr y+mag2 Point {..} = sqr x + sqr y++strict !x = x++irrefutable ~x = x++(//) a b = undefined++a // b = undefined++main = do greet "World"+ where greet who = putStrLn $ "Hello, " ++ who ++ "!"+```++### ForImp and ForExp++``` haskell+{-# LANGUAGE ForeignFunctionInterface #-}++foreign import ccall sin :: Double -> Double++foreign import ccall "sin" sin :: Double -> Double++foreign import ccall "sin" sin :: Double -> Double++foreign import ccall unsafe exit :: Double -> Double++foreign export ccall callback :: Int -> Int+```++### Pragmas++``` haskell+{-# RULES #-}++{-# RULES "map/map" forall f g xs. map f (map g xs) = map (f . g) xs #-}++{-# RULES "map/append" [2] forall f xs ys. map f (xs ++ ys) =+ map f xs ++ map f ys #-}++{-# DEPRECATED #-}+{-# DEPRECATED foo "use bar instead" #-}+{-# DEPRECATED foo,bar,baz "no longer supported" #-}+{-# WARNING #-}+{-# WARNING foo "use bar instead" #-}+{-# WARNING foo,bar,baz "no longer supported" #-}+{-# INLINE foo #-}+{-# INLINE [3] foo #-}+{-# INLINE [~3] foo #-}+{-# NOINLINE foo #-}+{-# INLINE CONLIKE foo #-}+{-# INLINE CONLIKE [3] foo #-}+{-# SPECIALISE foo :: Int -> Int #-}+{-# SPECIALISE [3] foo :: Int -> Int,Float -> Float #-}+{-# SPECIALISE INLINE foo :: Int -> Int #-}+{-# SPECIALISE NOINLINE foo :: Int -> Int #-}+{-# SPECIALISE instance Foo Int #-}+{-# SPECIALISE instance forall a. (Ord a) => Foo a #-}+{-# ANN foo (Just "Foo") #-}+{-# ANN type Foo (Just "Foo") #-}+{-# ANN module (Just "Foo") #-}+{-# MINIMAL foo | bar,(baz | quux) #-}+```++## Exp++### Var, Con, Lit, Tuple, UnboxedSum, List, and ExpTypeSig++``` haskell+{-# LANGUAGE TupleSections #-}+{-# LANGUAGE UnboxedTuples #-}+{-# LANGUAGE UnboxedSums #-}++foo = foo++foo = Nothing++foo = 123++foo = 'x'++foo = ""++foo = "Lorem Ipsum Dolor Amet Sit"++foo = ()++foo = (1,2)++foo =+ (1 -- the one+ ,2)++foo = (1,)++foo = (,2)++foo = (,2,)++foo = (# #)++foo = (# 1,2 #)++foo =+ (# 1 -- the one+ ,2 #)++foo = (# 1 #)++foo = (# | 1 | | #)++foo =+ (# | 1 -- the one+ | | #)++foo = []++foo = [1]++foo = [1,2]++foo =+ [1 -- the one+ ,2]++foo = 1 :: Int+```++### App, InfixApp, NegApp, LeftSection, RightSection++``` haskell+foo = foldl fn init list++foo =+ foldl fn -- reducer+ init -- initial value+ list++foo = 1 + 2++foo = fn `map` list++foo = -3++foo = (+ arg)++foo = (`op` arg)++foo = (arg +)++foo = (arg `op`)+```++### EnumFrom, EnumFromTo, EnumFromThen, EnumFromThenTo, ParArrayFromTo, ParArrayFromThenTo++``` haskell+foo = [1 ..]++foo = [1 .. 10]++foo = [1,2 ..]++foo = [1,2 .. 10]++foo = [:1 .. 10:]++foo = [:1,2 .. 10:]+```++### ListComp, ParComp, and ParArrayComp++``` haskell+{-# LANGUAGE TransformListComp #-}++foo = [(x,y) | x <- xs,y <- ys]++foo =+ [(x,y) -- cartesian product+ | x <- xs -- first list+ ,y <- ys -- second list+ ]++foo = [(x,y) | x <- xs | y <- ys]++foo =+ [(x,y) -- zip+ | x <- xs -- first list+ | y <- ys -- second list+ ]++foo = [:(x,y) | x <- xs | y <- ys:]++foo =+ [:(x,y) -- zip+ | x <- xs -- first list+ | y <- ys -- second list+ :]++foo =+ [(x,y) | x <- xs+ ,y <- ys+ ,then reverse+ ,then sortWith by (x + y)+ ,then group using permutations+ ,then group by (x + y) using groupWith]+```++### RecConstr and RecUpdate++``` haskell+{-# LANGUAGE RecordWildCards #-}++foo =+ Point {x = 1+ ,y = 2}++foo =+ Point {x = 1 -- the one+ ,y+ ,..}++foo = bar {x = 1}++foo =+ bar {x = 1 -- the one+ ,y+ ,..}+```++### Let, If, MultiIf, and Case++``` haskell+{-# LANGUAGE MultiWayIf #-}++foo =+ let x = x+ in x++foo =+ let x = x -- bottom+ in+ -- bottom+ x++foo =+ if null xs+ then None+ else Some $ head xs++foo =+ if null xs -- condition+ then None -- it's empty+ else Some $ head xs -- it's not++foo =+ if+ | null xs -> None+ | otherwise -> Some $ head xs++foo =+ if+ | null xs ->+ -- it's empty+ None+ | otherwise ->+ -- it's not+ Some $ head x++foo =+ case x of+ True -> False+ False -> True++foo =+ case xs of+ [] ->+ -- it's empty+ None+ x:_ ->+ -- it's not+ Some x++foo =+ case xs of+ _+ | null xs -> None+ _ -> Some $ head x+```++### Do and MDo++``` haskell+{-# LANGUAGE RecursiveDo #-}++foo = do return ()++foo = do return ()++foo =+ do this <- that+ let this' = tail this+ if this -- condition+ then that+ else those++foo = mdo return ()+```++### Lambda, LCase++``` haskell+{-# LANGUAGE LambdaCase #-}++foo = \x -> x++foo = \ ~x -> x++foo = \ !x -> x++foo d =+ \case+ Nothing -> d+ Some x -> x+```++### BracketExp, SpliceExp, QuasiQuote, VarQuote, and TypQuote++``` haskell+{-# LANGUAGE TemplateHaskell #-}++mkDecl :: Q Decl+mkDecl = [d|id x = x|]++mkType :: Q Type+mkType = [t|(a,b) -> a|]++mkPat :: Q Pat+mkPat = [p|(a,b)|]++mkExp :: Q Exp+mkExp = [|a|]++fst :: $(mkType)+fst $(mkPat) = $(mkExp)++html = [html|<p>Lorem Ipsum Dolor Amet Sit</p>|]++foo = mkSomething 'id 'Nothing ''Maybe+```++# Regression Tests++## Do++Before comments and onside indent do not mix well.++``` haskell+foo =+ do+ -- comment+ some expression+```++## Types++Long types allow linebreaks.++``` haskell+newtype MyMonadT a b m =+ MyMonad {runMyMonad :: StateT ([(a,a -> b)])+ (ReaderT a+ (ExceptT [IM.IntMap b])+ (WriterT [IS.IntSet x] m))}+```++Promoted types.++``` haskell+type Foo = Bar 1 "foo" '() '(A,B) '[X,Y]+```++## Patterns++Long function pattern matches allow linebreaks.++``` haskell+doThing (Constructor field1 field2 field3)+ (Constructor field1 field2 field3)+ (Constructor field1 field2 field3) = undefined+```++## Onside++Indent within onside started on non-empty line should still not stack.++``` haskell+foo =+ if cond+ then do this+ else do that+```++Before comments at the start of onside do not trigger onside.++``` haskell+foo =+ do+ -- comment+ some expression+```++Matche arms have individual onside.++``` haskell+foo True =+ some -- comment+ expression+foo False =+ some -- comment+ other+ expression+```++Where binds are considered outside of onside.++``` haskell+foo =+ some -- comment+ expression+ where expression = other+```++Align overrides onside.++``` haskell+foo =+ some expr+ [1 -- comment+ ,2]+```++If-then-else must always indent in do blocks.++``` haskell+foo =+ do if condition -- comment+ then this+ else that+```++Lists must not suppress onside.++``` haskell+foo =+ case x of+ [y -- comment+ ,z] -> bar++foo =+ do [x -- comment+ ,y]+```++## Comments++Don't be too eager in assigning comments to the following AST node.++``` haskell+data Foo =+ Foo {fooBar :: Text+ -- ^A comment, long enough to end up on its own line, or at least I hope so.+ }+ deriving (Eq)+```++Keep comments together and aligned.++``` haskell+-- block+-- one+data Foo+ = Foo -- some+ -- comments+ | Quux -- more+ -- comments+-- block+-- two+```++... even when haskell-src-exts has weird column span info.++``` haskell+module Main where++-- comment+instance Foo Bar where+ foo = undefined++bar = undefined+```++Only comments.++``` haskell+-- some comment+```++Make sure no comments are dropped from operators or argument.++``` haskell+foo =+ some -- comment 1+ -- comment 2+ %~ -- comment 3+ argument -- comment 4+```++Comments after `where` stay there.++``` haskell+consM :: Monad m => m a -> Stream m a -> Stream m a+consM m (Stream step state) = Stream step1 Nothing+ where+ {-# INLINE_LATE step1 #-}+ step1 _ _ = undefined+```++Comments between declarations do not cause empty lines.++``` haskell+f :: ()+--+f = ()+```++## Indentation and Line Prefixes++Preserving indentation and line prefixes so that Floskell can be run+on individual declarations and quoted haskell code.++``` haskell+ data Enum+ = One -- Foo+ | Two -- Bar+ | Three -- Baz+```++``` haskell+>+> data Enum+> = One -- Foo+> | Two -- Bar+> | Three -- Baz+>+```++## Module Exports++Long module exports don't force overlong line.++``` haskell+module SimpleFunctions (identity,compose,append,firstElement,secondElem) where+```
+ styles/cramer.md view
@@ -0,0 +1,1007 @@+# Introduction++This file acts both as a presentation of the Floskell formatting+styles, as well as a set of regression tests.++You can see how a particular style will format Haskell source by+reading the matching Markdown file in the styles/ directory.++For regression testing, the canonical source, TEST.md in the root+directory, is parsed and each Haskell code block formatted according+to all predefined styles. The formatted output is then compared with+the corresponding, already formatted code block in the <style\>.md file+in the styles/ subdirectory.++The regression test will also verify that repeated invocations of the+pretty printer will not modify an already formatted piece of code.++The following code block acts as a quick presentation for the+different formatting styles, by presenting a mixture of common Haskell+constructs.++``` haskell+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards #-}++{-# OPTIONS_GHC -fno-warn-name-shadowing #-}++{- |+Module: Style.Haskell.Example++Haskell Code Style Example.+-}+module Style.Haskell.Example+ ( -- * Types+ Enum(..)+ , Either(..)+ , Point(..)+ -- * Functions+ , hello+ ) where++-- Module imports+import qualified Control.Monad.Trans.State+ ( State, evalState, execState, get, modify, put, runState )++import qualified Data.Map as Map+import qualified Data.Text as Text++import Prelude hiding ( map )++-- Data declarations+data Enum = CaseA | CaseB | CaseC+ deriving ( Eq, Enum, Show )++data Either a b = Left a | Right b+ deriving ( Eq, Show )++data Point = Point { pointX :: Float, pointY :: Float, pointLabel :: String }+ deriving ( Eq, Show )++-- Type classes+class Functor f => Applicative a where+ pure :: b -> a b+ ap :: a (b -> c) -> a b -> a c++class Fundep a b | a -> b where+ convert :: a -> b++instance Functor f => Functor (Wrap f) where+ fmap f (Wrap x) = Wrap $ fmap f x++-- Values+origin :: Point+origin = Point { pointX = 0, pointY = 0, pointLabel = "Origin" }++lorem :: [String]+lorem =+ [ "Lorem ipsum dolor sit amet, consectetur adipiscing elit."+ , "Curabitur nec ante nec mauris ornare suscipit."+ , "In ac vulputate libero."+ , "Duis eget magna non purus imperdiet molestie nec quis mauris."+ , "Praesent blandit quam vel arcu pellentesque, id aliquet turpis faucibus."+ ]++-- Functions+facs :: [Int]+facs = [ 1, 1 ] ++ zipWith (+) (tailfacs)++hello :: MonadIO m => m ()+hello = do+ name <- liftIO getLine+ liftIO . putStrLn $ greetings name+ where+ greetings n = "Hello " ++ n ++ "!"++letExpr :: Point -> String+letExp x = let y = 1+ z = 2+ in+ if x > 0 then y else z++ifExpr :: Bool -> Bool+ifExpr b = if b == True then False else True++caseExpr :: [a] -> Maybe a+caseExpr xs = case xs of+ [] -> Nothing+ (x : _) -> Just x++guarded :: Int -> Int+guarded x+ | x == 0 = 1+ | x == 1 = 1+ | otherwise = guarded (x - 2) + guarded (x - 1)++someLongFunctionNameWithALotOfParameters+ :: (MonadIO m, MonadRandom m) => String -> (String -> String) -> m ()+someLongFunctionNameWithALotOfParameters = undefined+```++# Unit Tests++## ModuleHead and ExportSpecList++Without exports++``` haskell+module Main where+```++With exports++``` haskell+module Main ( foo, bar, baz, main ) where+```++With exports and comments++``` haskell+module Main+ ( -- * Main Program+ main+ -- * Functions+ , foo -- foo function+ , bar -- bar function+ , baz -- baz function+ ) where+```++With deprecation++``` haskell+module Main {-# DEPRECATED "no longer supported" #-} where+```++With warnings++``` haskell+module Main {-# WARNING "do not use" #-} where+```++## ImportDecl++``` haskell+import Control.Monad hiding ( forM )++import qualified Data.ByteString ( ByteString, pack, unpack )+import qualified Data.ByteString as BS ( pack, unpack )+import Data.Text ( Text )+import qualified Data.Text as T++import {-# SOURCE #-} safe qualified "foo" Foo as F++import Prelude+```++## Decl++### TypeDecl++``` haskell+type Name = String++type Pair a = (a, a)++type Fun a b = a -> b+```++### DataDecl and GDataDecl++``` haskell+data Void++data Unit = Unit++data Maybe a = Nothing | Just a++data Num a => SomeNum = SomeNum a++newtype RWS r w s = RWS (ReaderT r (WriterT w (StateT s Identity)))+ deriving ( Functor, Applicative, Monad )++data Enum = One -- Foo+ | Two -- Bar+ | Three -- Baz++data Foo+ deriving ()++data Foo+ deriving Show++data Foo+ deriving ( Show )++data Foo+ deriving ( Eq, Ord )++data Expr :: * -> * where+ Const :: Int -> Expr Int+ Plus :: Expr Int -> Expr Int -> Expr Int+ Eq :: Expr Int -> Expr Int -> Expr Bool+ deriving ( Show )++data Term a where+ Lit :: { val :: Int } -> Term Int+ Succ :: { num :: Term Int } -> Term Int+ Pred :: { num :: Term Int } -> Term Int+ IsZero :: { arg :: Term Int } -> Term Bool+ Pair :: { arg1 :: Term a, arg2 :: Term b } -> Term (a, b)+ If :: { cnd :: Term Bool, tru :: Term a, fls :: Term a } -> Term a+```++### TypeFamDecl, TypeInsDecl, and ClosedTypeFamDecl++``` haskell+type family Mutable v++type family Mutable v = (r :: *)++type family Mutable v = r | r -> v++type instance Mutable Int = MIntVector++type family Store a where+ Store Bool = [Int]+ Store a = [a]++type family Store a = (r :: *) where+ Store a = [a]++type family Store a = r | r -> a where+ Store a = [a]+```++### DataFamDecl, DataInsDecl, and GDataInsDecl++``` haskell+data family List a++data instance List () = NilList Int++data instance List Char = CharNil | CharCons Char (List Char)+ deriving ( Eq, Ord, Show )++data instance List Int :: * where+ IntNil :: List Int+ IntCons :: Int -> List Int+ deriving ( Eq, Ord, Show )++data instance List Int :: * where+ IntNil :: List Int+ IntCons :: { val :: Int } -> List Int+ deriving ( Eq, Ord, Show )++newtype Penalty = Penalty Int+ deriving ( Eq, Ord )+ deriving stock ( Read, Show )+ deriving newtype ( Num )+ deriving anyclass ( FromJSON, ToJSON )+ deriving ( Semigroup, Monoid ) via M.Sum Int+```++### ClassDecl and InstDecl++``` haskell+class Monoid a where+ mempty :: a+ mappend :: a -> a -> a++class Applicative m => Monad m where+ fail :: m a+ return :: a -> m a+ (>>=) :: a -> (a -> m b) -> m b++class Monad m => MonadState s m | m -> s where+ get :: m s+ put :: s -> m ()+ state :: (s -> (a, s)) -> m a++class ToJSON a where+ toJSON :: a -> Value+ default toJSON :: (Generic a, GToJSON (Rep a)) => a -> Value+ toJSON = genericToJSON defaultOptions++instance ToJSON ()++instance Bounded Bool where+ minBound = False++ maxBound = True++instance Semigroup a => Monoid (Maybe a) where+ mempty = Nothing++ Nothing `mappend` m = m+ m `mappend` Nothing = m+ Just m1 `mappend` Just m2 = Just (m1 `mappend` m2)++instance Data () where+ type Base = ()++ newtype Wrapped = Wrapped { unWrap :: () }++ data Expr :: * -> * where+ Const :: Int -> Expr Int+ Plus :: Expr Int -> Expr Int -> Expr Int+ Eq :: Expr Int -> Expr Int -> Expr Bool+```++### DerivDecl++``` haskell+deriving instance Eq a => Eq (Sum a)++deriving instance {-# OVERLAP #-} Eq a => Eq (Sum a)++deriving stock instance {-# OVERLAPS #-} Eq a => Eq (Sum a)++deriving anyclass instance {-# OVERLAPPING #-} Eq a => Eq (Sum a)++deriving newtype instance {-# OVERLAPPABLE #-} Eq a => Eq (Sum a)+```++### InfixDecl++``` haskell+infix 4 ==, /=, <, <=, >, >=++infixr 0 $++infixl !!+```++### DefaultDecl++``` haskell+default ()++default ( Integer, Double )+```++### SpliceDecl++``` haskell+$foo++$(bar baz)+```++### TypeSig++``` haskell+id :: a -> a+sort :: Ord a => [a] -> [a]+long :: (IsString a, Monad m)+ => ByteString+ -> ByteString+ -> ByteString+ -> ByteString+ -> ByteString+ -> a+ -> m ()+mktime :: Int -- hours+ -> Int -- minutes+ -> Int -- seconds+ -> Time+transform :: forall a. St -> State St a -> EitherT ServantErr IO a+```++### PatSyn and PatSynSig++``` haskell+{-# LANGUAGE PatternSynonyms #-}++pattern MyJust :: a -> Maybe a+pattern MyJust a = Just a++pattern MyPoint :: Int -> Int -> (Int, Int)+pattern MyPoint{x, y} = (x, y)++pattern ErrorCall :: String -> ErrorCall+pattern ErrorCall s <- ErrorCallWithLocation s _+ where+ ErrorCall s = ErrorCallWithLocation s ""++pattern IsTrue :: Show a => a+pattern IsTrue <- ((== "True") . show -> True)++pattern ExNumPat :: () => Show b => b -> T+pattern ExNumPat x = MkT x++pattern Foo, Bar :: Show a => a+```++### FunBind and PatBind++``` haskell+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE UnboxedSums #-}+{-# LANGUAGE UnboxedTuples #-}++pi = 3.14++id x = x++not False = True+not _ = False++head (x : _) = x++maybe x _ Nothing = x+maybe _ f (Some x) = f x++fst (x, _) = x++fst' (# x, _ #) = x++fstPrism (# x | | #) = Just x+fstPrism (# | _ | #) = Nothing+fstPrism (# | | _ #) = Nothing++empty [] = True+empty _ = False++unSum (Sum{getSum = s}) = s++mag2 Point{x, y} = sqr x + sqr y+mag2 Point{..} = sqr x + sqr y++strict !x = x++irrefutable ~x = x++(//) a b = undefined++a // b = undefined++main = do+ greet "World"+ where+ greet who = putStrLn $ "Hello, " ++ who ++ "!"+```++### ForImp and ForExp++``` haskell+{-# LANGUAGE ForeignFunctionInterface #-}++foreign import ccall sin :: Double -> Double++foreign import ccall "sin" sin :: Double -> Double++foreign import ccall "sin" sin :: Double -> Double++foreign import ccall unsafe exit :: Double -> Double++foreign export ccall callback :: Int -> Int+```++### Pragmas++``` haskell+{-# RULES #-}++{-# RULES "map/map" forall f g xs. map f (map g xs) = map (f . g) xs #-}++{-# RULES "map/append" [2] forall f xs ys. map f (xs ++ ys) =+ map f xs ++ map f ys #-}++{-# DEPRECATED #-}+{-# DEPRECATED foo "use bar instead" #-}+{-# DEPRECATED foo, bar, baz "no longer supported" #-}++{-# WARNING #-}+{-# WARNING foo "use bar instead" #-}+{-# WARNING foo, bar, baz "no longer supported" #-}++{-# INLINE foo #-}+{-# INLINE [3] foo #-}+{-# INLINE [~3] foo #-}+{-# NOINLINE foo #-}++{-# INLINE CONLIKE foo #-}+{-# INLINE CONLIKE [3] foo #-}++{-# SPECIALISE foo :: Int -> Int #-}+{-# SPECIALISE [3] foo :: Int -> Int, Float -> Float #-}++{-# SPECIALISE INLINE foo :: Int -> Int #-}+{-# SPECIALISE NOINLINE foo :: Int -> Int #-}++{-# SPECIALISE instance Foo Int #-}+{-# SPECIALISE instance forall a. (Ord a) => Foo a #-}++{-# ANN foo (Just "Foo") #-}+{-# ANN type Foo (Just "Foo") #-}+{-# ANN module (Just "Foo") #-}++{-# MINIMAL foo | bar, (baz | quux) #-}+```++## Exp++### Var, Con, Lit, Tuple, UnboxedSum, List, and ExpTypeSig++``` haskell+{-# LANGUAGE TupleSections #-}++{-# LANGUAGE UnboxedSums #-}+{-# LANGUAGE UnboxedTuples #-}++foo = foo++foo = Nothing++foo = 123++foo = 'x'++foo = ""++foo = "Lorem Ipsum Dolor Amet Sit"++foo = ()++foo = (1, 2)++foo = ( 1 -- the one+ , 2+ )++foo = (1, )++foo = (, 2)++foo = (, 2, )++foo = (# #)++foo = (# 1, 2 #)++foo = (# 1 -- the one+ , 2+ #)++foo = (# 1 #)++foo = (# | 1 | | #)++foo = (# | 1 -- the one+ | |+ #)++foo = []++foo = [ 1 ]++foo = [ 1, 2 ]++foo = [ 1 -- the one+ , 2+ ]++foo = 1 :: Int+```++### App, InfixApp, NegApp, LeftSection, RightSection++``` haskell+foo = foldl fn init list++foo = foldl fn -- reducer+ init -- initial value+ list++foo = 1 + 2++foo = fn `map` list++foo = -3++foo = (+ arg)++foo = (`op` arg)++foo = (arg +)++foo = (arg `op`)+```++### EnumFrom, EnumFromTo, EnumFromThen, EnumFromThenTo, ParArrayFromTo, ParArrayFromThenTo++``` haskell+foo = [ 1 .. ]++foo = [ 1 .. 10 ]++foo = [ 1, 2 .. ]++foo = [ 1, 2 .. 10 ]++foo = [: 1 .. 10 :]++foo = [: 1, 2 .. 10 :]+```++### ListComp, ParComp, and ParArrayComp++``` haskell+{-# LANGUAGE TransformListComp #-}++foo = [ (x, y) | x <- xs, y <- ys ]++foo = [ (x, y) -- cartesian product+ | x <- xs -- first list+ , y <- ys -- second list+ ]++foo = [ (x, y) | x <- xs | y <- ys ]++foo = [ (x, y) -- zip+ | x <- xs -- first list+ | y <- ys -- second list+ ]++foo = [: (x, y) | x <- xs | y <- ys :]++foo = [: (x, y) -- zip+ | x <- xs -- first list+ | y <- ys -- second list+ :]++foo = [ (x, y)+ | x <- xs+ , y <- ys+ , then reverse+ , then sortWith by (x + y)+ , then group using permutations+ , then group by (x + y) using groupWith+ ]+```++### RecConstr and RecUpdate++``` haskell+{-# LANGUAGE RecordWildCards #-}++foo = Point { x = 1, y = 2 }++foo = Point { x = 1 -- the one+ , y+ , ..+ }++foo = bar { x = 1 }++foo = bar { x = 1 -- the one+ , y+ , ..+ }+```++### Let, If, MultiIf, and Case++``` haskell+{-# LANGUAGE MultiWayIf #-}++foo = let x = x in x++foo = let x = x -- bottom+ in+ -- bottom+ x++foo = if null xs then None else Some $ head xs++foo = if null xs -- condition+ then None -- it's empty+ else Some $ head xs -- it's not++foo = if+ | null xs -> None+ | otherwise -> Some $ head xs++foo = if+ | null xs ->+ -- it's empty+ None+ | otherwise ->+ -- it's not+ Some $ head x++foo = case x of+ True -> False+ False -> True++foo = case xs of+ [] ->+ -- it's empty+ None+ x : _ ->+ -- it's not+ Some x++foo = case xs of+ _+ | null xs -> None+ _ -> Some $ head x+```++### Do and MDo++``` haskell+{-# LANGUAGE RecursiveDo #-}++foo = do+ return ()++foo = do+ return ()++foo = do+ this <- that+ let this' = tail this+ if this -- condition+ then that+ else those++foo = mdo+ return ()+```++### Lambda, LCase++``` haskell+{-# LANGUAGE LambdaCase #-}++foo = \x -> x++foo = \ ~x -> x++foo = \ !x -> x++foo d = \case+ Nothing -> d+ Some x -> x+```++### BracketExp, SpliceExp, QuasiQuote, VarQuote, and TypQuote++``` haskell+{-# LANGUAGE TemplateHaskell #-}++mkDecl :: Q Decl+mkDecl = [d|id x = x|]++mkType :: Q Type+mkType = [t|(a, b) -> a|]++mkPat :: Q Pat+mkPat = [p|(a, b)|]++mkExp :: Q Exp+mkExp = [|a|]++fst :: $(mkType)+fst $(mkPat) = $(mkExp)++html = [html|<p>Lorem Ipsum Dolor Amet Sit</p>|]++foo = mkSomething 'id 'Nothing ''Maybe+```++# Regression Tests++## Do++Before comments and onside indent do not mix well.++``` haskell+foo = do+ -- comment+ some expression+```++## Types++Long types allow linebreaks.++``` haskell+newtype MyMonadT a b m =+ MyMonad { runMyMonad :: StateT ([(a, a -> b)])+ (ReaderT a+ (ExceptT [IM.IntMap b])+ (WriterT [IS.IntSet x] m))+ }+```++Promoted types.++``` haskell+type Foo = Bar 1 "foo" '() '(A, B) '[ X, Y ]+```++## Patterns++Long function pattern matches allow linebreaks.++``` haskell+doThing (Constructor field1 field2 field3)+ (Constructor field1 field2 field3)+ (Constructor field1 field2 field3) = undefined+```++## Onside++Indent within onside started on non-empty line should still not stack.++``` haskell+foo = if cond+ then do+ this+ else do+ that+```++Before comments at the start of onside do not trigger onside.++``` haskell+foo = do+ -- comment+ some expression+```++Matche arms have individual onside.++``` haskell+foo True = some -- comment+ expression+foo False = some -- comment+ other+ expression+```++Where binds are considered outside of onside.++``` haskell+foo = some -- comment+ expression+ where+ expression = other+```++Align overrides onside.++``` haskell+foo = some expr+ [ 1 -- comment+ , 2+ ]+```++If-then-else must always indent in do blocks.++``` haskell+foo = do+ if condition -- comment+ then this+ else that+```++Lists must not suppress onside.++``` haskell+foo = case x of+ [ y -- comment+ , z+ ] -> bar++foo = do+ [ x -- comment+ , y+ ]+```++## Comments++Don't be too eager in assigning comments to the following AST node.++``` haskell+data Foo = Foo { fooBar :: Text+ -- ^A comment, long enough to end up on its own line, or at least I hope so.+ }+ deriving ( Eq )+```++Keep comments together and aligned.++``` haskell+-- block+-- one+data Foo = Foo -- some+ -- comments+ | Quux -- more+ -- comments+-- block+-- two+```++... even when haskell-src-exts has weird column span info.++``` haskell+module Main where++-- comment+instance Foo Bar where+ foo = undefined++bar = undefined+```++Only comments.++``` haskell+-- some comment+```++Make sure no comments are dropped from operators or argument.++``` haskell+foo = some -- comment 1+ -- comment 2+ %~ -- comment 3+ argument -- comment 4+```++Comments after `where` stay there.++``` haskell+consM :: Monad m => m a -> Stream m a -> Stream m a+consM m (Stream step state) = Stream step1 Nothing+ where+ {-# INLINE_LATE step1 #-}+ step1 _ _ = undefined+```++Comments between declarations do not cause empty lines.++``` haskell+f :: ()+--+f = ()+```++## Indentation and Line Prefixes++Preserving indentation and line prefixes so that Floskell can be run+on individual declarations and quoted haskell code.++``` haskell+ data Enum = One -- Foo+ | Two -- Bar+ | Three -- Baz+```++``` haskell+>+> data Enum = One -- Foo+> | Two -- Bar+> | Three -- Baz+>+```++## Module Exports++Long module exports don't force overlong line.++``` haskell+module SimpleFunctions+ ( identity+ , compose+ , append+ , firstElement+ , secondElem+ ) where+```
+ styles/fundamental.md view
@@ -0,0 +1,1080 @@+# Introduction++This file acts both as a presentation of the Floskell formatting+styles, as well as a set of regression tests.++You can see how a particular style will format Haskell source by+reading the matching Markdown file in the styles/ directory.++For regression testing, the canonical source, TEST.md in the root+directory, is parsed and each Haskell code block formatted according+to all predefined styles. The formatted output is then compared with+the corresponding, already formatted code block in the <style\>.md file+in the styles/ subdirectory.++The regression test will also verify that repeated invocations of the+pretty printer will not modify an already formatted piece of code.++The following code block acts as a quick presentation for the+different formatting styles, by presenting a mixture of common Haskell+constructs.++``` haskell+{-# OPTIONS_GHC -fno-warn-name-shadowing #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards #-}++{- |+Module: Style.Haskell.Example++Haskell Code Style Example.+-}+module Style.Haskell.Example+ (+ -- * Types+ Enum(..)+ ,Either(..)+ ,Point(..)+ ,+ -- * Functions+ hello)+ where++-- Module imports+import qualified Control.Monad.Trans.State+ (State, evalState, execState, get, modify, put, runState)+import qualified Data.Map as Map+import qualified Data.Text as Text+import Prelude hiding (map)++-- Data declarations+data Enum+ = CaseA+ | CaseB+ | CaseC+ deriving (Eq,Enum,Show)++data Either a b+ = Left a+ | Right b+ deriving (Eq,Show)++data Point =+ Point {pointX :: Float+ ,pointY :: Float+ ,pointLabel :: String}+ deriving (Eq,Show)++-- Type classes+class Functor f =>+ Applicative a where+ pure :: b -> a b+ ap :: a (b -> c) -> a b -> a c++class Fundep a b | a -> b where+ convert :: a -> b++instance Functor f =>+ Functor (Wrap f) where+ fmap f (Wrap x) =+ Wrap $ fmap+ f+ x++-- Values+origin :: Point+origin =+ Point {pointX = + 0+ ,pointY = + 0+ ,pointLabel = + "Origin"}++lorem :: [String]+lorem =+ ["Lorem ipsum dolor sit amet, consectetur adipiscing elit."+ ,"Curabitur nec ante nec mauris ornare suscipit."+ ,"In ac vulputate libero."+ ,"Duis eget magna non purus imperdiet molestie nec quis mauris."+ ,"Praesent blandit quam vel arcu pellentesque, id aliquet turpis faucibus."]++-- Functions+facs :: [Int]+facs =+ [1+ ,1] ++ zipWith+ (+)+ (tailfacs)++hello :: MonadIO m =>+ m ()+hello =+ do name <- liftIO+ getLine+ liftIO . putStrLn $ greetings+ name+ where greetings n =+ "Hello " ++ n ++ "!"++letExpr :: Point -> String+letExp x =+ let y =+ 1+ z =+ 2+ in if x > 0+ then y+ else z++ifExpr :: Bool -> Bool+ifExpr b =+ if b == True+ then False+ else True++caseExpr :: [a] -> Maybe a+caseExpr xs =+ case xs of+ [] ->+ Nothing+ (x:_) ->+ Just+ x++guarded :: Int -> Int+guarded x+ | x == 0 =+ 1+ | x == 1 =+ 1+ | otherwise =+ guarded+ (x - 2) + guarded+ (x - 1)++someLongFunctionNameWithALotOfParameters :: (MonadIO m+ ,MonadRandom m) =>+ String -> (String -> String) -> m ()+someLongFunctionNameWithALotOfParameters =+ undefined+```++# Unit Tests++## ModuleHead and ExportSpecList++Without exports++``` haskell+module Main where+```++With exports++``` haskell+module Main+ (foo+ ,bar+ ,baz+ ,main)+ where+```++With exports and comments++``` haskell+module Main+ (+ -- * Main Program+ main+ ,+ -- * Functions+ foo -- foo function+ ,bar -- bar function+ ,baz -- baz function+ )+ where+```++With deprecation++``` haskell+module Main {-# DEPRECATED "no longer supported" #-} where+```++With warnings++``` haskell+module Main {-# WARNING "do not use" #-} where+```++## ImportDecl++``` haskell+import Prelude+import Data.Text (Text)+import qualified Data.Text as T+import qualified Data.ByteString (ByteString, pack, unpack)+import qualified Data.ByteString as BS (pack, unpack)+import Control.Monad hiding (forM)+```++## Decl++### TypeDecl++``` haskell+type Name = String++type Pair a = (a,a)++type Fun a b = a -> b+```++### DataDecl and GDataDecl++``` haskell+data Void++data Unit =+ Unit++data Maybe a+ = Nothing+ | Just a++data Num a =>+ SomeNum =+ SomeNum a++newtype RWS r w s =+ RWS (ReaderT r (WriterT w (StateT s Identity)))+ deriving (Functor,Applicative,Monad)++data Enum+ = One -- Foo+ | Two -- Bar+ | Three -- Baz++data Foo+ deriving ()++data Foo+ deriving (Show)++data Foo+ deriving (Show)++data Foo+ deriving (Eq,Ord)++data Expr :: * -> * where+ Const :: Int -> Expr Int+ Plus :: Expr Int -> Expr Int -> Expr Int+ Eq :: Expr Int -> Expr Int -> Expr Bool+ deriving (Show)++data Term a where+ Lit :: {val :: Int} -> Term Int+ Succ :: {num :: Term Int} -> Term Int+ Pred :: {num :: Term Int} -> Term Int+ IsZero :: {arg :: Term Int} -> Term Bool+ Pair :: {arg1 :: Term a, arg2 :: Term b} -> Term (a, b)+ If :: {cnd :: Term Bool, tru :: Term a, fls :: Term a} -> Term a+```++### TypeFamDecl, TypeInsDecl, and ClosedTypeFamDecl++``` haskell+type family Mutable v++type family Mutable v = (r :: *)++type family Mutable v = r | r -> v++type instance Mutable Int = MIntVector++type family Store a where+ Store Bool = [Int]+ Store a = [a]++type family Store a = (r :: *) where+ Store a = [a]++type family Store a = r | r -> a where+ Store a = [a]+```++### DataFamDecl, DataInsDecl, and GDataInsDecl++``` haskell+data family List a++data instance List () = NilList Int++data instance List Char = CharNil+ | CharCons Char (List Char)+ deriving (Eq, Ord, Show)++data instance List Int :: * where+ IntNil :: List Int+ IntCons :: Int -> List Int+ deriving (Eq, Ord, Show)++data instance List Int :: * where+ IntNil :: List Int+ IntCons :: {val :: Int} -> List Int+ deriving (Eq, Ord, Show)+```++### ClassDecl and InstDecl++``` haskell+class Monoid a where+ mempty :: a+ mappend :: a -> a -> a++class Applicative m =>+ Monad m where+ fail :: m a+ return :: a -> m a+ (>>=) :: a -> (a -> m b) -> m b++class Monad m =>+ MonadState s m | m -> s where+ get :: m s+ put :: s -> m ()+ state :: (s -> (a,s)) -> m a++class ToJSON a where+ toJSON :: a -> Value+ default toJSON :: (Generic a+ ,GToJSON (Rep a)) =>+ a -> Value+ toJSON =+ genericToJSON+ defaultOptions++instance ToJSON ()++instance Bounded Bool where+ minBound =+ False+ maxBound =+ True++instance Semigroup a =>+ Monoid (Maybe a) where+ mempty =+ Nothing+ Nothing `mappend` m =+ m+ m `mappend` Nothing =+ m+ Just m1 `mappend` Just m2 =+ Just+ (m1 `mappend` m2)++instance Data () where+ type Base = ()+ newtype Wrapped = Wrapped{unWrap :: ()}+ data Expr :: * -> * where+ Const :: Int -> Expr Int+ Plus :: Expr Int -> Expr Int -> Expr Int+ Eq :: Expr Int -> Expr Int -> Expr Bool+```++### DerivDecl++``` haskell+deriving instance Eq a => Eq (Sum a)++deriving instance {-# OVERLAP #-} Eq a => Eq (Sum a)++deriving stock instance {-# OVERLAPS #-} Eq a => Eq (Sum a)++deriving anyclass instance {-# OVERLAPPING #-} Eq a => Eq (Sum a)++deriving newtype instance {-# OVERLAPPABLE #-} Eq a => Eq (Sum a)+```++### InfixDecl++``` haskell+infix 4 ==, /=, <, <=, >, >=++infixr 0 $++infixl !!+```++### DefaultDecl++``` haskell+default ()++default (Integer, Double)+```++### SpliceDecl++``` haskell+$foo++$(bar+ baz)+```++### TypeSig++``` haskell+id :: a -> a+sort :: Ord a =>+ [a] -> [a]+long :: (IsString a+ ,Monad m) =>+ ByteString -> ByteString -> ByteString -> ByteString -> ByteString -> a -> m ()+mktime :: Int -- hours+ -> Int -- minutes+ -> Int -- seconds+ -> Time+transform :: forall a. St -> State St a -> EitherT ServantErr IO a+```++### PatSyn and PatSynSig++``` haskell+{-# LANGUAGE PatternSynonyms #-}++pattern MyJust :: a -> Maybe a++pattern MyJust a = Just a++pattern MyPoint :: Int -> Int -> (Int, Int)++pattern MyPoint{x, y} = (x, y)++pattern ErrorCall :: String -> ErrorCall++pattern ErrorCall s <- ErrorCallWithLocation s _+ where ErrorCall s = ErrorCallWithLocation s ""++pattern IsTrue :: Show a => a++pattern IsTrue <- ((== "True") . show -> True)++pattern ExNumPat :: () => Show b => b -> T++pattern ExNumPat x = MkT x++pattern Foo, Bar :: Show a => a+```++### FunBind and PatBind++``` haskell+{-# LANGUAGE UnboxedTuples #-}+{-# LANGUAGE UnboxedSums #-}+{-# LANGUAGE RecordWildCards #-}++pi =+ 3.14++id x =+ x++not False =+ True+not _ =+ False++head (x:_) =+ x++maybe x _ Nothing =+ x+maybe _ f (Some x) =+ f+ x++fst (x,_) =+ x++fst' (# x,_ #) =+ x++fstPrism (# x | | #) =+ Just+ x+fstPrism (# | _ | #) =+ Nothing+fstPrism (# | | _ #) =+ Nothing++empty [] =+ True+empty _ =+ False++unSum (Sum {getSum = s}) =+ s++mag2 Point {x+ ,y} =+ sqr+ x + sqr+ y+mag2 Point {..} =+ sqr+ x + sqr+ y++strict !x =+ x++irrefutable ~x =+ x++(//) a b =+ undefined++a // b =+ undefined++main =+ do greet+ "World"+ where greet who =+ putStrLn $ "Hello, " ++ who ++ "!"+```++### ForImp and ForExp++``` haskell+{-# LANGUAGE ForeignFunctionInterface #-}++foreign import ccall sin :: Double -> Double++foreign import ccall "sin" sin :: Double -> Double++foreign import ccall "sin" sin :: Double -> Double++foreign import ccall unsafe exit :: Double -> Double++foreign export ccall Nothing callback :: Int -> Int+```++### Pragmas++``` haskell+{-# RULES+ #-}++{-# RULES+"map/map" forall f g xs . map f (map g xs) = map (f . g) xs+ #-}++{-# RULES+"map/append" [2] forall f xs ys . map f (xs ++ ys) =+ map f xs ++ map f ys+ #-}++{-# DEPRECATED+ #-}++{-# DEPRECATED+foo "use bar instead"+ #-}++{-# DEPRECATED+foo, bar, baz "no longer supported"+ #-}++{-# WARNING+ #-}++{-# WARNING+foo "use bar instead"+ #-}++{-# WARNING+foo, bar, baz "no longer supported"+ #-}++{-# INLINE foo #-}++{-# INLINE foo #-}++{-# INLINE foo #-}++{-# NOINLINE foo #-}++{-# INLINE CONLIKE foo #-}++{-# INLINE CONLIKE [3] foo #-}++{-# SPECIALISE foo :: Int -> Int #-}++{-# SPECIALISE [3] foo :: Int -> Int, Float -> Float #-}++{-# SPECIALISE INLINE foo :: Int -> Int #-}++{-# SPECIALISE NOINLINE foo :: Int -> Int #-}++{-# SPECIALISE instance Foo Int #-}++{-# SPECIALISE instance forall a . (Ord a) => Foo a #-}++{-# ANN foo (Just "Foo") #-}++{-# ANN type Foo (Just "Foo") #-}++{-# ANN module (Just "Foo") #-}++{-# MINIMAL foo | bar , (baz | quux) #-}+```++## Exp++### Var, Con, Lit, Tuple, UnboxedSum, List, and ExpTypeSig++``` haskell+{-# LANGUAGE UnboxedTuples #-}+{-# LANGUAGE UnboxedSums #-}++foo =+ foo++foo =+ Nothing++foo =+ 123++foo =+ 'x'++foo =+ ""++foo =+ "Lorem Ipsum Dolor Amet Sit"++foo =+ ()++foo =+ (1+ ,2)++foo =+ (1 -- the one+ ,2)++foo =+ (# #)++foo =+ (# 1+ ,2 #)++foo =+ (# 1 -- the one+ ,2 #)++foo =+ (# 1 #)++foo =+ (# | 1 | | #)++foo =+ (# | 1 -- the one+ | | #)++foo =+ []++foo =+ [1]++foo =+ [1+ ,2]++foo =+ [1 -- the one+ ,2]++foo =+ 1 :: Int+```++### App, InfixApp, NegApp, LeftSection, RightSection++``` haskell+foo =+ foldl+ fn+ init+ list++foo =+ foldl+ fn+ init+ list++foo =+ 1 + 2++foo =+ fn `map` list++foo =+ -3++foo =+ (+ arg)++foo =+ (`op` arg)++foo =+ (arg +)++foo =+ (arg `op`)+```++### EnumFrom, EnumFromTo, EnumFromThen, EnumFromThenTo, ParArrayFromTo, ParArrayFromThenTo++``` haskell+foo =+ [1 ..]++foo =+ [1 .. 10]++foo =+ [1,2 ..]++foo =+ [1,2 .. 10]++foo =+ [:1 .. 10:]++foo =+ [:1, 2 .. 10:]+```++### ListComp, ParComp, and ParArrayComp++``` haskell+{-# LANGUAGE TransformListComp #-}++foo =+ [(x+ ,y)+ |x <- xs+ ,y <- ys]++foo =+ [(x+ ,y) -- cartesian product+ |x <- xs -- first list+ ,y <- ys -- second list+ ]++foo =+ [(x, y)| x <- xs| y <- ys]++foo =+ [(x, y)| x <- xs| y <- ys]++foo =+ [:(x, y)| x <- xs| y <- ys:]++foo =+ [:(x, y)| x <- xs| y <- ys:]++foo =+ [(x+ ,y)+ |x <- xs+ ,y <- ys+ ,then reverse+ ,then sortWith by (x + y)+ ,then group using permutations+ ,then group by (x + y) using groupWith]+```++### RecConstr and RecUpdate++``` haskell+{-# LANGUAGE RecordWildCards #-}++foo =+ Point {x = + 1+ ,y = + 2}++foo =+ Point {x = + 1 -- the one+ ,y+ ,..}++foo =+ bar {x = + 1}++foo =+ bar {x = + 1 -- the one+ ,y+ ,..}+```++### Let, If, MultiIf, and Case++``` haskell+{-# LANGUAGE MultiWayIf #-}++foo =+ let x =+ x+ in x++foo =+ let x =+ x -- bottom+ in + -- bottom+ x++foo =+ if null+ xs+ then None+ else Some $ head+ xs++foo =+ if null+ xs -- condition+ then None -- it's empty+ else Some $ head+ xs -- it's not++foo =+ if | null+ xs ->+ None+ | otherwise ->+ Some $ head+ xs++foo =+ if | null+ xs ->+ -- it's empty+ None+ | otherwise ->+ -- it's not+ Some $ head+ x++foo =+ case x of+ True ->+ False+ False ->+ True++foo =+ case xs of+ [] ->+ -- it's empty+ None+ x:_ ->+ -- it's not+ Some+ x++foo =+ case xs of+ _+ | null+ xs ->+ None+ _ ->+ Some $ head+ x+```++### Do and MDo++``` haskell+{-# LANGUAGE RecursiveDo #-}++foo =+ do return+ ()++foo =+ do return+ ()++foo =+ do this <- that+ let this' =+ tail+ this+ if this -- condition+ then that+ else those++foo =+ mdo return+ ()+```++### Lambda, LCase++``` haskell+{-# LANGUAGE LambdaCase #-}++foo =+ \x -> + x++foo =+ \ ~x -> + x++foo =+ \ !x -> + x++foo d =+ \case+ Nothing ->+ d+ Some x ->+ x+```++### BracketExp, SpliceExp, QuasiQuote, VarQuote, and TypQuote++``` haskell+{-# LANGUAGE TemplateHaskell #-}++mkDecl :: Q Decl+mkDecl =+ [d| id x = x |]++mkType :: Q Type+mkType =+ [t|(a,b) -> a|]++mkPat :: Q Pat+mkPat =+ [p|(a,b)|]++mkExp :: Q Exp+mkExp =+ [|a|]++fst :: $(mkType)+fst $(mkPat) =+ $(mkExp)++html =+ [html|<p>Lorem Ipsum Dolor Amet Sit</p>|]++foo =+ mkSomething+ 'id+ 'Nothing+ ''Maybe+```++# Regression Tests++## Do++Before comments and onside indent do not mix well.++``` haskell+foo =+ do + -- comment+ some+ expression+```++## Onside++Indent within onside started on non-empty line should still not stack.++``` haskell+foo =+ if cond+ then do this+ else do that+```++Before comments at the start of onside do not trigger onside.++``` haskell+foo =+ do + -- comment+ some+ expression+```++Matche arms have individual onside.++``` haskell+foo True =+ some -- comment+ expression+foo False =+ some -- comment+ other+ expression+```++Where binds are considered outside of onside.++``` haskell+foo =+ some -- comment+ expression+ where expression =+ other+```++Align overrides onside.++``` haskell+foo =+ some+ expr+ [1 -- comment+ ,2]+```++If-then-else must always indent in do blocks.++``` haskell+foo =+ do if condition -- comment+ then this+ else that+```
+ styles/gibiansky.md view
@@ -0,0 +1,997 @@+# Introduction++This file acts both as a presentation of the Floskell formatting+styles, as well as a set of regression tests.++You can see how a particular style will format Haskell source by+reading the matching Markdown file in the styles/ directory.++For regression testing, the canonical source, TEST.md in the root+directory, is parsed and each Haskell code block formatted according+to all predefined styles. The formatted output is then compared with+the corresponding, already formatted code block in the <style\>.md file+in the styles/ subdirectory.++The regression test will also verify that repeated invocations of the+pretty printer will not modify an already formatted piece of code.++The following code block acts as a quick presentation for the+different formatting styles, by presenting a mixture of common Haskell+constructs.++``` haskell+{-# OPTIONS_GHC -fno-warn-name-shadowing #-}++{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards #-}++{- |+Module: Style.Haskell.Example++Haskell Code Style Example.+-}+module Style.Haskell.Example+ ( -- * Types+ Enum(..)+ , Either(..)+ , Point(..)+ -- * Functions+ , hello) where++-- Module imports+import qualified Control.Monad.Trans.State (State, evalState, execState, get+ , modify, put, runState)+import qualified Data.Map as Map+import qualified Data.Text as Text+import Prelude hiding (map)++-- Data declarations+data Enum = CaseA+ | CaseB+ | CaseC+ deriving (Eq, Enum, Show)++data Either a b = Left a+ | Right b+ deriving (Eq, Show)++data Point = Point { pointX :: Float, pointY :: Float, pointLabel :: String }+ deriving (Eq, Show)++-- Type classes+class Functor f => Applicative a where+ pure :: b -> a b+ ap :: a (b -> c) -> a b -> a c++class Fundep a b | a -> b where+ convert :: a -> b++instance Functor f => Functor (Wrap f) where+ fmap f (Wrap x) = Wrap $ fmap f x++-- Values+origin :: Point+origin = Point { pointX = 0, pointY = 0, pointLabel = "Origin" }++lorem :: [String]+lorem =+ [ "Lorem ipsum dolor sit amet, consectetur adipiscing elit."+ , "Curabitur nec ante nec mauris ornare suscipit."+ , "In ac vulputate libero."+ , "Duis eget magna non purus imperdiet molestie nec quis mauris."+ , "Praesent blandit quam vel arcu pellentesque, id aliquet turpis faucibus."]++-- Functions+facs :: [Int]+facs = [1, 1] ++ zipWith (+) (tailfacs)++hello :: MonadIO m => m ()+hello = do+ name <- liftIO getLine+ liftIO . putStrLn $ greetings name+ where+ greetings n = "Hello " ++ n ++ "!"++letExpr :: Point -> String+letExp x = let y = 1+ z = 2+ in if x > 0+ then y+ else z++ifExpr :: Bool -> Bool+ifExpr b = if b == True+ then False+ else True++caseExpr :: [a] -> Maybe a+caseExpr xs = case xs of+ [] -> Nothing+ (x:_) -> Just x++guarded :: Int -> Int+guarded x+ | x == 0 = 1+ | x == 1 = 1+ | otherwise = guarded (x - 2) + guarded (x - 1)++someLongFunctionNameWithALotOfParameters+ :: (MonadIO m, MonadRandom m) => String -> (String -> String) -> m ()+someLongFunctionNameWithALotOfParameters = undefined+```++# Unit Tests++## ModuleHead and ExportSpecList++Without exports++``` haskell+module Main where+```++With exports++``` haskell+module Main (foo, bar, baz, main) where+```++With exports and comments++``` haskell+module Main+ ( -- * Main Program+ main+ -- * Functions+ , foo -- foo function+ , bar -- bar function+ , baz -- baz function+ ) where+```++With deprecation++``` haskell+module Main {-# DEPRECATED "no longer supported" #-} where+```++With warnings++``` haskell+module Main {-# WARNING "do not use" #-} where+```++## ImportDecl++``` haskell+import Prelude+import Data.Text (Text)+import qualified Data.Text as T+import qualified Data.ByteString (ByteString, pack, unpack)+import qualified Data.ByteString as BS (pack, unpack)+import Control.Monad hiding (forM)+import {-# SOURCE #-} safe qualified "foo" Foo as F+```++## Decl++### TypeDecl++``` haskell+type Name = String++type Pair a = (a, a)++type Fun a b = a -> b+```++### DataDecl and GDataDecl++``` haskell+data Void++data Unit = Unit++data Maybe a = Nothing+ | Just a++data Num a => SomeNum = SomeNum a++newtype RWS r w s = RWS (ReaderT r (WriterT w (StateT s Identity)))+ deriving (Functor, Applicative, Monad)++data Enum = One -- Foo+ | Two -- Bar+ | Three -- Baz++data Foo+ deriving ()++data Foo+ deriving Show++data Foo+ deriving (Show)++data Foo+ deriving (Eq, Ord)++data Expr :: * -> * where+ Const :: Int -> Expr Int+ Plus :: Expr Int -> Expr Int -> Expr Int+ Eq :: Expr Int -> Expr Int -> Expr Bool+ deriving (Show)++data Term a where+ Lit :: { val :: Int } -> Term Int+ Succ :: { num :: Term Int } -> Term Int+ Pred :: { num :: Term Int } -> Term Int+ IsZero :: { arg :: Term Int } -> Term Bool+ Pair :: { arg1 :: Term a, arg2 :: Term b } -> Term (a, b)+ If :: { cnd :: Term Bool, tru :: Term a, fls :: Term a } -> Term a+```++### TypeFamDecl, TypeInsDecl, and ClosedTypeFamDecl++``` haskell+type family Mutable v++type family Mutable v = (r :: *)++type family Mutable v = r | r -> v++type instance Mutable Int = MIntVector++type family Store a where+ Store Bool = [Int]+ Store a = [a]++type family Store a = (r :: *) where+ Store a = [a]++type family Store a = r | r -> a where+ Store a = [a]+```++### DataFamDecl, DataInsDecl, and GDataInsDecl++``` haskell+data family List a++data instance List () = NilList Int++data instance List Char = CharNil+ | CharCons Char (List Char)+ deriving (Eq, Ord, Show)++data instance List Int :: * where+ IntNil :: List Int+ IntCons :: Int -> List Int+ deriving (Eq, Ord, Show)++data instance List Int :: * where+ IntNil :: List Int+ IntCons :: { val :: Int } -> List Int+ deriving (Eq, Ord, Show)++newtype Penalty = Penalty Int+ deriving (Eq, Ord)+ deriving stock (Read, Show)+ deriving newtype (Num)+ deriving anyclass (FromJSON, ToJSON)+ deriving (Semigroup, Monoid) via M.Sum Int+```++### ClassDecl and InstDecl++``` haskell+class Monoid a where+ mempty :: a+ mappend :: a -> a -> a++class Applicative m => Monad m where+ fail :: m a+ return :: a -> m a+ (>>=) :: a -> (a -> m b) -> m b++class Monad m => MonadState s m | m -> s where+ get :: m s+ put :: s -> m ()+ state :: (s -> (a, s)) -> m a++class ToJSON a where+ toJSON :: a -> Value+ default toJSON :: (Generic a, GToJSON (Rep a)) => a -> Value+ toJSON = genericToJSON defaultOptions++instance ToJSON ()++instance Bounded Bool where+ minBound = False++ maxBound = True++instance Semigroup a => Monoid (Maybe a) where+ mempty = Nothing++ Nothing `mappend` m = m+ m `mappend` Nothing = m+ Just m1 `mappend` Just m2 = Just (m1 `mappend` m2)++instance Data () where+ type Base = ()++ newtype Wrapped = Wrapped { unWrap :: () }++ data Expr :: * -> * where+ Const :: Int -> Expr Int+ Plus :: Expr Int -> Expr Int -> Expr Int+ Eq :: Expr Int -> Expr Int -> Expr Bool+```++### DerivDecl++``` haskell+deriving instance Eq a => Eq (Sum a)++deriving instance {-# OVERLAP #-} Eq a => Eq (Sum a)++deriving stock instance {-# OVERLAPS #-} Eq a => Eq (Sum a)++deriving anyclass instance {-# OVERLAPPING #-} Eq a => Eq (Sum a)++deriving newtype instance {-# OVERLAPPABLE #-} Eq a => Eq (Sum a)+```++### InfixDecl++``` haskell+infix 4 ==, /=, <, <=, >, >=++infixr 0 $++infixl !!+```++### DefaultDecl++``` haskell+default ()++default (Integer, Double)+```++### SpliceDecl++``` haskell+$foo++$(bar baz)+```++### TypeSig++``` haskell+id :: a -> a+sort :: Ord a => [a] -> [a]+long :: (IsString a, Monad m)+ => ByteString+ -> ByteString+ -> ByteString+ -> ByteString+ -> ByteString+ -> a+ -> m ()+mktime :: Int -- hours+ -> Int -- minutes+ -> Int -- seconds+ -> Time+transform :: forall a. St -> State St a -> EitherT ServantErr IO a+```++### PatSyn and PatSynSig++``` haskell+{-# LANGUAGE PatternSynonyms #-}++pattern MyJust :: a -> Maybe a+pattern MyJust a = Just a++pattern MyPoint :: Int -> Int -> (Int, Int)+pattern MyPoint { x, y } = (x, y)++pattern ErrorCall :: String -> ErrorCall+pattern ErrorCall s <- ErrorCallWithLocation s _+ where+ ErrorCall s = ErrorCallWithLocation s ""++pattern IsTrue :: Show a => a+pattern IsTrue <- ((== "True") . show -> True)++pattern ExNumPat :: () => Show b => b -> T+pattern ExNumPat x = MkT x++pattern Foo, Bar :: Show a => a+```++### FunBind and PatBind++``` haskell+{-# LANGUAGE UnboxedTuples #-}+{-# LANGUAGE UnboxedSums #-}+{-# LANGUAGE RecordWildCards #-}++pi = 3.14++id x = x++not False = True+not _ = False++head (x:_) = x++maybe x _ Nothing = x+maybe _ f (Some x) = f x++fst (x, _) = x++fst' (# x, _ #) = x++fstPrism (# x | | #) = Just x+fstPrism (# | _ | #) = Nothing+fstPrism (# | | _ #) = Nothing++empty [] = True+empty _ = False++unSum (Sum { getSum = s }) = s++mag2 Point { x, y } = sqr x + sqr y+mag2 Point { .. } = sqr x + sqr y++strict !x = x++irrefutable ~x = x++(//) a b = undefined++a // b = undefined++main = do+ greet "World"+ where+ greet who = putStrLn $ "Hello, " ++ who ++ "!"+```++### ForImp and ForExp++``` haskell+{-# LANGUAGE ForeignFunctionInterface #-}++foreign import ccall sin :: Double -> Double++foreign import ccall "sin" sin :: Double -> Double++foreign import ccall "sin" sin :: Double -> Double++foreign import ccall unsafe exit :: Double -> Double++foreign export ccall callback :: Int -> Int+```++### Pragmas++``` haskell+{-# RULES #-}++{-# RULES "map/map" forall f g xs. map f (map g xs) = map (f . g) xs #-}++{-# RULES "map/append" [2] forall f xs ys. map f (xs ++ ys) =+ map f xs ++ map f ys #-}++{-# DEPRECATED #-}+{-# DEPRECATED foo "use bar instead" #-}+{-# DEPRECATED foo, bar, baz "no longer supported" #-}+{-# WARNING #-}+{-# WARNING foo "use bar instead" #-}+{-# WARNING foo, bar, baz "no longer supported" #-}+{-# INLINE foo #-}+{-# INLINE [3] foo #-}+{-# INLINE [~3] foo #-}+{-# NOINLINE foo #-}+{-# INLINE CONLIKE foo #-}+{-# INLINE CONLIKE [3] foo #-}+{-# SPECIALISE foo :: Int -> Int #-}+{-# SPECIALISE [3] foo :: Int -> Int, Float -> Float #-}+{-# SPECIALISE INLINE foo :: Int -> Int #-}+{-# SPECIALISE NOINLINE foo :: Int -> Int #-}+{-# SPECIALISE instance Foo Int #-}+{-# SPECIALISE instance forall a. (Ord a) => Foo a #-}+{-# ANN foo (Just "Foo") #-}+{-# ANN type Foo (Just "Foo") #-}+{-# ANN module (Just "Foo") #-}+{-# MINIMAL foo | bar, (baz | quux) #-}+```++## Exp++### Var, Con, Lit, Tuple, UnboxedSum, List, and ExpTypeSig++``` haskell+{-# LANGUAGE TupleSections #-}+{-# LANGUAGE UnboxedTuples #-}+{-# LANGUAGE UnboxedSums #-}++foo = foo++foo = Nothing++foo = 123++foo = 'x'++foo = ""++foo = "Lorem Ipsum Dolor Amet Sit"++foo = ()++foo = (1, 2)++foo = ( 1 -- the one+ , 2)++foo = (1, )++foo = (, 2)++foo = (, 2, )++foo = (# #)++foo = (# 1, 2 #)++foo = (# 1 -- the one+ , 2 #)++foo = (# 1 #)++foo = (# | 1 | | #)++foo = (# | 1 -- the one+ | | #)++foo = []++foo = [1]++foo = [1, 2]++foo = [ 1 -- the one+ , 2]++foo = 1 :: Int+```++### App, InfixApp, NegApp, LeftSection, RightSection++``` haskell+foo = foldl fn init list++foo = foldl+ fn -- reducer+ init -- initial value+ list++foo = 1 + 2++foo = fn `map` list++foo = -3++foo = (+ arg)++foo = (`op` arg)++foo = (arg +)++foo = (arg `op`)+```++### EnumFrom, EnumFromTo, EnumFromThen, EnumFromThenTo, ParArrayFromTo, ParArrayFromThenTo++``` haskell+foo = [1 ..]++foo = [1 .. 10]++foo = [1, 2 ..]++foo = [1, 2 .. 10]++foo = [:1 .. 10:]++foo = [:1, 2 .. 10:]+```++### ListComp, ParComp, and ParArrayComp++``` haskell+{-# LANGUAGE TransformListComp #-}++foo = [(x, y) | x <- xs, y <- ys]++foo = [(x, y) -- cartesian product+ | x <- xs -- first list+ , y <- ys -- second list+ ]++foo = [(x, y) | x <- xs | y <- ys]++foo = [(x, y) -- zip+ | x <- xs -- first list+ | y <- ys -- second list+ ]++foo = [:(x, y) | x <- xs | y <- ys:]++foo = [:(x, y) -- zip+ | x <- xs -- first list+ | y <- ys -- second list+ :]++foo = [(x, y)+ | x <- xs+ , y <- ys+ , then reverse+ , then sortWith by (x + y)+ , then group using permutations+ , then group by (x + y) using groupWith]+```++### RecConstr and RecUpdate++``` haskell+{-# LANGUAGE RecordWildCards #-}++foo = Point { x = 1, y = 2 }++foo = Point { x = 1 -- the one+ , y+ , ..+ }++foo = bar { x = 1 }++foo = bar { x = 1 -- the one+ , y+ , ..+ }+```++### Let, If, MultiIf, and Case++``` haskell+{-# LANGUAGE MultiWayIf #-}++foo = let x = x+ in x++foo = let x = x -- bottom+ in+ -- bottom+ x++foo = if null xs+ then None+ else Some $ head xs++foo = if null xs -- condition+ then None -- it's empty+ else Some $ head xs -- it's not++foo = if+ | null xs -> None+ | otherwise -> Some $ head xs++foo = if+ | null xs ->+ -- it's empty+ None+ | otherwise ->+ -- it's not+ Some $ head x++foo = case x of+ True -> False+ False -> True++foo = case xs of+ [] ->+ -- it's empty+ None+ x:_ ->+ -- it's not+ Some x++foo = case xs of+ _+ | null xs -> None+ _ -> Some $ head x+```++### Do and MDo++``` haskell+{-# LANGUAGE RecursiveDo #-}++foo = do+ return ()++foo = do+ return ()++foo = do+ this <- that+ let this' = tail this+ if this -- condition+ then that+ else those++foo = mdo+ return ()+```++### Lambda, LCase++``` haskell+{-# LANGUAGE LambdaCase #-}++foo = \x -> x++foo = \ ~x -> x++foo = \ !x -> x++foo d = \case+ Nothing -> d+ Some x -> x+```++### BracketExp, SpliceExp, QuasiQuote, VarQuote, and TypQuote++``` haskell+{-# LANGUAGE TemplateHaskell #-}++mkDecl :: Q Decl+mkDecl = [d|id x = x|]++mkType :: Q Type+mkType = [t|(a, b) -> a|]++mkPat :: Q Pat+mkPat = [p|(a, b)|]++mkExp :: Q Exp+mkExp = [|a|]++fst :: $(mkType)+fst $(mkPat) = $(mkExp)++html = [html|<p>Lorem Ipsum Dolor Amet Sit</p>|]++foo = mkSomething 'id 'Nothing ''Maybe+```++# Regression Tests++## Do++Before comments and onside indent do not mix well.++``` haskell+foo = do+ -- comment+ some expression+```++## Types++Long types allow linebreaks.++``` haskell+newtype MyMonadT a b m =+ MyMonad { runMyMonad+ :: StateT+ ([(a, a -> b)])+ (ReaderT a (ExceptT [IM.IntMap b]) (WriterT [IS.IntSet x] m))+ }+```++Promoted types.++``` haskell+type Foo = Bar 1 "foo" '() '(A, B) '[X, Y]+```++## Patterns++Long function pattern matches allow linebreaks.++``` haskell+doThing+ (Constructor field1 field2 field3)+ (Constructor field1 field2 field3)+ (Constructor field1 field2 field3) = undefined+```++## Onside++Indent within onside started on non-empty line should still not stack.++``` haskell+foo = if cond+ then do+ this+ else do+ that+```++Before comments at the start of onside do not trigger onside.++``` haskell+foo = do+ -- comment+ some expression+```++Matche arms have individual onside.++``` haskell+foo True = some -- comment+ expression+foo False = some -- comment+ other+ expression+```++Where binds are considered outside of onside.++``` haskell+foo = some -- comment+ expression+ where+ expression = other+```++Align overrides onside.++``` haskell+foo = some+ expr+ [ 1 -- comment+ , 2]+```++If-then-else must always indent in do blocks.++``` haskell+foo = do+ if condition -- comment+ then this+ else that+```++Lists must not suppress onside.++``` haskell+foo = case x of+ [ y -- comment+ , z] -> bar++foo = do+ [ x -- comment+ , y]+```++## Comments++Don't be too eager in assigning comments to the following AST node.++``` haskell+data Foo =+ Foo { fooBar :: Text+ -- ^A comment, long enough to end up on its own line, or at least I hope so.+ }+ deriving (Eq)+```++Keep comments together and aligned.++``` haskell+-- block+-- one+data Foo = Foo -- some+ -- comments+ | Quux -- more+ -- comments+-- block+-- two+```++... even when haskell-src-exts has weird column span info.++``` haskell+module Main where++-- comment+instance Foo Bar where+ foo = undefined++bar = undefined+```++Only comments.++``` haskell+-- some comment+```++Make sure no comments are dropped from operators or argument.++``` haskell+foo = some -- comment 1+ -- comment 2+ %~ -- comment 3+ argument -- comment 4+```++Comments after `where` stay there.++``` haskell+consM :: Monad m => m a -> Stream m a -> Stream m a+consM m (Stream step state) = Stream step1 Nothing+ where+ {-# INLINE_LATE step1 #-}+ step1 _ _ = undefined+```++Comments between declarations do not cause empty lines.++``` haskell+f :: ()+--+f = ()+```++## Indentation and Line Prefixes++Preserving indentation and line prefixes so that Floskell can be run+on individual declarations and quoted haskell code.++``` haskell+ data Enum = One -- Foo+ | Two -- Bar+ | Three -- Baz+```++``` haskell+>+> data Enum = One -- Foo+> | Two -- Bar+> | Three -- Baz+>+```++## Module Exports++Long module exports don't force overlong line.++``` haskell+module SimpleFunctions+ ( identity+ , compose+ , append+ , firstElement+ , secondElem) where+```
+ styles/johan-tibell.md view
@@ -0,0 +1,1058 @@+# Introduction++This file acts both as a presentation of the Floskell formatting+styles, as well as a set of regression tests.++You can see how a particular style will format Haskell source by+reading the matching Markdown file in the styles/ directory.++For regression testing, the canonical source, TEST.md in the root+directory, is parsed and each Haskell code block formatted according+to all predefined styles. The formatted output is then compared with+the corresponding, already formatted code block in the <style\>.md file+in the styles/ subdirectory.++The regression test will also verify that repeated invocations of the+pretty printer will not modify an already formatted piece of code.++The following code block acts as a quick presentation for the+different formatting styles, by presenting a mixture of common Haskell+constructs.++``` haskell+{-# OPTIONS_GHC -fno-warn-name-shadowing #-}++{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards #-}++{- |+Module: Style.Haskell.Example++Haskell Code Style Example.+-}+module Style.Haskell.Example+ (-- * Types+ Enum(..)+ ,Either(..)+ ,Point(..)+ -- * Functions+ ,hello) where++-- Module imports+import qualified Control.Monad.Trans.State+ (State,evalState,execState,get,modify,put,runState)+import qualified Data.Map as Map+import qualified Data.Text as Text+import Prelude hiding (map)++-- Data declarations+data Enum+ = CaseA+ | CaseB+ | CaseC+ deriving (Eq,Enum,Show)++data Either a b+ = Left a+ | Right b+ deriving (Eq,Show)++data Point =+ Point+ { pointX :: Float+ , pointY :: Float+ , pointLabel :: String+ }+ deriving (Eq,Show)++-- Type classes+class Functor f => Applicative a where+ pure :: b -> a b+ ap :: a (b -> c) -> a b -> a c++class Fundep a b | a -> b where+ convert :: a -> b++instance Functor f => Functor (Wrap f) where+ fmap f (Wrap x) = Wrap $ fmap f x++-- Values+origin :: Point+origin =+ Point+ { pointX = 0+ , pointY = 0+ , pointLabel = "Origin"+ }++lorem :: [String]+lorem =+ [ "Lorem ipsum dolor sit amet, consectetur adipiscing elit."+ , "Curabitur nec ante nec mauris ornare suscipit."+ , "In ac vulputate libero."+ , "Duis eget magna non purus imperdiet molestie nec quis mauris."+ , "Praesent blandit quam vel arcu pellentesque, id aliquet turpis faucibus."]++-- Functions+facs :: [Int]+facs = [1, 1] ++ zipWith (+) (tailfacs)++hello :: MonadIO m => m ()+hello = do+ name <- liftIO getLine+ liftIO . putStrLn $ greetings name+ where+ greetings n = "Hello " ++ n ++ "!"++letExpr :: Point -> String+letExp x =+ let y = 1+ z = 2+ in if x > 0+ then y+ else z++ifExpr :: Bool -> Bool+ifExpr b =+ if b == True+ then False+ else True++caseExpr :: [a] -> Maybe a+caseExpr xs = case xs of+ [] -> Nothing+ (x:_) -> Just x++guarded :: Int -> Int+guarded x+ | x == 0 = 1+ | x == 1 = 1+ | otherwise = guarded (x - 2) + guarded (x - 1)++someLongFunctionNameWithALotOfParameters+ :: (MonadIO m, MonadRandom m) => String -> (String -> String) -> m ()+someLongFunctionNameWithALotOfParameters = undefined+```++# Unit Tests++## ModuleHead and ExportSpecList++Without exports++``` haskell+module Main where+```++With exports++``` haskell+module Main (foo,bar,baz,main) where+```++With exports and comments++``` haskell+module Main+ (-- * Main Program+ main+ -- * Functions+ ,foo -- foo function+ ,bar -- bar function+ ,baz -- baz function+ ) where+```++With deprecation++``` haskell+module Main {-# DEPRECATED "no longer supported" #-} where+```++With warnings++``` haskell+module Main {-# WARNING "do not use" #-} where+```++## ImportDecl++``` haskell+import Prelude+import Data.Text (Text)+import qualified Data.Text as T+import qualified Data.ByteString (ByteString,pack,unpack)+import qualified Data.ByteString as BS (pack,unpack)+import Control.Monad hiding (forM)+import {-# SOURCE #-} safe qualified "foo" Foo as F+```++## Decl++### TypeDecl++``` haskell+type Name = String++type Pair a = (a, a)++type Fun a b = a -> b+```++### DataDecl and GDataDecl++``` haskell+data Void++data Unit = Unit++data Maybe a+ = Nothing+ | Just a++data Num a => SomeNum = SomeNum a++newtype RWS r w s = RWS (ReaderT r (WriterT w (StateT s Identity)))+ deriving (Functor,Applicative,Monad)++data Enum+ = One -- Foo+ | Two -- Bar+ | Three -- Baz++data Foo+ deriving ()++data Foo+ deriving Show++data Foo+ deriving (Show)++data Foo+ deriving (Eq,Ord)++data Expr :: * -> * where+ Const :: Int -> Expr Int+ Plus :: Expr Int -> Expr Int -> Expr Int+ Eq :: Expr Int -> Expr Int -> Expr Bool+ deriving (Show)++data Term a where+ Lit :: { val :: Int+ } -> Term Int+ Succ :: { num :: Term Int+ } -> Term Int+ Pred :: { num :: Term Int+ } -> Term Int+ IsZero :: { arg :: Term Int+ } -> Term Bool+ Pair :: { arg1 :: Term a+ , arg2 :: Term b+ } -> Term (a, b)+ If :: { cnd :: Term Bool+ , tru :: Term a+ , fls :: Term a+ } -> Term a+```++### TypeFamDecl, TypeInsDecl, and ClosedTypeFamDecl++``` haskell+type family Mutable v++type family Mutable v = (r :: *)++type family Mutable v = r | r -> v++type instance Mutable Int = MIntVector++type family Store a where+ Store Bool = [Int]+ Store a = [a]++type family Store a = (r :: *) where+ Store a = [a]++type family Store a = r | r -> a where+ Store a = [a]+```++### DataFamDecl, DataInsDecl, and GDataInsDecl++``` haskell+data family List a++data instance List () = NilList Int++data instance List Char+ = CharNil+ | CharCons Char (List Char)+ deriving (Eq,Ord,Show)++data instance List Int :: * where+ IntNil :: List Int+ IntCons :: Int -> List Int+ deriving (Eq,Ord,Show)++data instance List Int :: * where+ IntNil :: List Int+ IntCons :: { val :: Int+ } -> List Int+ deriving (Eq,Ord,Show)++newtype Penalty = Penalty Int+ deriving (Eq,Ord)+ deriving stock (Read,Show)+ deriving newtype (Num)+ deriving anyclass (FromJSON,ToJSON)+ deriving (Semigroup,Monoid) via M.Sum Int+```++### ClassDecl and InstDecl++``` haskell+class Monoid a where+ mempty :: a+ mappend :: a -> a -> a++class Applicative m => Monad m where+ fail :: m a+ return :: a -> m a+ (>>=) :: a -> (a -> m b) -> m b++class Monad m => MonadState s m | m -> s where+ get :: m s+ put :: s -> m ()+ state :: (s -> (a, s)) -> m a++class ToJSON a where+ toJSON :: a -> Value+ default toJSON :: (Generic a, GToJSON (Rep a)) => a -> Value+ toJSON = genericToJSON defaultOptions++instance ToJSON ()++instance Bounded Bool where+ minBound = False++ maxBound = True++instance Semigroup a => Monoid (Maybe a) where+ mempty = Nothing++ Nothing `mappend` m = m+ m `mappend` Nothing = m+ Just m1 `mappend` Just m2 = Just (m1 `mappend` m2)++instance Data () where+ type Base = ()++ newtype Wrapped =+ Wrapped+ { unWrap :: ()+ }++ data Expr :: * -> * where+ Const :: Int -> Expr Int+ Plus :: Expr Int -> Expr Int -> Expr Int+ Eq :: Expr Int -> Expr Int -> Expr Bool+```++### DerivDecl++``` haskell+deriving instance Eq a => Eq (Sum a)++deriving instance {-# OVERLAP #-} Eq a => Eq (Sum a)++deriving stock instance {-# OVERLAPS #-} Eq a => Eq (Sum a)++deriving anyclass instance {-# OVERLAPPING #-} Eq a => Eq (Sum a)++deriving newtype instance {-# OVERLAPPABLE #-} Eq a => Eq (Sum a)+```++### InfixDecl++``` haskell+infix 4 ==, /=, <, <=, >, >=++infixr 0 $++infixl !!+```++### DefaultDecl++``` haskell+default ()++default (Integer,Double)+```++### SpliceDecl++``` haskell+$foo++$(bar baz)+```++### TypeSig++``` haskell+id :: a -> a+sort :: Ord a => [a] -> [a]+long :: (IsString a, Monad m)+ => ByteString+ -> ByteString+ -> ByteString+ -> ByteString+ -> ByteString+ -> a+ -> m ()+mktime :: Int -- hours+ -> Int -- minutes+ -> Int -- seconds+ -> Time+transform :: forall a. St -> State St a -> EitherT ServantErr IO a+```++### PatSyn and PatSynSig++``` haskell+{-# LANGUAGE PatternSynonyms #-}++pattern MyJust :: a -> Maybe a+pattern MyJust a = Just a++pattern MyPoint :: Int -> Int -> (Int, Int)+pattern MyPoint {x,y} = (x,y)++pattern ErrorCall :: String -> ErrorCall+pattern ErrorCall s <- ErrorCallWithLocation s _+ where+ ErrorCall s = ErrorCallWithLocation s ""++pattern IsTrue :: Show a => a+pattern IsTrue <- ((== "True") . show -> True)++pattern ExNumPat :: () => Show b => b -> T+pattern ExNumPat x = MkT x++pattern Foo, Bar :: Show a => a+```++### FunBind and PatBind++``` haskell+{-# LANGUAGE UnboxedTuples #-}+{-# LANGUAGE UnboxedSums #-}+{-# LANGUAGE RecordWildCards #-}++pi = 3.14++id x = x++not False = True+not _ = False++head (x:_) = x++maybe x _ Nothing = x+maybe _ f (Some x) = f x++fst (x,_) = x++fst' (# x,_ #) = x++fstPrism (# x | | #) = Just x+fstPrism (# | _ | #) = Nothing+fstPrism (# | | _ #) = Nothing++empty [] = True+empty _ = False++unSum (Sum {getSum = s}) = s++mag2 Point {x,y} = sqr x + sqr y+mag2 Point {..} = sqr x + sqr y++strict !x = x++irrefutable ~x = x++(//) a b = undefined++a // b = undefined++main = do+ greet "World"+ where+ greet who = putStrLn $ "Hello, " ++ who ++ "!"+```++### ForImp and ForExp++``` haskell+{-# LANGUAGE ForeignFunctionInterface #-}++foreign import ccall sin :: Double -> Double++foreign import ccall "sin" sin :: Double -> Double++foreign import ccall "sin" sin :: Double -> Double++foreign import ccall unsafe exit :: Double -> Double++foreign export ccall callback :: Int -> Int+```++### Pragmas++``` haskell+{-# RULES #-}++{-# RULES "map/map" forall f g xs. map f (map g xs) = map (f . g) xs #-}++{-# RULES "map/append" [2] forall f xs ys. map f (xs ++ ys) =+ map f xs ++ map f ys #-}++{-# DEPRECATED #-}+{-# DEPRECATED foo "use bar instead" #-}+{-# DEPRECATED foo, bar, baz "no longer supported" #-}+{-# WARNING #-}+{-# WARNING foo "use bar instead" #-}+{-# WARNING foo, bar, baz "no longer supported" #-}+{-# INLINE foo #-}+{-# INLINE [3] foo #-}+{-# INLINE [~3] foo #-}+{-# NOINLINE foo #-}+{-# INLINE CONLIKE foo #-}+{-# INLINE CONLIKE [3] foo #-}+{-# SPECIALISE foo :: Int -> Int #-}+{-# SPECIALISE [3] foo :: Int -> Int, Float -> Float #-}+{-# SPECIALISE INLINE foo :: Int -> Int #-}+{-# SPECIALISE NOINLINE foo :: Int -> Int #-}+{-# SPECIALISE instance Foo Int #-}+{-# SPECIALISE instance forall a. (Ord a) => Foo a #-}+{-# ANN foo (Just "Foo") #-}+{-# ANN type Foo (Just "Foo") #-}+{-# ANN module (Just "Foo") #-}+{-# MINIMAL foo | bar, (baz | quux) #-}+```++## Exp++### Var, Con, Lit, Tuple, UnboxedSum, List, and ExpTypeSig++``` haskell+{-# LANGUAGE TupleSections #-}+{-# LANGUAGE UnboxedTuples #-}+{-# LANGUAGE UnboxedSums #-}++foo = foo++foo = Nothing++foo = 123++foo = 'x'++foo = ""++foo = "Lorem Ipsum Dolor Amet Sit"++foo = ()++foo = (1, 2)++foo =+ ( 1 -- the one+ , 2)++foo = (1, )++foo = (, 2)++foo = (, 2, )++foo = (# #)++foo = (# 1, 2 #)++foo =+ (# 1 -- the one+ , 2 #)++foo = (# 1 #)++foo = (# | 1 | | #)++foo =+ (# | 1 -- the one+ | | #)++foo = []++foo = [1]++foo = [1, 2]++foo =+ [ 1 -- the one+ , 2]++foo = 1 :: Int+```++### App, InfixApp, NegApp, LeftSection, RightSection++``` haskell+foo = foldl fn init list++foo =+ foldl+ fn -- reducer+ init -- initial value+ list++foo = 1 + 2++foo = fn `map` list++foo = -3++foo = (+ arg)++foo = (`op` arg)++foo = (arg +)++foo = (arg `op`)+```++### EnumFrom, EnumFromTo, EnumFromThen, EnumFromThenTo, ParArrayFromTo, ParArrayFromThenTo++``` haskell+foo = [1 ..]++foo = [1 .. 10]++foo = [1, 2 ..]++foo = [1, 2 .. 10]++foo = [:1 .. 10:]++foo = [:1, 2 .. 10:]+```++### ListComp, ParComp, and ParArrayComp++``` haskell+{-# LANGUAGE TransformListComp #-}++foo = [(x, y) | x <- xs, y <- ys]++foo =+ [(x, y) -- cartesian product+ | x <- xs -- first list+ , y <- ys -- second list+ ]++foo = [(x, y) | x <- xs | y <- ys]++foo =+ [(x, y) -- zip+ | x <- xs -- first list+ | y <- ys -- second list+ ]++foo = [:(x, y) | x <- xs | y <- ys:]++foo =+ [:(x, y) -- zip+ | x <- xs -- first list+ | y <- ys -- second list+ :]++foo =+ [(x, y) | x <- xs+ , y <- ys+ , then reverse+ , then sortWith by (x + y)+ , then group using permutations+ , then group by (x + y) using groupWith]+```++### RecConstr and RecUpdate++``` haskell+{-# LANGUAGE RecordWildCards #-}++foo =+ Point+ { x = 1+ , y = 2+ }++foo =+ Point+ { x = 1 -- the one+ , y+ , ..+ }++foo =+ bar+ { x = 1+ }++foo =+ bar+ { x = 1 -- the one+ , y+ , ..+ }+```++### Let, If, MultiIf, and Case++``` haskell+{-# LANGUAGE MultiWayIf #-}++foo =+ let x = x+ in x++foo =+ let x = x -- bottom+ in+ -- bottom+ x++foo =+ if null xs+ then None+ else Some $ head xs++foo =+ if null xs -- condition+ then None -- it's empty+ else Some $ head xs -- it's not++foo =+ if+ | null xs -> None+ | otherwise -> Some $ head xs++foo =+ if+ | null xs ->+ -- it's empty+ None+ | otherwise ->+ -- it's not+ Some $ head x++foo = case x of+ True -> False+ False -> True++foo = case xs of+ [] ->+ -- it's empty+ None+ x:_ ->+ -- it's not+ Some x++foo = case xs of+ _+ | null xs -> None+ _ -> Some $ head x+```++### Do and MDo++``` haskell+{-# LANGUAGE RecursiveDo #-}++foo = do+ return ()++foo = do+ return ()++foo = do+ this <- that+ let this' = tail this+ if this -- condition+ then that+ else those++foo = mdo+ return ()+```++### Lambda, LCase++``` haskell+{-# LANGUAGE LambdaCase #-}++foo = \x -> x++foo = \ ~x -> x++foo = \ !x -> x++foo d = \case+ Nothing -> d+ Some x -> x+```++### BracketExp, SpliceExp, QuasiQuote, VarQuote, and TypQuote++``` haskell+{-# LANGUAGE TemplateHaskell #-}++mkDecl :: Q Decl+mkDecl = [d|id x = x|]++mkType :: Q Type+mkType = [t|(a, b) -> a|]++mkPat :: Q Pat+mkPat = [p|(a,b)|]++mkExp :: Q Exp+mkExp = [|a|]++fst :: $(mkType)+fst $(mkPat) = $(mkExp)++html = [html|<p>Lorem Ipsum Dolor Amet Sit</p>|]++foo = mkSomething 'id 'Nothing ''Maybe+```++# Regression Tests++## Do++Before comments and onside indent do not mix well.++``` haskell+foo = do+ -- comment+ some expression+```++## Types++Long types allow linebreaks.++``` haskell+newtype MyMonadT a b m =+ MyMonad+ { runMyMonad+ :: StateT+ ([(a, a -> b)])+ (ReaderT a (ExceptT [IM.IntMap b]) (WriterT [IS.IntSet x] m))+ }+```++Promoted types.++``` haskell+type Foo = Bar 1 "foo" '() '(A, B) '[X, Y]+```++## Patterns++Long function pattern matches allow linebreaks.++``` haskell+doThing+ (Constructor field1 field2 field3)+ (Constructor field1 field2 field3)+ (Constructor field1 field2 field3) = undefined+```++## Onside++Indent within onside started on non-empty line should still not stack.++``` haskell+foo =+ if cond+ then do+ this+ else do+ that+```++Before comments at the start of onside do not trigger onside.++``` haskell+foo = do+ -- comment+ some expression+```++Matche arms have individual onside.++``` haskell+foo True =+ some -- comment+ expression+foo False =+ some -- comment+ other+ expression+```++Where binds are considered outside of onside.++``` haskell+foo =+ some -- comment+ expression+ where+ expression = other+```++Align overrides onside.++``` haskell+foo =+ some+ expr+ [ 1 -- comment+ , 2]+```++If-then-else must always indent in do blocks.++``` haskell+foo = do+ if condition -- comment+ then this+ else that+```++Lists must not suppress onside.++``` haskell+foo = case x of+ [y -- comment+ ,z] -> bar++foo = do+ [ x -- comment+ , y]+```++## Comments++Don't be too eager in assigning comments to the following AST node.++``` haskell+data Foo =+ Foo+ { fooBar :: Text+ -- ^A comment, long enough to end up on its own line, or at least I hope so.+ }+ deriving (Eq)+```++Keep comments together and aligned.++``` haskell+-- block+-- one+data Foo+ = Foo -- some+ -- comments+ | Quux -- more+ -- comments+-- block+-- two+```++... even when haskell-src-exts has weird column span info.++``` haskell+module Main where++-- comment+instance Foo Bar where+ foo = undefined++bar = undefined+```++Only comments.++``` haskell+-- some comment+```++Make sure no comments are dropped from operators or argument.++``` haskell+foo =+ some -- comment 1+ -- comment 2+ %~ -- comment 3+ argument -- comment 4+```++Comments after `where` stay there.++``` haskell+consM :: Monad m => m a -> Stream m a -> Stream m a+consM m (Stream step state) = Stream step1 Nothing+ where+ {-# INLINE_LATE step1 #-}+ step1 _ _ = undefined+```++Comments between declarations do not cause empty lines.++``` haskell+f :: ()+--+f = ()+```++## Indentation and Line Prefixes++Preserving indentation and line prefixes so that Floskell can be run+on individual declarations and quoted haskell code.++``` haskell+ data Enum+ = One -- Foo+ | Two -- Bar+ | Three -- Baz+```++``` haskell+>+> data Enum+> = One -- Foo+> | Two -- Bar+> | Three -- Baz+>+```++## Module Exports++Long module exports don't force overlong line.++``` haskell+module SimpleFunctions (identity,compose,append,firstElement,secondElem) where+```