{-# LANGUAGE DeriveDataTypeable #-} module Data.Choice where import Control.DeepSeq (NFData(..)) import Data.Bifunctor import Data.Data import Data.Hashable import Safe.Plus import Test.QuickCheck -- | 'Choice' is a version of 'Either' that is strict on both the 'Left' side (called 'This') -- and the 'Right' side (called 'That'). -- -- Note: 'Choice' is not used as an error monad. Use 'Data.Fail.Fail' for that. data Choice a b = This !a | That !b deriving (Eq, Ord, Read, Show, Typeable, Data) -- | 'Choice''s version of 'either' choice :: (a -> c) -> (b -> c) -> Choice a b -> c choice fa fb = mergeChoice . bimap fa fb -- | -- >>> this (This "foo") :: Maybe String -- Just "foo" -- -- >>> this (That "bar") :: Maybe String -- Nothing this :: Monad m => Choice a b -> m a this (This a) = return a this _ = safeFail "This is a that" -- | -- >>> that (This "foo") :: Maybe String -- Nothing -- -- >>> that (That "bar") :: Maybe String -- Just "bar" that :: Monad m => Choice a b -> m b that (That a) = return a that _ = safeFail "That is a this" -- | -- >>> these [This "foo", This "bar", That "baz", This "quux"] -- ["foo","bar","quux"] these :: [Choice a b] -> [a] these = concatMap this -- | -- >>> those [This "foo", This "bar", That "baz", This "quux"] -- ["baz"] those :: [Choice a b] -> [b] those = concatMap that -- | -- >>> eitherToChoice (Left 1) -- This 1 -- -- >>> eitherToChoice (Right 5) -- That 5 eitherToChoice :: Either a b -> Choice a b eitherToChoice = either This That -- | -- >>> mergeChoice (This 5 :: Choice Int Int) -- 5 -- -- >>> mergeChoice (That 'c' :: Choice Char Char) -- 'c' mergeChoice :: Choice a a -> a mergeChoice x = case x of This y -> y That y -> y instance Bifunctor Choice where bimap f g x = case x of This a -> This (f a) That b -> That (g b) instance (Hashable a, Hashable b) => Hashable (Choice a b) where hashWithSalt s (This x) = s `hashWithSalt` (0 :: Int) `hashWithSalt` x hashWithSalt s (That x) = s `hashWithSalt` (1 :: Int) `hashWithSalt` x instance Applicative (Choice e) where pure = That This e <*> _ = This e That f <*> r = fmap f r instance Functor (Choice a) where fmap = second instance Monad (Choice e) where return = That This l >>= _ = This l That r >>= k = k r instance (Arbitrary a, Arbitrary b) => Arbitrary (Choice a b) where arbitrary = do bool <- arbitrary if bool then fmap This arbitrary else fmap That arbitrary shrink (This a) = map This $ shrink a shrink (That b) = map That $ shrink b instance (NFData a, NFData b) => NFData (Choice a b) where rnf (This x) = rnf x rnf (That y) = rnf y