One solution to this is to have variants of the _
functions that are type-specialised to only accept ()
as the loop body's result:
traverse_' :: (Applicative f, Foldable t)
=> (a -> f ()) -> t a -> f ()
traverse_' = traverse_
for_' :: (Applicative f, Foldable t)
=> t a -> (a -> f ()) -> f ()
for_' = for_
mapM_' :: (Monad m, Foldable t)
=> (a -> m ()) -> t a -> m ()
mapM_' = mapM_
forM_' :: (Monad m, Foldable t)
=> t a -> (a -> m ()) -> m ()
forM_' = forM_
These make it explicit that the loop should have no result, and makes it a type error to accidentally introduce a non-()
result.