I am writing my first monad instance so please forgive if I'm missing something obvious.
I want to do something like this:
readStuffFromDatabase >>= function1 >>= ... >>= functionN >>= writeStuffToDatabase
function1 ... functionN are business logic. Any business logic can return DoNothing which should obviously prevent any further computation.
Here are my questions:
Am I thinking about the problem in the right way? Can this approach lead to idiomatic code, good performance, etc. or is it already doomed?
How should I define a type intended to chain arbitrary amounts of computation together? What's fuzzy to me is do all monad instances already do that and all I need is a vanilla monad instance? (Like Maybe?) Or do I need something more sophisticated?
CodePudding user response:
Short version: Monad
is almost certainly going to paint you into a corner. You need Applicative
instead, or at most, a selective applicative.
Suppose you go for a monad, name it M
, and have some action like numEmployees :: M Int
or something. Now I write:
do
n <- numEmployees
if n > 10
then computeTaxes
else dollars 1000 <$ DoNothing
To execute this action, you need to decide whether the else
branch gets taken before knowing n
. Not possible.
The fundamental feature of monads that's in your way here is that later actions can inspect the values returned by earlier actions before deciding what to do. Applicative functors do not support that, and so are more amenable to the kind of static analysis you're hoping to do.