Programming-Guidelines.txt revision 3db8b71dd1ccc662325b96a5ee8f351ace0293ba
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis TsogiasProgramming guidelines shall help to make the code of a project better
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogiasreadable and maintainable by the varying number of contributors.
e21e5f0fa66bf80e14cfd3f571e09b3952e46ad9Alexis Tsogias
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis TsogiasIt takes some programming experience to develop something like a
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogiaspersonal "coding style" (see
fc09e0a6af734edbd944dd8082bb51985c233b43Alexis Tsogiashttp://www.haskell.org/hawiki/HaskellStyle) and guidelines only serve
fc09e0a6af734edbd944dd8082bb51985c233b43Alexis Tsogiasas rough shape for code. Guidelines should be followed by all members
fc09e0a6af734edbd944dd8082bb51985c233b43Alexis Tsogiasworking on the project even if they prefer (or are already used to)
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogiasdifferent guidelines.
e21e5f0fa66bf80e14cfd3f571e09b3952e46ad9Alexis Tsogias
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis TsogiasIn the following I will describe documentation, file format, naming
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogiasconventions and good programming practice (adapted form Matt's C/C++
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis TsogiasProgramming Guidelines and the Linux kernel coding style).
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias---------------------------------------------------------------------------
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis TsogiasDocumentation:
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias---------------------------------------------------------------------------
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias
1e622ddf5a057555db1924ddc88475c695c6f7f2Alexis TsogiasComments are to be written in application terms (i.e. user's point of
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogiasview). Don't use technical terms - that's what the code is for!
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis TsogiasComments should be written using correct spelling and grammar in complete
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogiassentences with punctation (in English only).
1e622ddf5a057555db1924ddc88475c695c6f7f2Alexis Tsogias
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias"Generally, you want your comments to tell WHAT your code does, not HOW.
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis TsogiasAlso, try to avoid putting comments inside a function body: if the
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogiasfunction is so complex that you need to separately comment parts of it,
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogiasyou should probably" (... decompose it)
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis TsogiasPut a haddock comment on top of every exported function and data type!
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis TsogiasMake sure haddock accepts these comments.
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias---------------------------------------------------------------------------
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis TsogiasFile Format:
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias---------------------------------------------------------------------------
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis TsogiasAll Haskell source files start with a haddock header of the form:
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias{- |
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis TsogiasModule : <File name, i.e. generated by \$Header\$>
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis TsogiasDescription : <Short text displayed on contents page>
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis TsogiasCopyright : (c) <You> and <Your affiliation>
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis TsogiasLicense : similar to LGPL, see LICENSE.txt
e21e5f0fa66bf80e14cfd3f571e09b3952e46ad9Alexis Tsogias
e21e5f0fa66bf80e14cfd3f571e09b3952e46ad9Alexis TsogiasMaintainer : maeder@tzi.de
e21e5f0fa66bf80e14cfd3f571e09b3952e46ad9Alexis TsogiasStability : provisional
e21e5f0fa66bf80e14cfd3f571e09b3952e46ad9Alexis TsogiasPortability : portable
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias<module description starting at first column>
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias-}
e21e5f0fa66bf80e14cfd3f571e09b3952e46ad9Alexis Tsogias
e21e5f0fa66bf80e14cfd3f571e09b3952e46ad9Alexis Tsogias
e21e5f0fa66bf80e14cfd3f571e09b3952e46ad9Alexis TsogiasA possible compiler pragma (like {-# OPTIONS -cpp #-}) may precede
e21e5f0fa66bf80e14cfd3f571e09b3952e46ad9Alexis Tsogiasthis header. The following hierarchical module name must of course
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogiasmatch the file name.
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis TsogiasMake sure that the description is changed to meet the module (if the
e21e5f0fa66bf80e14cfd3f571e09b3952e46ad9Alexis Tsogiasheader was copied from elsewhere). Insert your email address as maintainer.
e21e5f0fa66bf80e14cfd3f571e09b3952e46ad9Alexis Tsogias
e21e5f0fa66bf80e14cfd3f571e09b3952e46ad9Alexis TsogiasTry to write portable (Haskell98) code. If you (indirectly) import
e21e5f0fa66bf80e14cfd3f571e09b3952e46ad9Alexis Tsogiasa module that uses i.e. multi-parameter type classes and functional
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogiasdependencies the code becomes "non-portable (MPTC with FD)".
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias
e21e5f0fa66bf80e14cfd3f571e09b3952e46ad9Alexis TsogiasThe Dollar-Header-Dollar entry is automatically expanded by cvs (and will wrap
e21e5f0fa66bf80e14cfd3f571e09b3952e46ad9Alexis Tsogiasaround). All other lines should not be longer than 80 (preferably 75)
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogiascharacters to avoid wrapped lines (for casual readers)!
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias
e21e5f0fa66bf80e14cfd3f571e09b3952e46ad9Alexis TsogiasExpand all your tabs to spaces to avoid the danger of wrongly expanding
4cea468e955597a7069faba3f43f27e913f2b651Alexis Tsogiasthem (or a different display of tabs versus eight spaces). Possibly put
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogiassomething like the following in your ~/.emacs file.
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias (custom-set-variables '(indent-tabs-mode nil))
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis TsogiasThe last character in your file should be a newline! Under solaris
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogiasyou'll get a warning if this is not the case and sometimes last lines
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogiaswithout newlines are ignored (i.e. "#endif" without newline). Emacs
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogiasusually asks for a final newline.
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis TsogiasThe whole module should not be too long (about 400 lines)
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias---------------------------------------------------------------------------
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis TsogiasNaming Conventions:
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias---------------------------------------------------------------------------
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis TsogiasIn Haskell types start with capital and functions with lowercase
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogiasletters, so only avoid infix identifiers! Defining symbolic infix
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogiasidentifiers should be left to library writers only.
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias(The infix identifier "\\" at the end of a line causes cpp preprocessor
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogiasproblems.)
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis TsogiasNames (especially global ones) should be descriptive and if you need
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogiaslong names write them as mixed case words (aka camelCase). (but "tmp"
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogiasis to be preferred over "thisVariableIsATemporaryCounter")
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias---------------------------------------------------------------------------
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis TsogiasGood Programming Practice:
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias---------------------------------------------------------------------------
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias"Functions should be short and sweet, and do just one thing. They should
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogiasfit on one or two screenfuls of text (the ISO/ANSI screen size is 80x24,
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogiasas we all know), and do one thing and do that well."
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis TsogiasMost haskell functions should be at most a few lines, only case
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogiasexpression over large data types (that should be avoided, too) may need
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogiascorresponding space.
1e622ddf5a057555db1924ddc88475c695c6f7f2Alexis Tsogias
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis TsogiasThe code should be succinct, readable and easy to maintain (after
1e622ddf5a057555db1924ddc88475c695c6f7f2Alexis Tsogiasunforeseeable changes). Don't exploit exotic language features without
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogiasgood reason (like code-reuse).
4cea468e955597a7069faba3f43f27e913f2b651Alexis Tsogias
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis TsogiasIt's not fixed how deep you indent (4 or 8 chars). You can break the
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogiasline after "do", "let", "where", and "case .. of". Make sure that
1e622ddf5a057555db1924ddc88475c695c6f7f2Alexis Tsogiasrenamings don't destroy your layout. (If you get to far to the right,
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogiasthe code is unreadable anyway and needs to be decomposed.)
1e622ddf5a057555db1924ddc88475c695c6f7f2Alexis Tsogias
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis TsogiasBad:
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias case foo of Foo -> "Foo"
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias Bar -> "Bar"
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis TsogiasGood:
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias case <longer expression> of
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias Foo -> "Foo"
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias Bar -> "Bar"
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias
1e622ddf5a057555db1924ddc88475c695c6f7f2Alexis TsogiasAvoid the notation with braces and semicolons since the layout rule
e21e5f0fa66bf80e14cfd3f571e09b3952e46ad9Alexis Tsogiasforces you to properly align your alternatives.
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis TsogiasRespect compiler warnings. Supply type signatures, avoid shadowing and
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogiasunused variables. Particularly avoid non-exhaustive and
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogiasoverlapping patterns. Missing unreachable cases can be filled in using
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias"error" with a fixed string "<ModuleName>.<function>" to indicate the
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogiaserror position (in case the impossible should happen). Don't invest
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogiastime to "show" the offending value, only do this temporarily when
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogiasdebugging the code.
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis TsogiasDon't leave unused or commented-out code in your files! (Readers don't
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogiasknow what to think of it.)
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis TsogiasCase expressions
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias---------------------------------------------------------------------------
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis TsogiasPrefer case expressions over pattern binding declarations.
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis TsogiasNot always nice:
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias longFunctionName (Foo: _ : _) = e1
4cea468e955597a7069faba3f43f27e913f2b651Alexis Tsogias longFunctionName (Bar: _) = e2
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis TsogiasBetter (I think):
4cea468e955597a7069faba3f43f27e913f2b651Alexis Tsogias longFunctionName arg = case arg of
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias Foo : _ : _ -> e1
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias Bar : _ -> e2
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias _ -> error "ProgrammingGuidelines.longFunctionName"
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis TsogiasFor partial functions document their preconditions (if not obvious)
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogiasand make sure that partial functions are only called when
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogiaspreconditions are obviously fulfilled (i.e. by a case statement or a
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogiasprevious test). Particularly the call of "head" should be used with
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogiascare or (even better) be made obsolete by a case statement.
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis TsogiasUsually a case statement (and the import of isJust and fromJust from
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis TsogiasData.Maybe) can be avoided by using the "maybe" function:
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias maybe (error "<ModuleName>.<function>") id $ Map.lookup key map
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis TsogiasDo avoid mixing "let" and "where". (I prefer "let" and have auxiliary
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogiasfunction on the top-level that are not exported.) Export lists also
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogiassupport the detection of unused functions.
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis TsogiasIf you notice that you're doing the same task again, try to generalize
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogiasit in order to avoid duplicate code. It is frustrating to change the
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogiassame error in several places.
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias
4cea468e955597a7069faba3f43f27e913f2b651Alexis Tsogias
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis TsogiasApplication notation
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias---------------------------------------------------------------------------
4cea468e955597a7069faba3f43f27e913f2b651Alexis Tsogias
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis TsogiasMany parentheses can be eliminated using the infix application operator "$"
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogiaswith lowest priority. Try at least to avoid unnecessary parentheses in
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogiasstandard infix expression.
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias f x : g x ++ h x
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias a == 1 && b == 1 || a == 0 && b == 0
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis TsogiasRather than putting a large final argument in parentheses (with a
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogiasdistant closing one) consider using "$" instead.
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias"f (g x)" becomes "f $ g x" and consecutive applications
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias"f (g (h x))" can be written as "f $ g $ h x" or "f . g $ h x".
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis TsogiasA function definition like
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias"f x = g $ h x" can be abbreviated to "f = g . h".
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis TsogiasNote that the final argument may even be an infix- or case expression:
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias map id $ c : l
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias filter (const True) . map id $ case l of ...
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis TsogiasHowever, be aware that $-terms cannot be composed further in infix
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogiasexpressions.
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis TsogiasProbably wrong:
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias f $ x ++ g $ x
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis TsogiasBut the scope of an expression is also limited by the layout rule, so
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogiasit is usually save to use "$" on right hand sides.
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis TsogiasOk:
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias do y <- f $ l
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias ++
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias do y <- g $ l
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis TsogiasOf course "$" can not be used in types. GHC has also some primitive
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogiasfunctions involving the kind "#" that cannot be applied using "$".
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis TsogiasLast warning: always leave spaces around "$" (and other mixfix
4cea468e955597a7069faba3f43f27e913f2b651Alexis Tsogiasoperators) since a clash with template haskell is possible.
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias(Also write "\ t" instead of "\t" in lambda expressions)
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis TsogiasList Comprehensions
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias---------------------------------------------------------------------------
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis TsogiasUse these only when "short and sweet". (I prefer map, filter, and foldr.)
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis TsogiasTypes
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias---------------------------------------------------------------------------
4cea468e955597a7069faba3f43f27e913f2b651Alexis Tsogias
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis TsogiasPrefer proper data types over type synonyms or tuples even if you have
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogiasto do more constructing and unpacking. This will make it easier to
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogiassupply class instances later on. Don't put class constraints on
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogiasa data type, constraints belong only to the functions that manipulate
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogiasthe data.
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis TsogiasUsing type synonyms consistently is difficult over a longer time,
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogiasbecause this is not checked by the compiler. (The types shown by
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogiasthe compiler may be unpredictable: i.e. FilePath, String or [Char])
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis TsogiasTake care if your data type has many variants (unless it is an
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogiasenumeration type.) Don't repeat common parts in every variant since
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogiasthis will cause code duplication.
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis TsogiasBad (to handle arguments in sync):
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias data Mode f p = Box f p | Diamond f p
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis TsogiasGood (to handle arguments only once):
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias data BoxOrDiamond = Box | Diamond
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias data Mode f p = Mode BoxOrDiamond f p
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis TsogiasConsider (bad):
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias data Tupel a b = Tupel a b | Undefined
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogiasversus (better):
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias data Tupel a b = Tupel a b
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogiasand using:
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias Maybe (Tupel a b)
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias(or another monad) whenever an undefined result needs to be propagated
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias
4cea468e955597a7069faba3f43f27e913f2b651Alexis Tsogias
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis TsogiasRecords
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias---------------------------------------------------------------------------
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis TsogiasFor (large) records avoid the use of the constructor directly and
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogiasremember that the order and number of fields may change.
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis TsogiasTake care with (the rare case of) depend polymorphic fields:
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias data Fields a =
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias VariantWithTwo { field1 :: a
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias , field2 :: a }
4cea468e955597a7069faba3f43f27e913f2b651Alexis Tsogias
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis TsogiasThe type of a value v can not be changed by only setting field1:
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias v { field1 = f }
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis TsogiasBetter construct a new value:
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias VariantWithTwo { field1 = f } -- leaving field2 undefined
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis TsogiasOr use a polymorphic element that is instantiated by updating:
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias e = VariantWithTwo { field1 = [], field2 = [] }
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias e { field1 = [f] }
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis TsogiasSeveral variants with identical fields may avoid some code duplication
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogiaswhen selecting and updating, though possibly not in a few
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogiasdepended polymorphic cases.
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis TsogiasHowever, I doubt if the following is a really good alternative to the
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogiasabove data Mode with data BoxOrDiamond.
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias data Mode f p =
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias Box { formula :: f, positions :: p }
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias | Diamond { formula :: f, positions :: p }
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias
4cea468e955597a7069faba3f43f27e913f2b651Alexis TsogiasIO
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias---------------------------------------------------------------------------
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis TsogiasTry to strictly separate IO, Monad and pure (without do) function
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogiasprogramming (possibly via separate modules).
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis TsogiasBad:
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias x <- return y
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias ...
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis TsogiasGood:
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias let x = y
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias ...
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis TsogiasDon't use Prelude.interact and make sure your program does not depend
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogiason the (not always obvious) order of evaluation. I.e. don't read and
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogiaswrite to the same file:
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis TsogiasThis will fail:
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias do s <- readFile f
4cea468e955597a7069faba3f43f27e913f2b651Alexis Tsogias writeFile f $ 'a' : s
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogiasbecause of lazy IO! (Writing is starting before reading is finished.)
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis TsogiasTrace
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias---------------------------------------------------------------------------
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis TsogiasTracing is for debugging purposes only and should not be used as
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogiasfeedback for the user. Clean code is not cluttered by trace calls.
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis TsogiasImports
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias---------------------------------------------------------------------------
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis TsogiasStandard library modules like Char. List, Maybe, Monad, etc should be
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogiasimported by their hierarchical module name, i.e. the base package (so
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogiasthat haddock finds them):
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias import Data.List
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias import Control.Monad
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias import System.Environment
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis TsogiasThe libraries for Set and Map are to be imported qualified:
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias import qualified Data.Set as Set
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias import qualified Data.Map as Map
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis TsogiasGlasgow extensions and Classes
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias---------------------------------------------------------------------------
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis TsogiasStay away form extensions as long as possible. Also use classes with
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogiascare because soon the desire for overlapping instances (like for lists
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogiasand strings) may arise. Then you may want MPTC (multi-parameter type
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogiasclasses), functional dependencies (FD), undecidable and possibly incoherent
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogiasinstances and then you are "in the wild" (according to SPJ).
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias
1e622ddf5a057555db1924ddc88475c695c6f7f2Alexis Tsogias---------------------------------------------------------------------------
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis TsogiasFinal remarks:
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias---------------------------------------------------------------------------
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis TsogiasDespite guidelines, writing "correct code" (without formal proof
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogiassupport yet) still remains the major challenge. As motivation to
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogiasfollow these guidelines consider the points that are from the "C++
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis TsogiasCoding Standard", where I replaced "C++" with "Haskell".
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis TsogiasGood Points:
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias * programmers can go into any code and figure out what's going on
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias * new people can get up to speed quickly
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias * people new to Haskell are spared the need to develop a personal
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias style and defend it to the death
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias * people new to Haskell are spared making the same mistakes over
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias and over again
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias * people make fewer mistakes in consistent environments
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias * programmers have a common enemy :-)
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis TsogiasBad Points:
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias * the standard is usually stupid because it was made by someone
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias who doesn't understand Haskell
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias * the standard is usually stupid because it's not what I do
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias * standards reduce creativity
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias * standards are unnecessary as long as people are consistent
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias * standards enforce too much structure
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias * people ignore standards anyway
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis TsogiasSend comments to the "Maintainer" of this file
12f6880fc0909e8dc2bdebc5f299a6a8bfa8afa7Alexis Tsogias