do bs <- bss bs
atomically :: STM a -> IO ais used to run STM transactions atomically. So, by specializing the types of atomically and join to
atomically :: STM (IO b) -> IO (IO b) join :: IO (IO b) -> IO bwe can compose them as
join . atomically :: STM (IO b) -> IO bto run an STM transaction and the IO action it returns.
>>> concat (Just [1, 2, 3]) [1,2,3]
>>> concat (Left 42) []
>>> concat [[1, 2, 3], [4, 5], [6], []] [1,2,3,4,5,6]