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