A good one to learn early on is ScopedTypeVariables
, because they are very useful for debugging type issues in a function. When I have a baffling type error, I temporarily add type declarations on each of the expressions in the function. (Often you'll need to break up some of the expressions to see what's really going on.) That usually helps me determine which expression has a different type than I expected.
TypeFamilies
are more powerful than MultiParamTypeClasses
, so you don't really need the latter. When working with type families, you usually need to enable FlexibleContexts
and FlexibleInstances
as well, so that's three pragmas you'll learn for the price of one. FunctionalDependencies
is generally used with MultiParamTypeClasses
, so that's one you can ignore for now.
GHC is pretty good at telling you when you need to enable Rank2Types
or RankNTypes
, so you can postpone learning more about those until a little later.
Those are the ones I'd start with.
EDIT: Removed comment about avoiding StandaloneDeriving
. (I was thinking of orphan instances.)