strict-data-0.2.0.2: src/Data/Option.hs
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE DeriveFoldable #-}
{-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DeriveTraversable #-}
module Data.Option where
import Data.Fail
import Data.StrictList.Types
import Control.Applicative
import Control.DeepSeq
import Control.Monad
import Control.Monad.Trans
import Data.Aeson
import Data.Data
import Data.Hashable
import GHC.Generics (Generic)
import Safe.Plus
import Test.QuickCheck
import qualified Control.Monad.Fail as Fail
data Option a
= None
| Some !a
deriving (Show, Read, Eq, Generic, Typeable, Data, Functor, Foldable, Traversable)
instance Applicative Option where
pure = Some
{-# INLINE pure #-}
f <*> x =
case f of
Some g -> fmap g x
None -> None
{-# INLINE (<*>) #-}
instance Monad Option where
(Some x) >>= k = k x
None >>= _ = None
(>>) = (*>)
fail _ = None
instance Monoid a => Monoid (Option a) where
mempty = None
None `mappend` m = m
m `mappend` None = m
Some m1 `mappend` Some m2 = Some (m1 `mappend` m2)
instance Alternative Option where
empty = None
None <|> r = r
l <|> _ = l
instance MonadPlus Option
instance ToJSON a => ToJSON (Option a) where
toJSON = toJSON . optionToMaybe
{-# INLINE toJSON #-}
instance FromJSON a => FromJSON (Option a) where
parseJSON x = maybeToOption <$> parseJSON x
{-# INLINE parseJSON #-}
newtype OptionT m a
= OptionT
{ runOptionT :: m (Option a)
}
runOptionTDef :: Functor m => a -> OptionT m a -> m a
runOptionTDef x = fmap (fromOption x) . runOptionT
class ToOptionT t where
optionT :: Monad m => m (t a) -> OptionT m a
instance ToOptionT Maybe where
optionT = OptionT . fmap maybeToOption
instance ToOptionT Option where
optionT = OptionT
instance Functor m => Functor (OptionT m) where
fmap f = OptionT . fmap (fmap f) . runOptionT
instance (Functor m, Monad m) => Applicative (OptionT m) where
pure = return
(<*>) = ap
instance Monad m => Fail.MonadFail (OptionT m) where
fail _ = OptionT (return None)
instance Monad m => Monad (OptionT m) where
fail = safeFail
return = lift . return
x >>= f = OptionT (runOptionT x >>= option (return None) (runOptionT . f))
instance Ord a => Ord (Option a) where
compare x y =
case x of
Some a ->
case y of
Some b -> compare a b
None -> GT
None ->
case y of
None -> EQ
Some _ -> LT
instance NFData a => NFData (Option a) where
rnf None = ()
rnf (Some b) = rnf b
instance MonadTrans OptionT where
lift x = OptionT (Some <$> x)
instance (MonadIO m) => MonadIO (OptionT m) where
liftIO = lift . liftIO
instance Fail.MonadFail Option where
fail _ = None
instance Arbitrary a => Arbitrary (Option a) where
arbitrary = frequency [(1, return None), (3, Some <$> arbitrary)]
shrink (Some x) = None : [ Some x' | x' <- shrink x ]
shrink _ = []
noneIf :: (a -> Bool) -> a -> Option a
noneIf p x
| p x = None
| otherwise = Some x
fromOption :: a -> Option a -> a
fromOption def opt =
case opt of
Some x -> x
None -> def
isSome :: Option a -> Bool
isSome (Some _) = True
isSome _ = False
isNone :: Option a -> Bool
isNone None = True
isNone _ = False
optionToMaybe :: Option a -> Maybe a
optionToMaybe (Some a) = Just a
optionToMaybe None = Nothing
{-# INLINE optionToMaybe #-}
-- |
-- prop> maybeToOption (optionToMaybe x) == x
maybeToOption :: Maybe a -> Option a
maybeToOption (Just a) = Some a
maybeToOption Nothing = None
{-# INLINE maybeToOption #-}
optionToList :: Option a -> [a]
optionToList (Some a) = [a]
optionToList None = []
optionToSL :: Option a -> StrictList a
optionToSL (Some a) = a :! Nil
optionToSL None = Nil
listToOption :: [a] -> Option a
listToOption [] = None
listToOption (x:_) = Some x
getSomeNote :: Monad m => String -> Option a -> m a
getSomeNote str = option (safeFail str) return
option :: b -> (a -> b) -> Option a -> b
option def f opt =
case opt of
Some a -> f $! a
None -> def
catOptions :: [Option a] -> [a]
catOptions ls = [x | Some x <- ls]
mapOption :: (a -> Option b) -> [a] -> [b]
mapOption _ [] = []
mapOption f (x:xs) =
let rs = mapOption f xs in
case f x of
None -> rs
Some r -> r : rs
instance Hashable a => Hashable (Option a)
forOptionM :: Monad m => [a] -> (a -> OptionT m b) -> m [b]
forOptionM xs f = catOptions <$> forM xs (runOptionT . f)
mapOptionM :: Monad m => (a -> OptionT m b) -> [a] -> m [b]
mapOptionM = flip forOptionM
safeFromSome :: Option a -> a
safeFromSome = fromOption (safeError "fromSome is None!")
failToOption :: Fail a -> Option a
failToOption (Ok x) = Some x
failToOption _ = None
optionToFail :: String -> Option a -> Fail a
optionToFail _ (Some x) = Ok x
optionToFail err None = Fail err
optionToFailT :: Monad m => String -> Option a -> FailT m a
optionToFailT _ (Some x) = return x
optionToFailT err None = safeFail err