mirror of
https://github.com/google/ormolu.git
synced 2024-11-23 22:27:16 +03:00
297 lines
4.8 KiB
Markdown
297 lines
4.8 KiB
Markdown
We aim for a format of Haskell code that minimizes the amount of changes
|
|
necessary when modifying a line. For instance the indentation of any
|
|
given fragment of code should not depend on the length of identifiers.
|
|
|
|
```Haskell
|
|
longFunctionName :: a
|
|
-> b
|
|
-> c
|
|
-> d
|
|
-> (a, b, c, d)
|
|
```
|
|
|
|
Renaming the function requires changing all the lines to
|
|
```Haskell
|
|
f :: a
|
|
-> b
|
|
-> c
|
|
-> d
|
|
-> (a, b, c, d)
|
|
```
|
|
|
|
A preferred alternative is to format like
|
|
```Haskell
|
|
longFunctionName
|
|
:: a
|
|
-> b
|
|
-> c
|
|
-> d
|
|
-> (a, b, c, d)
|
|
```
|
|
|
|
We are grabbing some inspiration from
|
|
[Elm](https://elm-lang.org/docs/style-guide)
|
|
and
|
|
[Tweag's](https://github.com/tweag/guides/blob/master/style/Haskell.md)
|
|
style guides.
|
|
|
|
The following examples show how a program is formatted in
|
|
multiple lines when the user introduces linebreaks. Otherwise,
|
|
the programs would be written in one line.
|
|
|
|
### Function types
|
|
|
|
```Haskell
|
|
functionName
|
|
:: (C1, C2, C3)
|
|
=> a
|
|
-> b
|
|
-> c
|
|
-> d
|
|
-> (a, b, c, d)
|
|
```
|
|
|
|
Context
|
|
```Haskell
|
|
functionName
|
|
:: ( C1
|
|
, C2
|
|
, C3
|
|
, C4
|
|
, C5
|
|
)
|
|
=> a
|
|
-> b
|
|
-> c
|
|
-> d
|
|
-> (a, b, c, d)
|
|
```
|
|
|
|
Arguments
|
|
```Haskell
|
|
functionName
|
|
:: (C1, C2, C3, C4, C5)
|
|
=> a
|
|
-> b
|
|
-> (forall a.
|
|
(C6, C7)
|
|
=> LongDataTypeName
|
|
-> a
|
|
-> AnotherLongDataTypeName
|
|
-> b
|
|
-> c
|
|
)
|
|
-> (c -> d)
|
|
-> (a, b, c, d)
|
|
```
|
|
|
|
```Haskell
|
|
functionName
|
|
:: (C1, C2, C3, C4, C5)
|
|
=> a
|
|
-> b
|
|
-> ( LongDataTypeName
|
|
AnotherLongDataTypeName
|
|
AnotherLongDataTypeName2
|
|
AnotherLongDataTypeName3
|
|
-> a
|
|
-> AnotherLongDataTypeName4
|
|
-> b
|
|
-> c
|
|
)
|
|
-> (c -> d)
|
|
-> (a, b, c, d)
|
|
```
|
|
|
|
### Expressions
|
|
|
|
```Haskell
|
|
f x y z =
|
|
if x then longFunctionName y else anotherLongFunctionName z
|
|
```
|
|
|
|
A lambda
|
|
```Haskell
|
|
f =
|
|
\(LongPattern x) ->
|
|
longFunctionName x
|
|
```
|
|
|
|
Multiple lambdas
|
|
```Haskell
|
|
f =
|
|
\(LongPattern x) ->
|
|
\(LongPattern2 y) ->
|
|
longFunctionName x
|
|
```
|
|
|
|
Lambda arguments
|
|
```Haskell
|
|
f xs =
|
|
forM xs $
|
|
\( LongPattern x
|
|
, LongPattern2 y
|
|
) ->
|
|
longFunctionName x
|
|
```
|
|
|
|
There is a do block. Note the change of indentation in the
|
|
body of `forM`.
|
|
```Haskell
|
|
f xs = do
|
|
forM xs $
|
|
\( LongPattern x
|
|
, LongPattern2 y
|
|
) ->
|
|
longFunctionName x
|
|
```
|
|
|
|
`if` expression
|
|
```Haskell
|
|
f x y z =
|
|
if x then
|
|
longFunctionName x y
|
|
else
|
|
anotherLongFunctionName x z
|
|
```
|
|
|
|
`if` expression with monadic blocks
|
|
```Haskell
|
|
f x y z =
|
|
if x then do
|
|
longFunctionName1 x y
|
|
longFunctionName2 x y
|
|
else do
|
|
anotherLongFunctionName1 x z
|
|
anotherLongFunctionName2 x z
|
|
```
|
|
|
|
Monadic blocks
|
|
```Haskell
|
|
f x y z = do
|
|
functionName1 x y
|
|
functionName2 x z
|
|
```
|
|
|
|
`case` expression
|
|
```Haskell
|
|
f x y z = case
|
|
Just w -> functionName x y w
|
|
Nothing -> functionName x y z
|
|
```
|
|
|
|
Branches of `case` expression
|
|
```Haskell
|
|
f x y z = case
|
|
Just w ->
|
|
longFunctionName x y w
|
|
Nothing ->
|
|
anotherLongFunctionName x y z
|
|
```
|
|
|
|
A list of arguments
|
|
```Haskell
|
|
f
|
|
(LongPattern x)
|
|
(AnotherLongPattern y)
|
|
=
|
|
functionName x y
|
|
```
|
|
|
|
Guards
|
|
```Haskell
|
|
f x y
|
|
| x > y = True
|
|
| otherwise = False
|
|
```
|
|
|
|
The right-hand side of guards
|
|
```Haskell
|
|
f x y
|
|
| x > y =
|
|
longFunctionName y
|
|
| otherwise =
|
|
anotherLongFunctionName x
|
|
```
|
|
|
|
Long guards
|
|
```Haskell
|
|
function x y z w y
|
|
| x > y
|
|
, y > z
|
|
, z > w
|
|
, w > z
|
|
=
|
|
longFunctionName y
|
|
| otherwise =
|
|
anotherLongFunctionName x
|
|
```
|
|
|
|
### Data type declarations
|
|
|
|
Declaration
|
|
```Haskell
|
|
data A
|
|
= B
|
|
| C
|
|
| D
|
|
| E
|
|
| F
|
|
| G
|
|
```
|
|
|
|
TODO: GADTs, record syntax, type families
|
|
|
|
### Comments
|
|
|
|
```Haskell
|
|
{- When a comment is not preceded with elements on the same line,
|
|
they are indented as the elements in the enclosing AST node or
|
|
braces/parenthesis/brackets.
|
|
If it is between AST nodes, it is indented as the following
|
|
node.
|
|
If the end-of-file follows, then indent to column 0.
|
|
-}
|
|
|
|
f = g {- When there are preceding elements, keep single-line comments in the same line. -}
|
|
|
|
h = g
|
|
{- Multi-line comments can't be kept on the same line as @h = g@.
|
|
Otherwise, changing h or g would change the indentation of all
|
|
the comment lines.
|
|
-}
|
|
|
|
data R = R
|
|
{- This comment always follows the R constructor -}
|
|
{ f1 :: T1
|
|
{- A comment not preceded by other elements -}
|
|
{- Another comment -}
|
|
, f2 :: T2
|
|
, f3 :: T3
|
|
}
|
|
```
|
|
|
|
```Haskell
|
|
{- a comment line -}
|
|
f = h
|
|
where
|
|
h = g
|
|
-- indented the same as g
|
|
g = False
|
|
```
|
|
|
|
This example
|
|
```Haskell
|
|
data R = R {- This comment always follows the R constructor -}
|
|
{ f1 :: T1, {- An inner comment -} {- Another inner comment -} f2 :: T2, f3 :: T3}
|
|
```
|
|
is reformatted to
|
|
```Haskell
|
|
data R = R
|
|
{- This comment always follows the R constructor -}
|
|
{ f1 :: T1 {- An inner comment -} {- Another inner comment -}
|
|
, f2 :: T2
|
|
, f3 :: T3
|
|
}
|
|
```
|