mapAccumLM :: Monad m
  => (acc -> x -> m (acc, y))
    {- ^ Function taking accumulator and list element,
         returning new accumulator and modified list element -}
  -> acc           -- ^ Initial accumulator
  -> [x]           -- ^ Input list
  -> m (acc, [y])  -- ^ Final accumulator and result list
mapAccumLM f s l = case l of
  [] -> return (s, [])
  x : xs -> do
    (s', y) <- f s x
    (s'', ys) <- mapAccumLM f s' xs
    return (s'', y : ys)

-- | generalization of mapAccumL to monads with combine function
mapAccumLM :: Monad m
  => (acc -> x -> m (acc, y))
    {- ^ Function taking accumulator and list element,
         returning new accumulator and modified list element -}
  -> acc           -- ^ Initial accumulator
  -> [x]           -- ^ Input list
  -> m (acc, [y])
mapAccumLM f s l = case l of
  [] -> return (s, [])
  x : xs -> do
    (s', y) <- f s x
    (s'', ys) <- mapAccumLM f s' xs
    return (s'', y : ys)

-- | generalization of mapAccumL to monads with combine function
mapAccumLM f s l = case l of
  [] -> return (s, [])
  x : xs -> do
    (s', y) <- f s x
    (s'', ys) <- mapAccumLM f s' xs
    return (s'', y : ys)

-- | generalization of mapAccumL to monads with combine function