У меня на практике многое сводится к следующему:
1. Если вычисление можно выразить без контекста, то карирование, ramda, ski и point-free.
2. Если Контекст может быть выражен через монады, то:
2.1. Если монады часть языковых конструкций, то отдать преимущество языку (например async/await)
2.2. Если монады не часть языковых конструкций, то брать их из fp-ts
3. Случаи несуществования преимущественно выражать через монады Option/Either.
4. Исключения использовать только в случае гарантированно фатальных происшествий.