alms-0.6.0: src/Data/Perhaps.hs
-- | Like maybe, but 'Eq' and 'Ord' instances are collapsed so that all
-- values of type @Perhaps a@ are equal. Useful for hiding optional
-- information from derived instances in other datatypes.
module Data.Perhaps (
Perhaps(..),
catPerhaps, mapPerhaps,
fromHere, fromPerhaps, isHere, isNope,
listToPerhaps, perhapsToList, perhapsToMaybe, maybeToPerhaps,
) where
import Control.Applicative
import Control.Arrow
import Control.Monad
import Control.Monad.Fix
import Data.Monoid
import Data.OptionalClass
import Data.Generics (Typeable, Data)
-- | This is like @Maybe@, except all values of the type compare as
-- equal, which is useful for “suggestions” in the syntax that have
-- no semantic significance.
data Perhaps a
= Nope
| Here a
deriving (Functor, Typeable, Data)
instance Optional Perhaps where
foldOpt = perhaps
optSome = Here
optNone = Nope
perhaps ∷ b → (a → b) → Perhaps a → b
perhaps nope _ Nope = nope
perhaps _ here (Here x) = here x
catPerhaps ∷ [Perhaps a] → [a]
catPerhaps = foldr (perhaps id (:)) []
fromHere ∷ Perhaps a → a
fromHere = perhaps (error "fromHere: got Nope") id
fromPerhaps ∷ a → Perhaps a → a
fromPerhaps = flip perhaps id
isHere, isNope ∷ Perhaps a → Bool
isHere = perhaps False (const True)
isNope = not . isHere
listToPerhaps ∷ [a] → Perhaps a
listToPerhaps = foldr (const . Here) Nope
mapPerhaps ∷ (a → Perhaps b) → [a] → [b]
mapPerhaps f = foldr (perhaps id (:) . f) []
perhapsToList ∷ Perhaps a → [a]
perhapsToList = perhaps [] (:[])
perhapsToMaybe ∷ Perhaps a → Maybe a
perhapsToMaybe = perhaps Nothing Just
maybeToPerhaps ∷ Maybe a → Perhaps a
maybeToPerhaps = maybe Nope Here
instance Eq (Perhaps a) where
_ == _ = True
instance Monad Perhaps where
return = Here
(>>=) = perhaps (const Nope) (flip ($))
instance Ord (Perhaps a) where
_ `compare` _ = EQ
instance Read a ⇒ Read (Perhaps a) where
readsPrec p s = case readsPrec p s of
[] → [ (Nope, s) ]
xs → map (first Here) xs
instance Show a ⇒ Show (Perhaps a) where
showsPrec = perhaps id . showsPrec
instance MonadFix Perhaps where
mfix f = let a = f (unHere a) in a
where unHere (Here x) = x
unHere Nope = error "mfix Perhaps: Nope"
instance MonadPlus Perhaps where
mzero = Nope
mplus = perhaps id (const . Here)
instance Applicative Perhaps where
pure = return
(<*>) = ap
instance Monoid a ⇒ Monoid (Perhaps a) where
mempty = Nope
Here x1 `mappend` Here x2 = Here (x1 `mappend` x2)
p1 `mappend` Nope = p1
Nope `mappend` p2 = p2
instance Alternative Perhaps where
empty = mzero
(<|>) = mplus