Agree with the advice about monads. You're going to think monads are weird because the first one you encounter is used to hide a particular detail of how Haskell works in the real world, namely that Haskell can't mutate objects, but that running your program mutates the real world. Ignore this use case, because while interesting, it's a messy implementation detail, not something to model in your own code.
Use monads for bailing out of computations early (Maybe/Either) or passing some state along through a computation (State). When you're comfortable with those concepts, look at ST for a generalization of what IO does. That is something you can actually use to simplify your own programs.