Instantly share code, notes, and snippets.

# singpolyma/CollectLeft.hs Created Sep 8, 2012

Alternative Applicative instance for Either that collects multiple Left values
 import Data.Monoid import Control.Applicative newtype CollectLeft es a = CollectLeft (Either es a) deriving (Show, Eq) -- Alternative applicative instance for Either with a Monoid on the Left -- If everything is Right, then it acts like the normal instance -- Instead of resulting in the first Left, the values inside all Left are -- concatenated (any Monoid) instance (Monoid es) => Applicative (CollectLeft es) where pure = CollectLeft . Right CollectLeft (Right f) <*> CollectLeft (Right b) = CollectLeft \$ Right (f b) CollectLeft (Right _) <*> CollectLeft (Left es) = CollectLeft (Left es) CollectLeft (Left es) <*> CollectLeft (Right _) = CollectLeft (Left es) CollectLeft (Left es) <*> CollectLeft (Left ds) = CollectLeft \$ Left (es `mappend` ds) -- Every Applicative is a Functor instance (Monoid es) => Functor (CollectLeft es) where fmap f x = pure f <*> x -- lift an Either into this alternate instance -- Instead of taking an Either with a Monoid on the Left, -- this actually takes any Either and pure's it into a Monoid -- (must be both Monoid and Applicative so values can be injected) collectEither :: (Monoid (es a), Applicative es) => Either a b -> CollectLeft (es a) b collectEither (Left e) = CollectLeft (Left \$ pure e) collectEither (Right a) = CollectLeft (Right a) -- Extractor because we had to use a newtype runCollectLeft :: CollectLeft es a -> Either es a runCollectLeft (CollectLeft either) = either

### yairchu commented Sep 10, 2012

 You can do newtype CollectLeft es a = CollectLeft { runCollectLeft :: Either es a } instead of defining the extractor