The following patterns are guidelines, not rules. There are exceptions.

Some of the patterns trade generality/beauty for performance. Only use these when needed.

Much of this is GHC specific.

A linked-list of linked-lists of pointers to integers is not a good way to represent a bitmap! (Someone actually did this and complained Haskell was slow.)

You can use -funbox-strict-fields on a per file basis if UNPACK is too verbose.

This is the most important optimization available to us.

Does not always apply (e.g. when representing streams and other infitinte structures.)

Strict spines cause more work to be done up-front (e.g. on insert), when the data structure is in cache, rather than later (e.g. on the next lookup.)

Inline HOFs if the higher-order argument is used a lot (e.g. in map , but not in Data.Map.insertWith .)

At the cost of increased code size, we can inline map into g by using the non-recursive wrapper trick on the previous slide together with an INLINE pragma.

Haskell makes it cheap to create throwaway data types like StrictPair : one line of code.

If you're using a composite accumulator (e.g. a pair), make sure it has strict fields.

Use strict returns in monadic code

return often wraps the value in some kind of (lazy) box. This is often not what we want, especially when returning some arithmetic expression. For example, assuming we're in a state monad:

return $ x + y

creates a thunk. We most likely want: