- write all functions related to math/geometry/combinatorics in pure functional style, even better with accompanying mathematical proofs to be sure they are principally sound (you won't avoid problems with floating numbers etc. that way)
- think about using functional programming in parallel/distributed tasks if you can manage communication complexity directly (i.e. this is not handled to you by some opaque, un-debuggable monad)
- write everything else in imperative style of your choice
I/O is the elephant in the room of functional programming, monads are "imperative" hacks to make functional programming useful in any real-world-related way, and most monad tutorials will only confuse you about what they are actually.