Haskell: imports vs exports
Haskell module
s are defined with:
- Imports
- Exports
- Extensions/flags
- Code
When I build a module
, I think in terms of interface, that's why I enumerate
the exports:
It has several benefits:
- Put purpose-first
- Detect dead code sooner (ease refactorings)
- Ensure stability (making contracts explicit)
This helps also to create smart-constructors, a common idiom which uncouple data-representation and data-construction.
For example, Nat
does not expose the constructor in our example, but mkNat
should be used as such:
newtype Nat
= Nat { toInteger :: Integer}
deriving newtype (Eq, Ord, Show)
mkNat x =
if x >= 0
then Just $ Nat x
else Nothing
So mkNat
enforces Nat
invariant, letting us also the freedom to rework
underlying constructors without changing consumers.
On another hand, I tend to let import
s implicit (unless there are conflicts,
or for clarity, I qualify them for this scenario):
-- Instead of
-- I use
Which reduces maintenance and diffs.
The rational being that implementations (should) change more frequently than interfaces.