You shouldn't need this stuff if you don't want to use it. Just write a few IO functions for interaction with the real world, and pure functions for the rest. I made the same mistake in the past, and I was completely lost. I'm still nowhere near advanced, but sticking to simple stuff and learning slowly I am able to be quite productive now.
I hit the same problem... I had decided to start with a little toy 'dice rolling' program, but since it involved random numbers I unwittingly got hit with the monad problem up front.
It seemed I had two options: either I could pass a seed value around everywhere, or I could lift all my values into monads, necessitating the use of the 'monadic' version of all the operators etc everywhere.
I was unable to achieve what you suggest... I could not find a way to keep the 'inner' part of the code as pure functions just expressing simple operations.
I had some useful feedback but no one addressed the "monad pollution" issue.
Apart from the different mindset of Haskell (which I found interesting)
I struggled with having multiple ways to do everything, how to find the 'right' or monadic version of a particular function or operation, poor docs.