What (if any) is the generally accepted way of minimising the impact of the IO Monad on my code

Viewed 145

I'm struggling a bit with the IO Monad. (still very much a 101 learner)

I believe I understand the excellent reasons for segregating "IO" from purely functional code, but this appears to be making my code much more complex when using clock and environment attributes. Here's an example (related to clocks):

timeZoneSeconds = liftA (60*) $ liftA timeZoneMinutes getCurrentTimeZone

Now, I have lots of other stuff to do with timeZoneSeconds -- adding, subtracting, comparing -- elsewhere in the program, and as timeZoneSeconds interacts with other bits, practically everything I'm dealing with turns into an "IO ", and thus fills my code with liftAs.

So basically I'm seeing all my pure code turning into IO-dirty code.

In all the didactic material I've seen, most of the explanations around the IO monad are of the general sort "read stuff then write stuff", without much "calculate stuff".

Is there a recommended way to minimise the impact of this?

Should I redefine all the operators I need to use liftA "under the covers"?

Or should I just get on with it?

1 Answers

Think of it as dependency injection. You inject the results of the impure calls into your pure code, then use the results of the pure code to do more impure IO such as printing the result:

main = do
  env <- lookupEnv "ENV"
  tz <- getCurrentTimeZone
  let result = pureCode env tz
  putStr result

Your pureCode function doesn't have any IO attached.

Related