This is a style guide for the language PureScript based on conventions used in its core libraries. A style guide is a set of conventions about how to write code for a project. It is easier to read a project's source code when it all has a consistent style. It is easier to contribute code to a project when there is no question as to how something should be written.
This style guide is licensed under the Creative Commons Zero license.
- 1. General formatting
- 1.1. Lines should be no longer than 80 characters
- 1.2. Do not use tabs
- 1.3. Indent with 2 spaces
- 1.4. Separate top-level definitions with a blank line
- 1.5. Surround operators with spaces
- 1.6. No space after a lambda
- 1.7. Lines must not have trailing spaces
- 1.8. Place each data type constructor on its own line
- 1.9. Don't align code
- 1.10. Place each element in a long array on its own line
- 1.11. Precede items in arrays, records, and import lists with commas
- 1.12. Format export lists like arrays
- 1.13. Doubly indent nested record or array literals
- 1.14. Prefer case expressions over equational pattern matching
- 2. Naming
- 3. Imports
- 4. Comments
- 5. Miscellaneous
Lines should not be longer than 80 characters.
Long lines hinder readability by making the eye scan too far across the screen or page. The column at which a line should be broken, however, is somewhat arbitrary and chosen for historical reasons.
URLs must not be split over multiple lines.
Source files must not contain tab characters; use spaces for indentation.
Indentation has syntactic meaning in PureScript, meaning that tabs must be interpreted as having a fixed width. However, editors can display tabs as any width. Thus, code that looks visually correct can be syntactically incorrect, especially if tabs have been mixed with spaces.
Code blocks should be indented with 2 spaces.
- Nested record and array literals should be indented 4 spaces.
let
bindings should be indented 4 spaces as well.
- There should be one blank line between top-level definitions.
- Do not place blank lines between type signatures and function definitions.
- One blank line may be placed between functions in type class instance declarations if the functions bodies are large.
Binary operators should be surrounded with a single space on either side.
Do not insert a space after the lambda symbol (backslash or \
).
Spaces must not appear at the end of any line of source code.
Data types with multiple constructors should have each constructor placed on its own line.
data Color
= Red
| Blue
| Green
Do not align code. Types within field declarations must not be aligned with one another; instead, they should be flush against the field name. Additionally, patterns and arrows in pattern match cases should not be aligned with one another.
Alignment makes it harder when updating code. For instance, if a new record field is added that is longer than the rest, the rest of the fields must be retabulated if the formatting is to be maintained. Doing so is even worse, however, because the resulting "diff" of the edit will indicate that several lines have changed, even though they were only reformatted.
data Rectangle = Rectangle
{ x :: Int
, y :: Int
, width :: Int
, height :: Int
}
Each successive element in a long array should be placed on its own line. If an array literal doesn't fit on a single line then it should be considered "long".
This makes for more readable diffs when having to alter a long array.
elements =
[ div
, h1
, p
, em
, span
, body
]
Each successive element in a long array, record, or import list should be preceded by a comma and a space.
PureScript does not support trailing commas, thus preceding an element with a comma makes it easier to add and remove items to the end of a list.
data Rgba = Rgba
{ red :: Int
, green :: Int
, blue :: Int
, alpha :: Int
}
Export lists should be formatted like regular arrays above (except with parentheses instead of square brackets.)
module Data.Array
( Array
, empty
, singleton
, sort
) where
When nesting record or array literals, the nested literal should be doubly indented (that is, indented 4 spaces.)
{ bounds:
{ x: 0
, y: 0
, width: 400
, height: 300
}
, color: Red
, children:
[ component1
, component2
, component3
]
}
Case expressions should be used instead of equational pattern matching.
If a function needs to be renamed when using a case expression in lieu of equational pattern maching, only a single edit needs to be made.
When matching multiple patterns, using equational pattern matching may be preferable.
catMaybes :: forall a. List (Maybe a) -> List a
catMaybes =
case _ of
Nil -> Nil
Nothing : xs -> catMaybes xs
Just x : xs -> x : catMaybes xs
Functions must be written in camel case.
add
fromMaybe
isJust
Syntactically, functions in PureScript must begin with a lower case letter.
Data types and constructors must be written in upper camel case.
Maybe
CommutativeRing
STRef
Syntactically, data types and constructors in PureScript must begin with a capital letter.
Effects should be written in all capital letters.
CONSOLE
EXCEPTION
RANDOM
Acronyms should be capitalized like any other word.
Names containing adjacent capitals that belong to separate words may hinder readability. Additionally, since function names must begin with a lower case letter, fully capitalizing all acronyms can be impossible.
Two letter acronyms should have both letters capitalized.
HtmlParser
rgbToHsl
ST
Module names should be in the singular.
- Use
Data.String
instead ofData.Strings
. - Use
Data.Function
instead ofData.Functions
.
Imports should be grouped in the following order:
- the
Prelude
- other third-party imports
- local application or library imports
The imports in each import group should be sorted alphabetically by module name.
Imported modules should either always be qualified or have explicit import lists.
This makes your code more robust against changes in imported modules. It also makes your code compile without warnings.
The Prelude
does not need to be qualified or have an implicit import list.
Markdown syntax should be used in documentation comments.
Every exported function and data type should have a documentation comment.
Point-free style should be avoided when it inhibits readability.
Code must not produce warnings when compiled.
Ignoring warnings that are false positives or benign can eventually make it difficult to identify warnings that are serious.