You should try actually doing some Haskell programming. There are some anti-patterns but the RIO pattern is very coherent and flexible. One IO base monad, one readerT that holds an IORef that gives you access to every other effect you need.
https://academy.fpblock.com/blog/2017/06/readert-design-patt... is the classic explanation of this pattern
https://academy.fpblock.com/blog/2017/06/readert-design-patt... is the classic explanation of this pattern