I've recently stumbled over the generic Control.Applicative.optional combinator:
optional :: Alternative f => f a -> f (Maybe a)
optional v = Just <$> v <|> pure Nothing
but I don't much practical use for that combinator; e.g. when applied to pure functors such as lists or Maybe, the results don't seem very useful:
> optional [1,2,3]
[Just 1,Just 2,Just 3,Nothing]
> optional Nothing
Just Nothing
> optional (Just 1)
Just (Just 1)
...what would be more sensible applications of optional?
It is useful for modelling any computation that is allowed to fail.
For example, let's say that you are dealing with STM and have these functions:
-- A database of Ints stored in a TVar
intDatabase :: TVar (ComplexDatabaseStructure Int)
-- Inserts an Int in the int database.
insertInt :: Int -> STM ()
-- Organizes the DB so that it is more efficient
optimizeDb :: STM ()
-- Checks whether an Int is in the DB
lookupInt :: Int -> STM Bool
Now, optimization is nice to do after inserts, but it isn't critical. So you could see this usage:
insert2AndCheck1 a b c =
  insertInt a *> insertInt b *> optional optimizeDb *> lookupInt c
This function inserts two ints, then tries to optimize the DB, but if it fails (because of STM reasons, like that someone was inserting something at the time), it isn't a big deal; we just go on anyways.
optional works with STM, and also any error monad in Control.Monad.Error, and a lot of different things; certainly also for pure computations.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With