Programming-Guidelines.txt revision 7e0943e4893be7d7d87059ef6995b59aa1d4e96b
1822350db15b089f094a6dbd2469842ab42c1d87Kay SieversProgramming guidelines shall help to make the code of a project better
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sieversreadable and maintainable by the varying number of contributors.
1822350db15b089f094a6dbd2469842ab42c1d87Kay SieversIt takes some programming experience to develop something like a
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sieverspersonal "coding style" and guidelines only serve as rough shape for
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sieverscode. Guidelines should be followed by all members working on the
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sieversproject even if they prefer (or are already used to) different
5430f7f2bc7330f3088b894166bf3524a067e3d8Lennart PoetteringThese guidelines have been originally set up for the hets-project
5430f7f2bc7330f3088b894166bf3524a067e3d8Lennart Poettering[http://www.informatik.uni-bremen.de/cofi/hets/ hets-project] and are
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sieversnow put on the [http://haskell.org/haskellwiki/ HaskellWiki] gradually
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sieversintegrating parts of [http://haskell.org/hawiki the old hawiki]
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sieversentries [http://haskell.org/haskellwiki/Things_to_avoid ThingsToAvoid] and
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers[http://haskell.org/hawiki/HaskellStyle HaskellStyle] (hopefully not
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievershurting someone's copyrights). The other related entry
5430f7f2bc7330f3088b894166bf3524a067e3d8Lennart Poettering[http://haskell.org/hawiki/TipsAndTricks TipsAndTricks] treats more
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sieversspecific points that are left out here,
1822350db15b089f094a6dbd2469842ab42c1d87Kay SieversSurely some style choices are a bit arbitrary (or "religious") and
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sieverstoo restrictive with respect to language extensions. Nevertheless I hope
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sieversto keep up these guidelines (at least as a basis) for our project
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sieversin order to avoid maintaining diverging guidelines. Of course I want
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sieversto supply - partly tool-dependent - reasons for certain decisions and
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sieversalso show alternatives by possibly bad examples. At the time of
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sieverswriting I use ghc-6.4.1, haddock-0.7 and (GNU-) emacs with the latest
3ffd4af22052963e7a29431721ee204e634bea75Lennart Poettering[http://www.haskell.org/haskell-mode/ haskell mode].
3ffd4af22052963e7a29431721ee204e634bea75Lennart PoetteringThe following quote and links are taken from
3ffd4af22052963e7a29431721ee204e634bea75Lennart Poettering[http://haskell.org/hawiki/HaskellStyle the old general comments]:
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay SieversWe all have our own ideas about good Haskell style. There's More Than
b5efdb8af40ea759a1ea584c1bc44ecc81dd00ceLennart PoetteringOne Way To Do It. But some ways are better than others.
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay SieversSome comments from the GHC team about their internal coding
bb15fafe9cd815fe5bf9eae84c08aead2eb98fd7Lennart Poetteringstandards can be found at
bb15fafe9cd815fe5bf9eae84c08aead2eb98fd7Lennart Poetteringhttp://hackage.haskell.org/trac/ghc/wiki/WorkingConventions
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay SieversAlso http://research.microsoft.com/~simonpj/papers/haskell-retrospective/
bb15fafe9cd815fe5bf9eae84c08aead2eb98fd7Lennart Poetteringcontains some brief comments on syntax and style,
bb15fafe9cd815fe5bf9eae84c08aead2eb98fd7Lennart PoetteringWhat now follows are descriptions of program documentation, file
7568345034f2890af745747783c5abfbf6eccf0fLennart Poetteringformat, naming conventions and good programming practice (adapted form
bb15fafe9cd815fe5bf9eae84c08aead2eb98fd7Lennart PoetteringMatt's C/C++ Programming Guidelines and the Linux kernel coding
ee104e11e303499a637c5cd8157bd12ad5cc116dLennart Poettering=== Documentation ===
1822350db15b089f094a6dbd2469842ab42c1d87Kay SieversComments are to be written in application terms (i.e. user's point of
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sieversview). Don't use technical terms - that's what the code is for!
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay SieversComments should be written using correct spelling and grammar in complete
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sieverssentences with punctation (in English only).
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sievers"Generally, you want your comments to tell WHAT your code does, not HOW.
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay SieversAlso, try to avoid putting comments inside a function body: if the
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sieversfunction is so complex that you need to separately comment parts of it,
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sieversyou should probably" (... decompose it)
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay SieversPut a haddock comment on top of every exported function and data type!
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay SieversMake sure haddock accepts these comments.
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sievers=== File Format ===
1822350db15b089f094a6dbd2469842ab42c1d87Kay SieversAll Haskell source files start with a haddock header of the form:
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay SieversModule : <File name or $Header$ to be replaced automatically>
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay SieversDescription : <optional short text displayed on contents page>
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay SieversCopyright : (c) <Authors or Affiliations>
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay SieversLicense : <license>
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay SieversMaintainer : <email>
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay SieversStability : unstable | experimental | provisional | stable | frozen
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay SieversPortability : portable | non-portable (<reason>)
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sievers<module description starting at first column>
1822350db15b089f094a6dbd2469842ab42c1d87Kay SieversA possible compiler pragma (like {-# LANGUAGE CPP #-}) may precede
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sieversthis header. The following hierarchical module name must of course
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sieversmatch the file name.
1822350db15b089f094a6dbd2469842ab42c1d87Kay SieversMake sure that the description is changed to meet the module (if the
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sieversheader was copied from elsewhere). Insert your email address as maintainer.
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay SieversTry to write portable (Haskell98) code. If you use i.e. multi-parameter
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sieverstype classes and functional dependencies the code becomes
d200735e13c52dcfe36c0e066f9f6c2fbfb85a9cMichal Schmidt"non-portable (MPTC with FD)".
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay SieversThe \$Header\$ entry will be automatically expanded.
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay SieversLines should not be longer than 80 (preferably 75)
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sieverscharacters to avoid wrapped lines (for casual readers)!
af76d302c1e26f916494202f1b3663f15710bdcdZbigniew Jędrzejewski-SzmekDon't leave trailing white space in your code in every line.
1822350db15b089f094a6dbd2469842ab42c1d87Kay SieversExpand all your tabs to spaces to avoid the danger of wrongly expanding
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sieversthem (or a different display of tabs versus eight spaces). Possibly put
81fd105a5f9762fa2f2e42bc949876e32b3a126fZbigniew Jędrzejewski-Szmeksomething like the following in your ~/.emacs file.
81fd105a5f9762fa2f2e42bc949876e32b3a126fZbigniew Jędrzejewski-Szmek (custom-set-variables '(indent-tabs-mode nil))
81fd105a5f9762fa2f2e42bc949876e32b3a126fZbigniew Jędrzejewski-SzmekThe last character in your file should be a newline! Under solaris
81fd105a5f9762fa2f2e42bc949876e32b3a126fZbigniew Jędrzejewski-Szmekyou'll get a warning if this is not the case and sometimes last lines
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sieverswithout newlines are ignored (i.e. "#endif" without newline). Emacs
87699fe313cf8919917f2ea422b8d10b3ae3b244Daniel Mackusually asks for a final newline.
87699fe313cf8919917f2ea422b8d10b3ae3b244Daniel MackYou may use http://hackage.haskell.org/package/scan to check your file format.
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay SieversThe whole module should not be too long (about 400 lines)
87699fe313cf8919917f2ea422b8d10b3ae3b244Daniel Mack=== Naming Conventions ===
1822350db15b089f094a6dbd2469842ab42c1d87Kay SieversIn Haskell types start with capital and functions with lowercase
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sieversletters, so only avoid infix identifiers! Defining symbolic infix
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sieversidentifiers should be left to library writers only.
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sievers(The infix identifier "\\" at the end of a line causes cpp preprocessor
1822350db15b089f094a6dbd2469842ab42c1d87Kay SieversNames (especially global ones) should be descriptive and if you need
36e34057a202d389263e98030fbd775b28b28af6Stef Walterlong names write them as mixed case words (aka camelCase). (but "tmp"
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sieversis to be preferred over "thisVariableIsATemporaryCounter")
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay SieversAlso in the standard libraries, function names with multiple words are
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sieverswritten using the camelCase convention. Similarly, type, typeclass and
36e34057a202d389263e98030fbd775b28b28af6Stef Walterconstructor names are written using the StudlyCaps convention.
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay SieversSome parts of our code use underlines (without unnecessary uppercase
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sieversletters) for long identifiers to better reflect names given with
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievershyphens in the requirement documentation. Also such names should be
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sieverstransliterated to camlCase identifiers possibly adding a (consistent)
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sieverssuffix or prefix to avoid conflicts with keywords. However, instead of
af76d302c1e26f916494202f1b3663f15710bdcdZbigniew Jędrzejewski-Szmeka recurring prefix or suffix you may consider to use qualified imports
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sievers=== Good Programming Practice ===
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sievers"Functions should be short and sweet, and do just one thing. They should
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sieversfit on one or two screenfuls of text (the ISO/ANSI screen size is 80x24,
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sieversas we all know), and do one thing and do that well."
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay SieversMost haskell functions should be at most a few lines, only case
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sieversexpression over large data types (that should be avoided, too) may need
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sieverscorresponding space.
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay SieversThe code should be succinct (though not obfuscated), readable and easy to
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sieversmaintain (after unforeseeable changes). Don't exploit exotic language
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sieversfeatures without good reason.
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay SieversIt's not fixed how deep you indent (4 or 8 chars). You can break the
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sieversline after "do", "let", "where", and "case .. of". Make sure that
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sieversrenamings don't destroy your layout. (If you get to far to the right,
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sieversthe code is unreadable anyway and needs to be decomposed.)
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers case foo of Foo -> "Foo"
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers Bar -> "Bar"
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers case <longer expression> of
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers Foo -> "Foo"
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sievers Bar -> "Bar"
1822350db15b089f094a6dbd2469842ab42c1d87Kay SieversAvoid the notation with braces and semicolons since the layout rule
af76d302c1e26f916494202f1b3663f15710bdcdZbigniew Jędrzejewski-Szmekforces you to properly align your alternatives.
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay SieversRespect compiler warnings. Supply type signatures, avoid shadowing and
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sieversunused variables. Particularly avoid non-exhaustive and
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sieversoverlapping patterns. Missing unreachable cases can be filled in using
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers"error" with a fixed string "<ModuleName>.<function>" to indicate the
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sieverserror position (in case the impossible should happen). Don't invest
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sieverstime to "show" the offending value, only do this temporarily when
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sieversdebugging the code.
1822350db15b089f094a6dbd2469842ab42c1d87Kay SieversDon't leave unused or commented-out code in your files! Readers don't
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sieversknow what to think of it.
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers==== Case expressions ====
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay SieversPrefer case expressions over pattern binding declarations with
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sieversmultiple equations.
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay SieversNot always nice:
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sievers longFunctionName (Foo: _ : _) = e1
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers longFunctionName (Bar: _) = e2
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers longFunctionName arg = case arg of
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers Foo : _ : _ -> e1
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers Bar : _ -> e2
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers _ -> error "ProgrammingGuidelines.longFunctionName"
28efac0d37ceb5093a804da6a00c620034c5484fZbigniew Jędrzejewski-Szmekhttp://research.microsoft.com/~simonpj/papers/haskell-retrospective/
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sieversthe first example is said to be written in [[declaration style]]. The
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sieversequations look like written for a rewrite system (although their order
b2fadec6048adb3596f2633cb7fe7a49f5937a18Zbigniew Jędrzejewski-Szmekmatters of course).
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay SieversBut this declarative style is only nice for toy examples and annoying
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sieversif functions are renamed or if the number of arguments changes.
f687b2738229570453c9412add6b9c4f99c9c004Lennart PoetteringThe other extreme (according to SPJ) is [[expression style]]:
f687b2738229570453c9412add6b9c4f99c9c004Lennart Poettering longFunctionName = \ arg -> ...
1822350db15b089f094a6dbd2469842ab42c1d87Kay SieversWe don't propose this style either. We propose to use as much pattern
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sieversmatching (including as-patterns) on a single left-hand-side as appropriate.
1822350db15b089f094a6dbd2469842ab42c1d87Kay SieversHowever, the expression style with a lambda term may come in handy, when
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sieverssetting record fields of a function type.
1822350db15b089f094a6dbd2469842ab42c1d87Kay SieversWe avoid lambda expressions if this is easily possibly using the
1822350db15b089f094a6dbd2469842ab42c1d87Kay SieversPrelude functions const, flip, curry, uncurry or section notation or
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sieversplain partial application. We do not indroduce an auxiliary function only to
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sieversavoid the lambda, though.
8adaf7bd23baa6e2cd99e9e88e55d0f5f5db29a2Richard Maw==== Partial functions ====
b2fadec6048adb3596f2633cb7fe7a49f5937a18Zbigniew Jędrzejewski-SzmekFor partial functions do document their preconditions (if not obvious)
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sieversand make sure that partial functions are only called when
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sieverspreconditions are obviously fulfilled (i.e. by a case statement or a
87699fe313cf8919917f2ea422b8d10b3ae3b244Daniel Mackprevious test). Particularly the call of "head" should be used with
87699fe313cf8919917f2ea422b8d10b3ae3b244Daniel Mackcare or (even better) be made obsolete by a case statement.
87699fe313cf8919917f2ea422b8d10b3ae3b244Daniel MackUsually a case statement (and the import of isJust and fromJust from
87699fe313cf8919917f2ea422b8d10b3ae3b244Daniel MackData.[[Maybe]]) can be avoided by using the "maybe" function:
87699fe313cf8919917f2ea422b8d10b3ae3b244Daniel Mack maybe (error "<ModuleName>.<function>") id $ Map.lookup key map
87699fe313cf8919917f2ea422b8d10b3ae3b244Daniel MackGenerally we require you to be more explicit about failure
87699fe313cf8919917f2ea422b8d10b3ae3b244Daniel Mackcases. Surely a missing (or an irrefutable) pattern would precisely
87699fe313cf8919917f2ea422b8d10b3ae3b244Daniel Mackreport the position of a runtime error, but these are not so obvious
87699fe313cf8919917f2ea422b8d10b3ae3b244Daniel Mackwhen reading the code.
87699fe313cf8919917f2ea422b8d10b3ae3b244Daniel Mack==== Let or where expressions ====
1822350db15b089f094a6dbd2469842ab42c1d87Kay SieversDo avoid mixing and nesting "let" and "where". (I prefer the
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sieversexpression-stylistic "let".) Use auxiliary top-level functions that
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sieversyou do not export. Export lists also support the detection of unused
8adaf7bd23baa6e2cd99e9e88e55d0f5f5db29a2Richard Maw==== Code reuse ====
1822350db15b089f094a6dbd2469842ab42c1d87Kay SieversIf you notice that you're doing the same task again, try to generalize
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sieversit in order to avoid duplicate code. It is frustrating to change the
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sieverssame error in several places.
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers==== Application notation ====
1822350db15b089f094a6dbd2469842ab42c1d87Kay SieversMany parentheses can be eliminated using the infix application operator "$"
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sieverswith lowest priority. Try at least to avoid unnecessary parentheses in
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sieversstandard infix expression.
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers f x : g x ++ h x
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers a == 1 && b == 1 || a == 0 && b == 0
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay SieversRather than putting a large final argument in parentheses (with a
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sieversdistant closing one) consider using "$" instead.
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers"f (g x)" becomes "f $ g x" and consecutive applications
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers"f (g (h x))" can be written as "f $ g $ h x" or "f . g $ h x".
1822350db15b089f094a6dbd2469842ab42c1d87Kay SieversA function definition like
502f961425f9dea1a85239766a3189695194da63Zbigniew Jędrzejewski-Szmek"f x = g $ h x" can be abbreviated to "f = g . h".
28efac0d37ceb5093a804da6a00c620034c5484fZbigniew Jędrzejewski-SzmekNote that the final argument may even be an infix- or case expression:
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart Poettering filter (const True) . map id $ case l of ...
1822350db15b089f094a6dbd2469842ab42c1d87Kay SieversHowever, be aware that $-terms cannot be composed further in infix
1822350db15b089f094a6dbd2469842ab42c1d87Kay SieversBut the scope of an expression is also limited by the layout rule, so
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sieversit is usually safe to use "$" on right hand sides.
1822350db15b089f094a6dbd2469842ab42c1d87Kay SieversOf course "$" can not be used in types. GHC has also some primitive
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sieversfunctions involving the kind "#" that cannot be applied using "$".
1822350db15b089f094a6dbd2469842ab42c1d87Kay SieversLast warning: always leave spaces around "$" (and other mixfix
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sieversoperators) since a clash with template haskell is possible.
28efac0d37ceb5093a804da6a00c620034c5484fZbigniew Jędrzejewski-Szmek(Also write "\ t" instead of "\t" in lambda expressions)
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers==== List Comprehensions ====
1822350db15b089f094a6dbd2469842ab42c1d87Kay SieversUse these only when "short and sweet". Prefer map, filter, and foldr!
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers [toUpper c | c <- s]
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers [toUpper c | s <- strings, c <- s]
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay SieversHere it takes some time for the reader to find out which value depends
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sieverson what other value and it is not so clear how many times the interim
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sieversvalues s and c are used. In contrast to that the following can't be clearer:
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sievers map toUpper (concat strings)
1822350db15b089f094a6dbd2469842ab42c1d87Kay SieversWhen using higher order functions you can switch easier to data
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sieversstructures different from list. Compare:
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sievers map (1+) list
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sievers==== Types ====
1822350db15b089f094a6dbd2469842ab42c1d87Kay SieversPrefer proper data types over type synonyms or tuples even if you have
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sieversto do more constructing and unpacking. This will make it easier to
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sieverssupply class instances later on. Don't put class constraints on
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sieversa data type, constraints belong only to the functions that manipulate
1822350db15b089f094a6dbd2469842ab42c1d87Kay SieversUsing type synonyms consistently is difficult over a longer time,
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sieversbecause this is not checked by the compiler. (The types shown by
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sieversthe compiler may be unpredictable: i.e. FilePath, String or [Char])
1822350db15b089f094a6dbd2469842ab42c1d87Kay SieversTake care if your data type has many variants (unless it is an
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sieversenumeration type.) Don't repeat common parts in every variant since
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sieversthis will cause code duplication.
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay SieversBad (to handle arguments in sync):
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sievers data Mode f p = Box f p | Diamond f p
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay SieversGood (to handle arguments only once):
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sievers data BoxOrDiamond = Box | Diamond
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers data Mode f p = Mode BoxOrDiamond f p
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay SieversConsider (bad):
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sievers data Tuple a b = Tuple a b | Undefined
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sieversversus (better):
c49b30a23583ff39daaa26696bcab478d2fee0bbLennart Poettering data Tuple a b = Tuple a b
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sievers Maybe (Tuple a b)
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers(or another monad) whenever an undefined result needs to be propagated
98fce79dea6f653dead88638fc17a27280b1f250Zbigniew Jędrzejewski-Szmek==== Records ====
717603e391b52983ca1fd218e7333a1b9dfc5c05Lennart PoetteringFor (large) records avoid the use of the constructor directly and
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sieversremember that the order and number of fields may change.
1822350db15b089f094a6dbd2469842ab42c1d87Kay SieversTake care with (the rare case of) depend polymorphic fields:
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers data Fields a = VariantWithTwo
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers { field1 :: a
1822350db15b089f094a6dbd2469842ab42c1d87Kay SieversThe type of a value v can not be changed by only setting field1:
98fce79dea6f653dead88638fc17a27280b1f250Zbigniew Jędrzejewski-Szmek v { field1 = f }
1822350db15b089f094a6dbd2469842ab42c1d87Kay SieversBetter construct a new value:
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers VariantWithTwo { field1 = f } -- leaving field2 undefined
1822350db15b089f094a6dbd2469842ab42c1d87Kay SieversOr use a polymorphic element that is instantiated by updating:
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers empty = VariantWithTwo { field1 = [], field2 = [] }
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers empty { field1 = [f] }
1822350db15b089f094a6dbd2469842ab42c1d87Kay SieversSeveral variants with identical fields may avoid some code duplication
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sieverswhen selecting and updating, though possibly not in a few
28efac0d37ceb5093a804da6a00c620034c5484fZbigniew Jędrzejewski-Szmekdepended polymorphic cases.
1822350db15b089f094a6dbd2469842ab42c1d87Kay SieversHowever, I doubt if the following is a really good alternative to the
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sieversabove data Mode with data BoxOrDiamond.
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers data Mode f p =
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers Box { formula :: f, positions :: p }
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers | Diamond { formula :: f, positions :: p }
1822350db15b089f094a6dbd2469842ab42c1d87Kay SieversTry to strictly separate IO, Monad and pure (without do) function
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sieversprogramming (possibly via separate modules).
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers x <- return y
e78af5ffe53a0d24854d721d1166a60f8ed0dfb6Zbigniew Jędrzejewski-SzmekDon't use Prelude.interact and make sure your program does not depend
98fce79dea6f653dead88638fc17a27280b1f250Zbigniew Jędrzejewski-Szmekon the (not always obvious) order of evaluation. I.e. don't read and
98fce79dea6f653dead88638fc17a27280b1f250Zbigniew Jędrzejewski-Szmekwrite to the same file:
1822350db15b089f094a6dbd2469842ab42c1d87Kay SieversThis will fail:
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sievers do s <- readFile f
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sievers writeFile f $ 'a' : s
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sieversbecause of lazy IO! (Writing is starting before reading is finished.)
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers==== Trace ====
1822350db15b089f094a6dbd2469842ab42c1d87Kay SieversTracing is for debugging purposes only and should not be used as
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sieversfeedback for the user. Clean code is not cluttered by trace calls.
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers==== Imports ====
1822350db15b089f094a6dbd2469842ab42c1d87Kay SieversStandard library modules like Char. List, Maybe, Monad, etc should be
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sieversimported by their hierarchical module name, i.e. the base package (so
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sieversthat haddock finds them):
1822350db15b089f094a6dbd2469842ab42c1d87Kay SieversThe libraries for Set and Map are to be imported qualified:
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sievers import qualified Data.Set as Set
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sievers import qualified Data.Map as Map
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sievers==== Glasgow extensions and Classes ====
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sievers[[Use of language extensions|Stay away from extensions]] as long as possible. Also use classes with
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sieverscare because soon the desire for overlapping instances (like for lists
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sieversand strings) may arise. Then you may want MPTC (multi-parameter type
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sieversclasses), functional dependencies (FD), undecidable and possibly incoherent
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sieversinstances and then you are "in the wild" (according to SPJ).
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers=== Style in other languages ===
dacd6cee76a08331b8c8616c5f30f70ee49aa2f9Lennart Poettering* [http://www.cs.caltech.edu/~cs20/a/style.html OCaml style]
dacd6cee76a08331b8c8616c5f30f70ee49aa2f9Lennart Poettering=== Final remarks ===
dacd6cee76a08331b8c8616c5f30f70ee49aa2f9Lennart PoetteringDespite guidelines, writing "correct code" (without formal proof
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sieverssupport yet) still remains the major challenge. As motivation to
dacd6cee76a08331b8c8616c5f30f70ee49aa2f9Lennart Poetteringfollow these guidelines consider the points that are from the "C++
dacd6cee76a08331b8c8616c5f30f70ee49aa2f9Lennart PoetteringCoding Standard", where I replaced "C++" with "Haskell".
dacd6cee76a08331b8c8616c5f30f70ee49aa2f9Lennart Poettering* programmers can go into any code and figure out what's going on
dacd6cee76a08331b8c8616c5f30f70ee49aa2f9Lennart Poettering* new people can get up to speed quickly
dacd6cee76a08331b8c8616c5f30f70ee49aa2f9Lennart Poettering* people new to Haskell are spared the need to develop a personal style and defend it to the death
dacd6cee76a08331b8c8616c5f30f70ee49aa2f9Lennart Poettering* people new to Haskell are spared making the same mistakes over and over again
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers* people make fewer mistakes in consistent environments
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sievers* programmers have a common enemy :-)
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers* the standard is usually stupid because it was made by someone who doesn't understand Haskell
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers* the standard is usually stupid because it's not what I do
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers* standards reduce creativity
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sievers* standards are unnecessary as long as people are consistent
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sievers* standards enforce too much structure
8d451309667578d3a03cdfc91d6e339fb9fe64a7Kay Sievers* people ignore standards anyway
1822350db15b089f094a6dbd2469842ab42c1d87Kay Sievers[[Category:Style]]