serokell / universum

:milky_way: Prelude written in @Serokell
MIT License
176 stars 28 forks source link

Generalize types of 'whenJust' and similar functions to return 'Monoid' #150

Open chshersh opened 6 years ago

chshersh commented 6 years ago

Currently whenJust has the following type signature:

whenJust :: Applicative f => Maybe a -> (a -> f ()) -> f ()

I propose to generalize types of whenJust and whenJustM functions to the following:

whenJust :: forall m f . (Applicative f, Monoid m) => Maybe a -> (a -> f m) -> f m

or even following:

whenJust :: Monoid m => Maybe a -> (a -> m) -> m

() has trivial Monoid instance so every existing code will work automatically. Also, IO has Monoid instance.

Drawbacks:

  1. More obscure type signature (probably?).
  2. Type errors can be hard to understand.

Advantages

  1. There's no single function to simulate foldMap :: (Monoid m, Foldable t) => (a -> m) -> t a -> m behavior for Maybe.
  2. This type signature will allow to make code like foo <- if p then listDirectory else pure [] shorter. Sometimes on Nothing case we want not only pure () but return some mempty
gromakovsky commented 6 years ago

I had an idea of doing the same for pass, but I am not sure whether it's reasonable.

int-index commented 6 years ago

When comparing

whenJust :: forall m f . (Applicative f, Monoid m) => Maybe a -> (a -> f m) -> f m

and

whenJust :: Monoid m => Maybe a -> (a -> m) -> m

note that mempty and pure mempty need not be equal, so these functions can behave differently for some instantiations of f.

chshersh commented 6 years ago

The reason for having whenJust :: Monoid m => Maybe a -> (a -> m) -> m type is because sometimes we want something like foldMap for Maybe but nobody came up with good name for this function.