bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian MaederProgramming guidelines shall help to make the code of a project better
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maederreadable and maintainable by the varying number of contributors.
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian MaederIt takes some programming experience to develop something like a
d71c501e69da3973406558162ad439da2b3464d6Christian Maederpersonal "coding style" and guidelines only serve as rough shape for
d71c501e69da3973406558162ad439da2b3464d6Christian Maedercode. Guidelines should be followed by all members working on the
d71c501e69da3973406558162ad439da2b3464d6Christian Maederproject even if they prefer (or are already used to) different
d71c501e69da3973406558162ad439da2b3464d6Christian Maederguidelines.
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder
46bf8457679e3dd601af7e35cc0966642ba09794Christian MaederThese guidelines have been originally set up for the hets-project
46bf8457679e3dd601af7e35cc0966642ba09794Christian Maeder[http://www.informatik.uni-bremen.de/cofi/hets/ hets-project] and are
46bf8457679e3dd601af7e35cc0966642ba09794Christian Maedernow put on the [http://haskell.org/haskellwiki/ HaskellWiki] gradually
46bf8457679e3dd601af7e35cc0966642ba09794Christian Maederintegrating parts of [http://haskell.org/hawiki the old hawiki]
51db8ddc5236cf8f39d87bf6139cbc9aad146828Christian Maederentries [http://haskell.org/haskellwiki/Things_to_avoid ThingsToAvoid] and
46bf8457679e3dd601af7e35cc0966642ba09794Christian Maeder[http://haskell.org/hawiki/HaskellStyle HaskellStyle] (hopefully not
46bf8457679e3dd601af7e35cc0966642ba09794Christian Maederhurting someone's copyrights). The other related entry
46bf8457679e3dd601af7e35cc0966642ba09794Christian Maeder[http://haskell.org/hawiki/TipsAndTricks TipsAndTricks] treats more
46bf8457679e3dd601af7e35cc0966642ba09794Christian Maederspecific points that are left out here,
46bf8457679e3dd601af7e35cc0966642ba09794Christian Maeder
51db8ddc5236cf8f39d87bf6139cbc9aad146828Christian MaederSurely some style choices are a bit arbitrary (or "religious") and
46bf8457679e3dd601af7e35cc0966642ba09794Christian Maedertoo restrictive with respect to language extensions. Nevertheless I hope
46bf8457679e3dd601af7e35cc0966642ba09794Christian Maederto keep up these guidelines (at least as a basis) for our project
46bf8457679e3dd601af7e35cc0966642ba09794Christian Maederin order to avoid maintaining diverging guidelines. Of course I want
46bf8457679e3dd601af7e35cc0966642ba09794Christian Maederto supply - partly tool-dependent - reasons for certain decisions and
46bf8457679e3dd601af7e35cc0966642ba09794Christian Maederalso show alternatives by possibly bad examples. At the time of
46bf8457679e3dd601af7e35cc0966642ba09794Christian Maederwriting I use ghc-6.4.1, haddock-0.7 and (GNU-) emacs with the latest
46bf8457679e3dd601af7e35cc0966642ba09794Christian Maeder[http://www.haskell.org/haskell-mode/ haskell mode].
46bf8457679e3dd601af7e35cc0966642ba09794Christian Maeder
46bf8457679e3dd601af7e35cc0966642ba09794Christian MaederThe following quote and links are taken from
46bf8457679e3dd601af7e35cc0966642ba09794Christian Maeder[http://haskell.org/hawiki/HaskellStyle the old general comments]:
46bf8457679e3dd601af7e35cc0966642ba09794Christian Maeder
46bf8457679e3dd601af7e35cc0966642ba09794Christian MaederWe all have our own ideas about good Haskell style. There's More Than
46bf8457679e3dd601af7e35cc0966642ba09794Christian MaederOne Way To Do It. But some ways are better than others.
46bf8457679e3dd601af7e35cc0966642ba09794Christian Maeder
1d8011d1730fb370a499d59afb3f05be871436feChristian MaederSome comments from the GHC team about their internal coding
46bf8457679e3dd601af7e35cc0966642ba09794Christian Maederstandards can be found at
1d8011d1730fb370a499d59afb3f05be871436feChristian Maederhttp://hackage.haskell.org/trac/ghc/wiki/WorkingConventions
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder
46bf8457679e3dd601af7e35cc0966642ba09794Christian MaederAlso http://research.microsoft.com/~simonpj/papers/haskell-retrospective/
46bf8457679e3dd601af7e35cc0966642ba09794Christian Maedercontains some brief comments on syntax and style,
46bf8457679e3dd601af7e35cc0966642ba09794Christian Maeder
46bf8457679e3dd601af7e35cc0966642ba09794Christian MaederWhat now follows are descriptions of program documentation, file
46bf8457679e3dd601af7e35cc0966642ba09794Christian Maederformat, naming conventions and good programming practice (adapted form
46bf8457679e3dd601af7e35cc0966642ba09794Christian MaederMatt's C/C++ Programming Guidelines and the Linux kernel coding
46bf8457679e3dd601af7e35cc0966642ba09794Christian Maederstyle).
46bf8457679e3dd601af7e35cc0966642ba09794Christian Maeder
46bf8457679e3dd601af7e35cc0966642ba09794Christian Maeder
46bf8457679e3dd601af7e35cc0966642ba09794Christian Maeder=== Documentation ===
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian MaederComments are to be written in application terms (i.e. user's point of
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maederview). Don't use technical terms - that's what the code is for!
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian MaederComments should be written using correct spelling and grammar in complete
ed0055e8e720ca2d07e857e7852de91d47fab9e7Christian Maedersentences with punctation (in English only).
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder
ed0055e8e720ca2d07e857e7852de91d47fab9e7Christian Maeder"Generally, you want your comments to tell WHAT your code does, not HOW.
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian MaederAlso, try to avoid putting comments inside a function body: if the
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maederfunction is so complex that you need to separately comment parts of it,
3db8b71dd1ccc662325b96a5ee8f351ace0293baChristian Maederyou should probably" (... decompose it)
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder
af1cb109bce240bcafe3823df022d6088cbfc438Christian MaederPut a haddock comment on top of every exported function and data type!
3db8b71dd1ccc662325b96a5ee8f351ace0293baChristian MaederMake sure haddock accepts these comments.
3db8b71dd1ccc662325b96a5ee8f351ace0293baChristian Maeder
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder
46bf8457679e3dd601af7e35cc0966642ba09794Christian Maeder=== File Format ===
46bf8457679e3dd601af7e35cc0966642ba09794Christian Maeder
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian MaederAll Haskell source files start with a haddock header of the form:
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder
46bf8457679e3dd601af7e35cc0966642ba09794Christian Maeder<pre>
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder{- |
4bb40320bdda9b90e305c1bc7982814ad7fcbc42Christian MaederModule : <File name or $Header$ to be replaced automatically>
7e0943e4893be7d7d87059ef6995b59aa1d4e96bChristian MaederDescription : <optional short text displayed on contents page>
7e0943e4893be7d7d87059ef6995b59aa1d4e96bChristian MaederCopyright : (c) <Authors or Affiliations>
7e0943e4893be7d7d87059ef6995b59aa1d4e96bChristian MaederLicense : <license>
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder
7e0943e4893be7d7d87059ef6995b59aa1d4e96bChristian MaederMaintainer : <email>
7e0943e4893be7d7d87059ef6995b59aa1d4e96bChristian MaederStability : unstable | experimental | provisional | stable | frozen
7e0943e4893be7d7d87059ef6995b59aa1d4e96bChristian MaederPortability : portable | non-portable (<reason>)
ed0055e8e720ca2d07e857e7852de91d47fab9e7Christian Maeder
9d3c461220f8076ef80ca48f7b0574ded9b23e7aChristian Maeder<module description starting at first column>
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder-}
46bf8457679e3dd601af7e35cc0966642ba09794Christian Maeder</pre>
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder
7e0943e4893be7d7d87059ef6995b59aa1d4e96bChristian MaederA possible compiler pragma (like {-# LANGUAGE CPP #-}) may precede
ce59e0cc5c7221245ed323290bfccbda4ee32dd9Christian Maederthis header. The following hierarchical module name must of course
ce59e0cc5c7221245ed323290bfccbda4ee32dd9Christian Maedermatch the file name.
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder
798a3d6fdcb8c17b0bc3502a150be75c9ec8799bChristian MaederMake sure that the description is changed to meet the module (if the
af1cb109bce240bcafe3823df022d6088cbfc438Christian Maederheader was copied from elsewhere). Insert your email address as maintainer.
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder
7e0943e4893be7d7d87059ef6995b59aa1d4e96bChristian MaederTry to write portable (Haskell98) code. If you use i.e. multi-parameter
7e0943e4893be7d7d87059ef6995b59aa1d4e96bChristian Maedertype classes and functional dependencies the code becomes
7e0943e4893be7d7d87059ef6995b59aa1d4e96bChristian Maeder"non-portable (MPTC with FD)".
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder
b814b1bb510007ba5d0638eb27d93ef93fe64e66Christian MaederThe \$Header\$ entry will be automatically expanded.
b814b1bb510007ba5d0638eb27d93ef93fe64e66Christian Maeder
b814b1bb510007ba5d0638eb27d93ef93fe64e66Christian MaederLines should not be longer than 80 (preferably 75)
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maedercharacters to avoid wrapped lines (for casual readers)!
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder
b814b1bb510007ba5d0638eb27d93ef93fe64e66Christian MaederDon't leave trailing white space in your code in every line.
b814b1bb510007ba5d0638eb27d93ef93fe64e66Christian Maeder
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian MaederExpand all your tabs to spaces to avoid the danger of wrongly expanding
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maederthem (or a different display of tabs versus eight spaces). Possibly put
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maedersomething like the following in your ~/.emacs file.
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder (custom-set-variables '(indent-tabs-mode nil))
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian MaederThe last character in your file should be a newline! Under solaris
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maederyou'll get a warning if this is not the case and sometimes last lines
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maederwithout newlines are ignored (i.e. "#endif" without newline). Emacs
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maederusually asks for a final newline.
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder
7e0943e4893be7d7d87059ef6995b59aa1d4e96bChristian MaederYou may use http://hackage.haskell.org/package/scan to check your file format.
7e0943e4893be7d7d87059ef6995b59aa1d4e96bChristian Maeder
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian MaederThe whole module should not be too long (about 400 lines)
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder
46bf8457679e3dd601af7e35cc0966642ba09794Christian Maeder=== Naming Conventions ===
46bf8457679e3dd601af7e35cc0966642ba09794Christian Maeder
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian MaederIn Haskell types start with capital and functions with lowercase
3db8b71dd1ccc662325b96a5ee8f351ace0293baChristian Maederletters, so only avoid infix identifiers! Defining symbolic infix
3db8b71dd1ccc662325b96a5ee8f351ace0293baChristian Maederidentifiers should be left to library writers only.
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder
3db8b71dd1ccc662325b96a5ee8f351ace0293baChristian Maeder(The infix identifier "\\" at the end of a line causes cpp preprocessor
3db8b71dd1ccc662325b96a5ee8f351ace0293baChristian Maederproblems.)
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder
3db8b71dd1ccc662325b96a5ee8f351ace0293baChristian MaederNames (especially global ones) should be descriptive and if you need
3db8b71dd1ccc662325b96a5ee8f351ace0293baChristian Maederlong names write them as mixed case words (aka camelCase). (but "tmp"
3db8b71dd1ccc662325b96a5ee8f351ace0293baChristian Maederis to be preferred over "thisVariableIsATemporaryCounter")
ed0055e8e720ca2d07e857e7852de91d47fab9e7Christian Maeder
46bf8457679e3dd601af7e35cc0966642ba09794Christian MaederAlso in the standard libraries, function names with multiple words are
46bf8457679e3dd601af7e35cc0966642ba09794Christian Maederwritten using the camelCase convention. Similarly, type, typeclass and
46bf8457679e3dd601af7e35cc0966642ba09794Christian Maederconstructor names are written using the StudlyCaps convention.
46bf8457679e3dd601af7e35cc0966642ba09794Christian Maeder
51db8ddc5236cf8f39d87bf6139cbc9aad146828Christian MaederSome parts of our code use underlines (without unnecessary uppercase
46bf8457679e3dd601af7e35cc0966642ba09794Christian Maederletters) for long identifiers to better reflect names given with
46bf8457679e3dd601af7e35cc0966642ba09794Christian Maederhyphens in the requirement documentation. Also such names should be
46bf8457679e3dd601af7e35cc0966642ba09794Christian Maedertransliterated to camlCase identifiers possibly adding a (consistent)
46bf8457679e3dd601af7e35cc0966642ba09794Christian Maedersuffix or prefix to avoid conflicts with keywords. However, instead of
46bf8457679e3dd601af7e35cc0966642ba09794Christian Maedera recurring prefix or suffix you may consider to use qualified imports
46bf8457679e3dd601af7e35cc0966642ba09794Christian Maederand names.
46bf8457679e3dd601af7e35cc0966642ba09794Christian Maeder
46bf8457679e3dd601af7e35cc0966642ba09794Christian Maeder
46bf8457679e3dd601af7e35cc0966642ba09794Christian Maeder=== Good Programming Practice ===
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder"Functions should be short and sweet, and do just one thing. They should
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maederfit on one or two screenfuls of text (the ISO/ANSI screen size is 80x24,
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maederas we all know), and do one thing and do that well."
ed0055e8e720ca2d07e857e7852de91d47fab9e7Christian Maeder
3db8b71dd1ccc662325b96a5ee8f351ace0293baChristian MaederMost haskell functions should be at most a few lines, only case
3db8b71dd1ccc662325b96a5ee8f351ace0293baChristian Maederexpression over large data types (that should be avoided, too) may need
3db8b71dd1ccc662325b96a5ee8f351ace0293baChristian Maedercorresponding space.
3db8b71dd1ccc662325b96a5ee8f351ace0293baChristian Maeder
1da2d3de72cd19f22820492bc832c9964762a64eChristian MaederThe code should be succinct (though not obfuscated), readable and easy to
1da2d3de72cd19f22820492bc832c9964762a64eChristian Maedermaintain (after unforeseeable changes). Don't exploit exotic language
1da2d3de72cd19f22820492bc832c9964762a64eChristian Maederfeatures without good reason.
3db8b71dd1ccc662325b96a5ee8f351ace0293baChristian Maeder
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian MaederIt's not fixed how deep you indent (4 or 8 chars). You can break the
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maederline after "do", "let", "where", and "case .. of". Make sure that
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maederrenamings don't destroy your layout. (If you get to far to the right,
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maederthe code is unreadable anyway and needs to be decomposed.)
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian MaederBad:
798a3d6fdcb8c17b0bc3502a150be75c9ec8799bChristian Maeder case foo of Foo -> "Foo"
798a3d6fdcb8c17b0bc3502a150be75c9ec8799bChristian Maeder Bar -> "Bar"
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian MaederGood:
798a3d6fdcb8c17b0bc3502a150be75c9ec8799bChristian Maeder case <longer expression> of
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder Foo -> "Foo"
ed0055e8e720ca2d07e857e7852de91d47fab9e7Christian Maeder Bar -> "Bar"
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian MaederAvoid the notation with braces and semicolons since the layout rule
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maederforces you to properly align your alternatives.
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder
af1cb109bce240bcafe3823df022d6088cbfc438Christian MaederRespect compiler warnings. Supply type signatures, avoid shadowing and
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maederunused variables. Particularly avoid non-exhaustive and
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maederoverlapping patterns. Missing unreachable cases can be filled in using
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder"error" with a fixed string "<ModuleName>.<function>" to indicate the
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maedererror position (in case the impossible should happen). Don't invest
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maedertime to "show" the offending value, only do this temporarily when
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maederdebugging the code.
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder
1da2d3de72cd19f22820492bc832c9964762a64eChristian MaederDon't leave unused or commented-out code in your files! Readers don't
1da2d3de72cd19f22820492bc832c9964762a64eChristian Maederknow what to think of it.
af1cb109bce240bcafe3823df022d6088cbfc438Christian Maeder
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder
46bf8457679e3dd601af7e35cc0966642ba09794Christian Maeder==== Case expressions ====
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder
99882cd0f42bd3c1bff73170b174e14d1fde7dc4Christian MaederPrefer case expressions over pattern binding declarations with
99882cd0f42bd3c1bff73170b174e14d1fde7dc4Christian Maedermultiple equations.
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian MaederNot always nice:
798a3d6fdcb8c17b0bc3502a150be75c9ec8799bChristian Maeder longFunctionName (Foo: _ : _) = e1
798a3d6fdcb8c17b0bc3502a150be75c9ec8799bChristian Maeder longFunctionName (Bar: _) = e2
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder
99882cd0f42bd3c1bff73170b174e14d1fde7dc4Christian MaederBetter:
ed0055e8e720ca2d07e857e7852de91d47fab9e7Christian Maeder longFunctionName arg = case arg of
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder Foo : _ : _ -> e1
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder Bar : _ -> e2
3db8b71dd1ccc662325b96a5ee8f351ace0293baChristian Maeder _ -> error "ProgrammingGuidelines.longFunctionName"
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder
99882cd0f42bd3c1bff73170b174e14d1fde7dc4Christian MaederIn
99882cd0f42bd3c1bff73170b174e14d1fde7dc4Christian Maederhttp://research.microsoft.com/~simonpj/papers/haskell-retrospective/
4bb40320bdda9b90e305c1bc7982814ad7fcbc42Christian Maederthe first example is said to be written in [[declaration style]]. The
99882cd0f42bd3c1bff73170b174e14d1fde7dc4Christian Maederequations look like written for a rewrite system (although their order
99882cd0f42bd3c1bff73170b174e14d1fde7dc4Christian Maedermatters of course).
99882cd0f42bd3c1bff73170b174e14d1fde7dc4Christian Maeder
99882cd0f42bd3c1bff73170b174e14d1fde7dc4Christian MaederBut this declarative style is only nice for toy examples and annoying
99882cd0f42bd3c1bff73170b174e14d1fde7dc4Christian Maederif functions are renamed or if the number of arguments changes.
99882cd0f42bd3c1bff73170b174e14d1fde7dc4Christian Maeder
4bb40320bdda9b90e305c1bc7982814ad7fcbc42Christian MaederThe other extreme (according to SPJ) is [[expression style]]:
99882cd0f42bd3c1bff73170b174e14d1fde7dc4Christian Maeder longFunctionName = \ arg -> ...
99882cd0f42bd3c1bff73170b174e14d1fde7dc4Christian Maeder
99882cd0f42bd3c1bff73170b174e14d1fde7dc4Christian MaederWe don't propose this style either. We propose to use as much pattern
99882cd0f42bd3c1bff73170b174e14d1fde7dc4Christian Maedermatching (including as-patterns) on a single left-hand-side as appropriate.
99882cd0f42bd3c1bff73170b174e14d1fde7dc4Christian Maeder
99882cd0f42bd3c1bff73170b174e14d1fde7dc4Christian MaederHowever, the expression style with a lambda term may come in handy, when
4bb40320bdda9b90e305c1bc7982814ad7fcbc42Christian Maedersetting record fields of a function type.
99882cd0f42bd3c1bff73170b174e14d1fde7dc4Christian Maeder
99882cd0f42bd3c1bff73170b174e14d1fde7dc4Christian MaederWe avoid lambda expressions if this is easily possibly using the
99882cd0f42bd3c1bff73170b174e14d1fde7dc4Christian MaederPrelude functions const, flip, curry, uncurry or section notation or
99882cd0f42bd3c1bff73170b174e14d1fde7dc4Christian Maederplain partial application. We do not indroduce an auxiliary function only to
99882cd0f42bd3c1bff73170b174e14d1fde7dc4Christian Maederavoid the lambda, though.
99882cd0f42bd3c1bff73170b174e14d1fde7dc4Christian Maeder
99882cd0f42bd3c1bff73170b174e14d1fde7dc4Christian Maeder
99882cd0f42bd3c1bff73170b174e14d1fde7dc4Christian Maeder==== Partial functions ====
99882cd0f42bd3c1bff73170b174e14d1fde7dc4Christian Maeder
99882cd0f42bd3c1bff73170b174e14d1fde7dc4Christian MaederFor partial functions do document their preconditions (if not obvious)
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maederand make sure that partial functions are only called when
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maederpreconditions are obviously fulfilled (i.e. by a case statement or a
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maederprevious test). Particularly the call of "head" should be used with
798a3d6fdcb8c17b0bc3502a150be75c9ec8799bChristian Maedercare or (even better) be made obsolete by a case statement.
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder
3db8b71dd1ccc662325b96a5ee8f351ace0293baChristian MaederUsually a case statement (and the import of isJust and fromJust from
51db8ddc5236cf8f39d87bf6139cbc9aad146828Christian MaederData.[[Maybe]]) can be avoided by using the "maybe" function:
31c6978fd9066c9d2c3c98c950f7abbe89112522Christian Maeder
31c6978fd9066c9d2c3c98c950f7abbe89112522Christian Maeder maybe (error "<ModuleName>.<function>") id $ Map.lookup key map
31c6978fd9066c9d2c3c98c950f7abbe89112522Christian Maeder
1da2d3de72cd19f22820492bc832c9964762a64eChristian MaederGenerally we require you to be more explicit about failure
99882cd0f42bd3c1bff73170b174e14d1fde7dc4Christian Maedercases. Surely a missing (or an irrefutable) pattern would precisely
99882cd0f42bd3c1bff73170b174e14d1fde7dc4Christian Maederreport the position of a runtime error, but these are not so obvious
99882cd0f42bd3c1bff73170b174e14d1fde7dc4Christian Maederwhen reading the code.
99882cd0f42bd3c1bff73170b174e14d1fde7dc4Christian Maeder
99882cd0f42bd3c1bff73170b174e14d1fde7dc4Christian Maeder==== Let or where expressions ====
99882cd0f42bd3c1bff73170b174e14d1fde7dc4Christian Maeder
99882cd0f42bd3c1bff73170b174e14d1fde7dc4Christian MaederDo avoid mixing and nesting "let" and "where". (I prefer the
99882cd0f42bd3c1bff73170b174e14d1fde7dc4Christian Maederexpression-stylistic "let".) Use auxiliary top-level functions that
99882cd0f42bd3c1bff73170b174e14d1fde7dc4Christian Maederyou do not export. Export lists also support the detection of unused
99882cd0f42bd3c1bff73170b174e14d1fde7dc4Christian Maederfunctions.
99882cd0f42bd3c1bff73170b174e14d1fde7dc4Christian Maeder
1da2d3de72cd19f22820492bc832c9964762a64eChristian Maeder
99882cd0f42bd3c1bff73170b174e14d1fde7dc4Christian Maeder==== Code reuse ====
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder
162a689da386fc8ddbbe47bcae83eaca4fc8dbc0Christian MaederIf you notice that you're doing the same task again, try to generalize
798a3d6fdcb8c17b0bc3502a150be75c9ec8799bChristian Maederit in order to avoid duplicate code. It is frustrating to change the
798a3d6fdcb8c17b0bc3502a150be75c9ec8799bChristian Maedersame error in several places.
af1cb109bce240bcafe3823df022d6088cbfc438Christian Maeder
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder
46bf8457679e3dd601af7e35cc0966642ba09794Christian Maeder==== Application notation ====
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder
798a3d6fdcb8c17b0bc3502a150be75c9ec8799bChristian MaederMany parentheses can be eliminated using the infix application operator "$"
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maederwith lowest priority. Try at least to avoid unnecessary parentheses in
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maederstandard infix expression.
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder
ed0055e8e720ca2d07e857e7852de91d47fab9e7Christian Maeder f x : g x ++ h x
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder
ed0055e8e720ca2d07e857e7852de91d47fab9e7Christian Maeder a == 1 && b == 1 || a == 0 && b == 0
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian MaederRather than putting a large final argument in parentheses (with a
ed0055e8e720ca2d07e857e7852de91d47fab9e7Christian Maederdistant closing one) consider using "$" instead.
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder
ed0055e8e720ca2d07e857e7852de91d47fab9e7Christian Maeder"f (g x)" becomes "f $ g x" and consecutive applications
ed0055e8e720ca2d07e857e7852de91d47fab9e7Christian Maeder"f (g (h x))" can be written as "f $ g $ h x" or "f . g $ h x".
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder
ed0055e8e720ca2d07e857e7852de91d47fab9e7Christian MaederA function definition like
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder"f x = g $ h x" can be abbreviated to "f = g . h".
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian MaederNote that the final argument may even be an infix- or case expression:
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder
31c6978fd9066c9d2c3c98c950f7abbe89112522Christian Maeder map id $ c : l
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder
31c6978fd9066c9d2c3c98c950f7abbe89112522Christian Maeder filter (const True) . map id $ case l of ...
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian MaederHowever, be aware that $-terms cannot be composed further in infix
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maederexpressions.
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian MaederProbably wrong:
31c6978fd9066c9d2c3c98c950f7abbe89112522Christian Maeder f $ x ++ g $ x
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian MaederBut the scope of an expression is also limited by the layout rule, so
7e0943e4893be7d7d87059ef6995b59aa1d4e96bChristian Maederit is usually safe to use "$" on right hand sides.
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder
af1cb109bce240bcafe3823df022d6088cbfc438Christian MaederOk:
51db8ddc5236cf8f39d87bf6139cbc9aad146828Christian Maeder do f $ l
ce59e0cc5c7221245ed323290bfccbda4ee32dd9Christian Maeder ++
51db8ddc5236cf8f39d87bf6139cbc9aad146828Christian Maeder do g $ l
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder
3db8b71dd1ccc662325b96a5ee8f351ace0293baChristian MaederOf course "$" can not be used in types. GHC has also some primitive
3db8b71dd1ccc662325b96a5ee8f351ace0293baChristian Maederfunctions involving the kind "#" that cannot be applied using "$".
3db8b71dd1ccc662325b96a5ee8f351ace0293baChristian Maeder
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian MaederLast warning: always leave spaces around "$" (and other mixfix
ed0055e8e720ca2d07e857e7852de91d47fab9e7Christian Maederoperators) since a clash with template haskell is possible.
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder(Also write "\ t" instead of "\t" in lambda expressions)
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder
46bf8457679e3dd601af7e35cc0966642ba09794Christian Maeder==== List Comprehensions ====
46bf8457679e3dd601af7e35cc0966642ba09794Christian Maeder
d71c501e69da3973406558162ad439da2b3464d6Christian MaederUse these only when "short and sweet". Prefer map, filter, and foldr!
d71c501e69da3973406558162ad439da2b3464d6Christian Maeder
d71c501e69da3973406558162ad439da2b3464d6Christian MaederInstead of:
d71c501e69da3973406558162ad439da2b3464d6Christian Maeder
d71c501e69da3973406558162ad439da2b3464d6Christian Maeder [toUpper c | c <- s]
d71c501e69da3973406558162ad439da2b3464d6Christian Maeder
d71c501e69da3973406558162ad439da2b3464d6Christian Maederwrite:
d71c501e69da3973406558162ad439da2b3464d6Christian Maeder
d71c501e69da3973406558162ad439da2b3464d6Christian Maeder map toUpper s
d71c501e69da3973406558162ad439da2b3464d6Christian Maeder
d71c501e69da3973406558162ad439da2b3464d6Christian Maeder
d71c501e69da3973406558162ad439da2b3464d6Christian MaederConsider:
d71c501e69da3973406558162ad439da2b3464d6Christian Maeder
d71c501e69da3973406558162ad439da2b3464d6Christian Maeder [toUpper c | s <- strings, c <- s]
d71c501e69da3973406558162ad439da2b3464d6Christian Maeder
d71c501e69da3973406558162ad439da2b3464d6Christian MaederHere it takes some time for the reader to find out which value depends
d71c501e69da3973406558162ad439da2b3464d6Christian Maederon what other value and it is not so clear how many times the interim
d71c501e69da3973406558162ad439da2b3464d6Christian Maedervalues s and c are used. In contrast to that the following can't be clearer:
d71c501e69da3973406558162ad439da2b3464d6Christian Maeder
d71c501e69da3973406558162ad439da2b3464d6Christian Maeder map toUpper (concat strings)
d71c501e69da3973406558162ad439da2b3464d6Christian Maeder
d71c501e69da3973406558162ad439da2b3464d6Christian Maeder
d71c501e69da3973406558162ad439da2b3464d6Christian MaederWhen using higher order functions you can switch easier to data
d71c501e69da3973406558162ad439da2b3464d6Christian Maederstructures different from list. Compare:
d71c501e69da3973406558162ad439da2b3464d6Christian Maeder
d71c501e69da3973406558162ad439da2b3464d6Christian Maeder map (1+) list
d71c501e69da3973406558162ad439da2b3464d6Christian Maeder
d71c501e69da3973406558162ad439da2b3464d6Christian Maederand:
d71c501e69da3973406558162ad439da2b3464d6Christian Maeder
d71c501e69da3973406558162ad439da2b3464d6Christian Maeder Set.map (1+) set
d71c501e69da3973406558162ad439da2b3464d6Christian Maeder
798a3d6fdcb8c17b0bc3502a150be75c9ec8799bChristian Maeder
46bf8457679e3dd601af7e35cc0966642ba09794Christian Maeder==== Types ====
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder
162a689da386fc8ddbbe47bcae83eaca4fc8dbc0Christian MaederPrefer proper data types over type synonyms or tuples even if you have
af1cb109bce240bcafe3823df022d6088cbfc438Christian Maederto do more constructing and unpacking. This will make it easier to
af1cb109bce240bcafe3823df022d6088cbfc438Christian Maedersupply class instances later on. Don't put class constraints on
af1cb109bce240bcafe3823df022d6088cbfc438Christian Maedera data type, constraints belong only to the functions that manipulate
ed0055e8e720ca2d07e857e7852de91d47fab9e7Christian Maederthe data.
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder
af1cb109bce240bcafe3823df022d6088cbfc438Christian MaederUsing type synonyms consistently is difficult over a longer time,
3db8b71dd1ccc662325b96a5ee8f351ace0293baChristian Maederbecause this is not checked by the compiler. (The types shown by
3db8b71dd1ccc662325b96a5ee8f351ace0293baChristian Maederthe compiler may be unpredictable: i.e. FilePath, String or [Char])
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder
3db8b71dd1ccc662325b96a5ee8f351ace0293baChristian MaederTake care if your data type has many variants (unless it is an
798a3d6fdcb8c17b0bc3502a150be75c9ec8799bChristian Maederenumeration type.) Don't repeat common parts in every variant since
798a3d6fdcb8c17b0bc3502a150be75c9ec8799bChristian Maederthis will cause code duplication.
798a3d6fdcb8c17b0bc3502a150be75c9ec8799bChristian Maeder
ed0055e8e720ca2d07e857e7852de91d47fab9e7Christian MaederBad (to handle arguments in sync):
798a3d6fdcb8c17b0bc3502a150be75c9ec8799bChristian Maeder
798a3d6fdcb8c17b0bc3502a150be75c9ec8799bChristian Maeder data Mode f p = Box f p | Diamond f p
798a3d6fdcb8c17b0bc3502a150be75c9ec8799bChristian Maeder
798a3d6fdcb8c17b0bc3502a150be75c9ec8799bChristian MaederGood (to handle arguments only once):
798a3d6fdcb8c17b0bc3502a150be75c9ec8799bChristian Maeder
798a3d6fdcb8c17b0bc3502a150be75c9ec8799bChristian Maeder data BoxOrDiamond = Box | Diamond
798a3d6fdcb8c17b0bc3502a150be75c9ec8799bChristian Maeder
3db8b71dd1ccc662325b96a5ee8f351ace0293baChristian Maeder data Mode f p = Mode BoxOrDiamond f p
798a3d6fdcb8c17b0bc3502a150be75c9ec8799bChristian Maeder
798a3d6fdcb8c17b0bc3502a150be75c9ec8799bChristian Maeder
3db8b71dd1ccc662325b96a5ee8f351ace0293baChristian MaederConsider (bad):
798a3d6fdcb8c17b0bc3502a150be75c9ec8799bChristian Maeder
51db8ddc5236cf8f39d87bf6139cbc9aad146828Christian Maeder data Tuple a b = Tuple a b | Undefined
798a3d6fdcb8c17b0bc3502a150be75c9ec8799bChristian Maeder
3db8b71dd1ccc662325b96a5ee8f351ace0293baChristian Maederversus (better):
798a3d6fdcb8c17b0bc3502a150be75c9ec8799bChristian Maeder
51db8ddc5236cf8f39d87bf6139cbc9aad146828Christian Maeder data Tuple a b = Tuple a b
798a3d6fdcb8c17b0bc3502a150be75c9ec8799bChristian Maeder
798a3d6fdcb8c17b0bc3502a150be75c9ec8799bChristian Maederand using:
798a3d6fdcb8c17b0bc3502a150be75c9ec8799bChristian Maeder
51db8ddc5236cf8f39d87bf6139cbc9aad146828Christian Maeder Maybe (Tuple a b)
798a3d6fdcb8c17b0bc3502a150be75c9ec8799bChristian Maeder
3db8b71dd1ccc662325b96a5ee8f351ace0293baChristian Maeder(or another monad) whenever an undefined result needs to be propagated
798a3d6fdcb8c17b0bc3502a150be75c9ec8799bChristian Maeder
798a3d6fdcb8c17b0bc3502a150be75c9ec8799bChristian Maeder
46bf8457679e3dd601af7e35cc0966642ba09794Christian Maeder==== Records ====
798a3d6fdcb8c17b0bc3502a150be75c9ec8799bChristian Maeder
3db8b71dd1ccc662325b96a5ee8f351ace0293baChristian MaederFor (large) records avoid the use of the constructor directly and
3db8b71dd1ccc662325b96a5ee8f351ace0293baChristian Maederremember that the order and number of fields may change.
798a3d6fdcb8c17b0bc3502a150be75c9ec8799bChristian Maeder
3db8b71dd1ccc662325b96a5ee8f351ace0293baChristian MaederTake care with (the rare case of) depend polymorphic fields:
798a3d6fdcb8c17b0bc3502a150be75c9ec8799bChristian Maeder
4bb40320bdda9b90e305c1bc7982814ad7fcbc42Christian Maeder data Fields a = VariantWithTwo
f09bc2a9244ed29b02ec8dd58a3040f8acb467baChristian Maeder { field1 :: a
f09bc2a9244ed29b02ec8dd58a3040f8acb467baChristian Maeder , field2 :: a }
798a3d6fdcb8c17b0bc3502a150be75c9ec8799bChristian Maeder
ed0055e8e720ca2d07e857e7852de91d47fab9e7Christian MaederThe type of a value v can not be changed by only setting field1:
798a3d6fdcb8c17b0bc3502a150be75c9ec8799bChristian Maeder
46bf8457679e3dd601af7e35cc0966642ba09794Christian Maeder v { field1 = f }
798a3d6fdcb8c17b0bc3502a150be75c9ec8799bChristian Maeder
798a3d6fdcb8c17b0bc3502a150be75c9ec8799bChristian MaederBetter construct a new value:
798a3d6fdcb8c17b0bc3502a150be75c9ec8799bChristian Maeder
46bf8457679e3dd601af7e35cc0966642ba09794Christian Maeder VariantWithTwo { field1 = f } -- leaving field2 undefined
798a3d6fdcb8c17b0bc3502a150be75c9ec8799bChristian Maeder
798a3d6fdcb8c17b0bc3502a150be75c9ec8799bChristian MaederOr use a polymorphic element that is instantiated by updating:
798a3d6fdcb8c17b0bc3502a150be75c9ec8799bChristian Maeder
f09bc2a9244ed29b02ec8dd58a3040f8acb467baChristian Maeder empty = VariantWithTwo { field1 = [], field2 = [] }
798a3d6fdcb8c17b0bc3502a150be75c9ec8799bChristian Maeder
f09bc2a9244ed29b02ec8dd58a3040f8acb467baChristian Maeder empty { field1 = [f] }
798a3d6fdcb8c17b0bc3502a150be75c9ec8799bChristian Maeder
798a3d6fdcb8c17b0bc3502a150be75c9ec8799bChristian MaederSeveral variants with identical fields may avoid some code duplication
798a3d6fdcb8c17b0bc3502a150be75c9ec8799bChristian Maederwhen selecting and updating, though possibly not in a few
798a3d6fdcb8c17b0bc3502a150be75c9ec8799bChristian Maederdepended polymorphic cases.
798a3d6fdcb8c17b0bc3502a150be75c9ec8799bChristian Maeder
3db8b71dd1ccc662325b96a5ee8f351ace0293baChristian MaederHowever, I doubt if the following is a really good alternative to the
3db8b71dd1ccc662325b96a5ee8f351ace0293baChristian Maederabove data Mode with data BoxOrDiamond.
3db8b71dd1ccc662325b96a5ee8f351ace0293baChristian Maeder
3db8b71dd1ccc662325b96a5ee8f351ace0293baChristian Maeder
1da2d3de72cd19f22820492bc832c9964762a64eChristian Maeder data Mode f p =
3db8b71dd1ccc662325b96a5ee8f351ace0293baChristian Maeder Box { formula :: f, positions :: p }
3db8b71dd1ccc662325b96a5ee8f351ace0293baChristian Maeder | Diamond { formula :: f, positions :: p }
ed0055e8e720ca2d07e857e7852de91d47fab9e7Christian Maeder
798a3d6fdcb8c17b0bc3502a150be75c9ec8799bChristian Maeder
46bf8457679e3dd601af7e35cc0966642ba09794Christian Maeder==== IO ====
798a3d6fdcb8c17b0bc3502a150be75c9ec8799bChristian Maeder
798a3d6fdcb8c17b0bc3502a150be75c9ec8799bChristian MaederTry to strictly separate IO, Monad and pure (without do) function
3db8b71dd1ccc662325b96a5ee8f351ace0293baChristian Maederprogramming (possibly via separate modules).
798a3d6fdcb8c17b0bc3502a150be75c9ec8799bChristian Maeder
798a3d6fdcb8c17b0bc3502a150be75c9ec8799bChristian MaederBad:
798a3d6fdcb8c17b0bc3502a150be75c9ec8799bChristian Maeder x <- return y
798a3d6fdcb8c17b0bc3502a150be75c9ec8799bChristian Maeder ...
798a3d6fdcb8c17b0bc3502a150be75c9ec8799bChristian Maeder
798a3d6fdcb8c17b0bc3502a150be75c9ec8799bChristian MaederGood:
ed0055e8e720ca2d07e857e7852de91d47fab9e7Christian Maeder let x = y
798a3d6fdcb8c17b0bc3502a150be75c9ec8799bChristian Maeder ...
798a3d6fdcb8c17b0bc3502a150be75c9ec8799bChristian Maeder
798a3d6fdcb8c17b0bc3502a150be75c9ec8799bChristian Maeder
798a3d6fdcb8c17b0bc3502a150be75c9ec8799bChristian MaederDon't use Prelude.interact and make sure your program does not depend
798a3d6fdcb8c17b0bc3502a150be75c9ec8799bChristian Maederon the (not always obvious) order of evaluation. I.e. don't read and
798a3d6fdcb8c17b0bc3502a150be75c9ec8799bChristian Maederwrite to the same file:
798a3d6fdcb8c17b0bc3502a150be75c9ec8799bChristian Maeder
798a3d6fdcb8c17b0bc3502a150be75c9ec8799bChristian MaederThis will fail:
798a3d6fdcb8c17b0bc3502a150be75c9ec8799bChristian Maeder
798a3d6fdcb8c17b0bc3502a150be75c9ec8799bChristian Maeder do s <- readFile f
798a3d6fdcb8c17b0bc3502a150be75c9ec8799bChristian Maeder writeFile f $ 'a' : s
798a3d6fdcb8c17b0bc3502a150be75c9ec8799bChristian Maeder
798a3d6fdcb8c17b0bc3502a150be75c9ec8799bChristian Maederbecause of lazy IO! (Writing is starting before reading is finished.)
798a3d6fdcb8c17b0bc3502a150be75c9ec8799bChristian Maeder
798a3d6fdcb8c17b0bc3502a150be75c9ec8799bChristian Maeder
46bf8457679e3dd601af7e35cc0966642ba09794Christian Maeder==== Trace ====
798a3d6fdcb8c17b0bc3502a150be75c9ec8799bChristian Maeder
798a3d6fdcb8c17b0bc3502a150be75c9ec8799bChristian MaederTracing is for debugging purposes only and should not be used as
798a3d6fdcb8c17b0bc3502a150be75c9ec8799bChristian Maederfeedback for the user. Clean code is not cluttered by trace calls.
798a3d6fdcb8c17b0bc3502a150be75c9ec8799bChristian Maeder
af1cb109bce240bcafe3823df022d6088cbfc438Christian Maeder
46bf8457679e3dd601af7e35cc0966642ba09794Christian Maeder==== Imports ====
ce59e0cc5c7221245ed323290bfccbda4ee32dd9Christian Maeder
ce59e0cc5c7221245ed323290bfccbda4ee32dd9Christian MaederStandard library modules like Char. List, Maybe, Monad, etc should be
3db8b71dd1ccc662325b96a5ee8f351ace0293baChristian Maederimported by their hierarchical module name, i.e. the base package (so
3db8b71dd1ccc662325b96a5ee8f351ace0293baChristian Maederthat haddock finds them):
ce59e0cc5c7221245ed323290bfccbda4ee32dd9Christian Maeder
798a3d6fdcb8c17b0bc3502a150be75c9ec8799bChristian Maeder import Data.List
798a3d6fdcb8c17b0bc3502a150be75c9ec8799bChristian Maeder import Control.Monad
ed0055e8e720ca2d07e857e7852de91d47fab9e7Christian Maeder import System.Environment
ce59e0cc5c7221245ed323290bfccbda4ee32dd9Christian Maeder
3db8b71dd1ccc662325b96a5ee8f351ace0293baChristian MaederThe libraries for Set and Map are to be imported qualified:
3db8b71dd1ccc662325b96a5ee8f351ace0293baChristian Maeder
3db8b71dd1ccc662325b96a5ee8f351ace0293baChristian Maeder import qualified Data.Set as Set
3db8b71dd1ccc662325b96a5ee8f351ace0293baChristian Maeder import qualified Data.Map as Map
ce59e0cc5c7221245ed323290bfccbda4ee32dd9Christian Maeder
ce59e0cc5c7221245ed323290bfccbda4ee32dd9Christian Maeder
46bf8457679e3dd601af7e35cc0966642ba09794Christian Maeder==== Glasgow extensions and Classes ====
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder
4bb40320bdda9b90e305c1bc7982814ad7fcbc42Christian Maeder[[Use of language extensions|Stay away from extensions]] as long as possible. Also use classes with
af1cb109bce240bcafe3823df022d6088cbfc438Christian Maedercare because soon the desire for overlapping instances (like for lists
ce59e0cc5c7221245ed323290bfccbda4ee32dd9Christian Maederand strings) may arise. Then you may want MPTC (multi-parameter type
3db8b71dd1ccc662325b96a5ee8f351ace0293baChristian Maederclasses), functional dependencies (FD), undecidable and possibly incoherent
798a3d6fdcb8c17b0bc3502a150be75c9ec8799bChristian Maederinstances and then you are "in the wild" (according to SPJ).
af1cb109bce240bcafe3823df022d6088cbfc438Christian Maeder
51db8ddc5236cf8f39d87bf6139cbc9aad146828Christian Maeder=== Style in other languages ===
51db8ddc5236cf8f39d87bf6139cbc9aad146828Christian Maeder
51db8ddc5236cf8f39d87bf6139cbc9aad146828Christian Maeder* [http://www.cs.caltech.edu/~cs20/a/style.html OCaml style]
af1cb109bce240bcafe3823df022d6088cbfc438Christian Maeder
46bf8457679e3dd601af7e35cc0966642ba09794Christian Maeder=== Final remarks ===
af1cb109bce240bcafe3823df022d6088cbfc438Christian Maeder
ed0055e8e720ca2d07e857e7852de91d47fab9e7Christian MaederDespite guidelines, writing "correct code" (without formal proof
af1cb109bce240bcafe3823df022d6088cbfc438Christian Maedersupport yet) still remains the major challenge. As motivation to
ed0055e8e720ca2d07e857e7852de91d47fab9e7Christian Maederfollow these guidelines consider the points that are from the "C++
ed0055e8e720ca2d07e857e7852de91d47fab9e7Christian MaederCoding Standard", where I replaced "C++" with "Haskell".
af1cb109bce240bcafe3823df022d6088cbfc438Christian Maeder
ed0055e8e720ca2d07e857e7852de91d47fab9e7Christian MaederGood Points:
af1cb109bce240bcafe3823df022d6088cbfc438Christian Maeder
46bf8457679e3dd601af7e35cc0966642ba09794Christian Maeder* programmers can go into any code and figure out what's going on
af1cb109bce240bcafe3823df022d6088cbfc438Christian Maeder
46bf8457679e3dd601af7e35cc0966642ba09794Christian Maeder* new people can get up to speed quickly
af1cb109bce240bcafe3823df022d6088cbfc438Christian Maeder
46bf8457679e3dd601af7e35cc0966642ba09794Christian Maeder* people new to Haskell are spared the need to develop a personal style and defend it to the death
af1cb109bce240bcafe3823df022d6088cbfc438Christian Maeder
46bf8457679e3dd601af7e35cc0966642ba09794Christian Maeder* people new to Haskell are spared making the same mistakes over and over again
af1cb109bce240bcafe3823df022d6088cbfc438Christian Maeder
46bf8457679e3dd601af7e35cc0966642ba09794Christian Maeder* people make fewer mistakes in consistent environments
af1cb109bce240bcafe3823df022d6088cbfc438Christian Maeder
46bf8457679e3dd601af7e35cc0966642ba09794Christian Maeder* programmers have a common enemy :-)
af1cb109bce240bcafe3823df022d6088cbfc438Christian Maeder
af1cb109bce240bcafe3823df022d6088cbfc438Christian MaederBad Points:
af1cb109bce240bcafe3823df022d6088cbfc438Christian Maeder
46bf8457679e3dd601af7e35cc0966642ba09794Christian Maeder* the standard is usually stupid because it was made by someone who doesn't understand Haskell
af1cb109bce240bcafe3823df022d6088cbfc438Christian Maeder
46bf8457679e3dd601af7e35cc0966642ba09794Christian Maeder* the standard is usually stupid because it's not what I do
af1cb109bce240bcafe3823df022d6088cbfc438Christian Maeder
46bf8457679e3dd601af7e35cc0966642ba09794Christian Maeder* standards reduce creativity
af1cb109bce240bcafe3823df022d6088cbfc438Christian Maeder
46bf8457679e3dd601af7e35cc0966642ba09794Christian Maeder* standards are unnecessary as long as people are consistent
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder
46bf8457679e3dd601af7e35cc0966642ba09794Christian Maeder* standards enforce too much structure
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder
46bf8457679e3dd601af7e35cc0966642ba09794Christian Maeder* people ignore standards anyway
bd8ff5b5f66be563e5be9d3a0c069e32d06f331cChristian Maeder
51db8ddc5236cf8f39d87bf6139cbc9aad146828Christian Maeder
51db8ddc5236cf8f39d87bf6139cbc9aad146828Christian Maeder
51db8ddc5236cf8f39d87bf6139cbc9aad146828Christian Maeder[[Category:Style]]