I think of monads mostly as "an implicit context on which we can perform operations in sequence", which is maybe similar. But I'll agree with other people here that you really have to build up your own intuition by working through examples and maybe trying to write your own Monad instances, etc. Otherwise you will apply this intuition in a subtly wrong way.
There are so many cool monads that work differently from IO, Maybe and such types, e.g. the binary package allows me to write
data Header = Header Word8 Word16
parseHeader :: Get Header
parseHeader = Header <$> getWord8 <*> getWord16le
or for a more complicated example
data Header = Header [Word16]
parseHeader :: Get Header
parseHeader = do
size <- fromIntegral <$> getWord8
fields <- replicateM size getWord16le
return $ Header fields
and then I can later run parseHeader on some binary input to parse a header, and I can do it in one go or I can run it incrementally, it really doesn't matter, because the Get monad only describes the way the input should be parsed and not the actual parsing algorithm.
There are so many cool monads that work differently from IO, Maybe and such types, e.g. the binary package allows me to write
or for a more complicated example and then I can later run parseHeader on some binary input to parse a header, and I can do it in one go or I can run it incrementally, it really doesn't matter, because the Get monad only describes the way the input should be parsed and not the actual parsing algorithm.