The Either type represents values with two possibilities: a value of
type Either a b is either Left a or Right b.
The Either type is sometimes used to represent a value which is either correct or an error; by convention, the Left constructor is used to hold an error value and the Right constructor is used to hold a correct value (mnemonic: "right" also means "correct").
Examples
The type Either String Int is the type of values which can be either
a String or an Int. The Left constructor can be used only on
Strings, and the Right constructor can be used only on Ints:
let s = Left "foo" :: Either String IntsLeft "foo"let n = Right 3 :: Either String IntnRight 3:type ss :: Either String Int:type nn :: Either String Int
The fmap from our Functor instance will ignore Left values, but will apply the supplied function to values contained in a Right:
let s = Left "foo" :: Either String Intlet n = Right 3 :: Either String Intfmap (*2) sLeft "foo"fmap (*2) nRight 6
The Monad instance for Either allows us to chain together multiple actions which may fail, and fail overall if any of the individual steps failed. First we'll write a function that can either parse an Int from a Char, or fail.
import Data.Char ( digitToInt, isDigit ):{ let parseEither :: Char -> Either String Int parseEither c | isDigit c = Right (digitToInt c) | otherwise = Left "parse error":}
The following should work, since both '1' and '2' can be
parsed as Ints.
:{ let parseMultiple :: Either String Int parseMultiple = do x <- parseEither '1' y <- parseEither '2' return (x + y):}
parseMultipleRight 3
But the following should fail overall, since the first operation where
we attempt to parse 'm' as an Int will fail:
:{ let parseMultiple :: Either String Int parseMultiple = do x <- parseEither 'm' y <- parseEither '2' return (x + y):}
parseMultipleLeft "parse error"
Instances16Generic1, Monad, Functor, MonadFix, Applicative, Foldable, …
Generic1 (Either a)Defined in ghc-internal-9.1003.0 · GHC.Internal.GenericsMonad (Either e)Defined in ghc-internal-9.1003.0 · GHC.Internal.Data.EitherFunctor (Either a)Defined in ghc-internal-9.1003.0 · GHC.Internal.Data.EitherMonadFix (Either e)Defined in ghc-internal-9.1003.0 · GHC.Internal.Control.Monad.FixApplicative (Either e)Defined in ghc-internal-9.1003.0 · GHC.Internal.Data.EitherFoldable (Either a)Defined in ghc-internal-9.1003.0 · GHC.Internal.Data.FoldableTraversable (Either a)Defined in ghc-internal-9.1003.0 · GHC.Internal.Data.Traversable(Eq a, Eq b) => Eq (Either a b)Defined in ghc-internal-9.1003.0 · GHC.Internal.Data.Either(Data a, Data b) => Data (Either a b)Defined in ghc-internal-9.1003.0 · GHC.Internal.Data.Data(Ord a, Ord b) => Ord (Either a b)Defined in ghc-internal-9.1003.0 · GHC.Internal.Data.Either(Read a, Read b) => Read (Either a b)Defined in ghc-internal-9.1003.0 · GHC.Internal.Data.Either(Show a, Show b) => Show (Either a b)Defined in ghc-internal-9.1003.0 · GHC.Internal.Data.EitherGeneric (Either a b)Defined in ghc-internal-9.1003.0 · GHC.Internal.GenericsSemigroup (Either a b)Defined in ghc-internal-9.1003.0 · GHC.Internal.Data.Eithertype Rep (Either a b) = D1 ('MetaDataDefined in ghc-internal-9.1003.0 · GHC.Internal.Generics"Either"
"GHC.Internal.Data.Either"
"ghc-internal"
'False) (C1 ('MetaCons"Left"
'PrefixI 'False) (S1 ('MetaSel 'Nothing 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 a)) :+: C1 ('MetaCons"Right"
'PrefixI 'False) (S1 ('MetaSel 'Nothing 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 b)))type Rep1 (Either a) = D1 ('MetaDataDefined in ghc-internal-9.1003.0 · GHC.Internal.Generics"Either"
"GHC.Internal.Data.Either"
"ghc-internal"
'False) (C1 ('MetaCons"Left"
'PrefixI 'False) (S1 ('MetaSel 'Nothing 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 a)) :+: C1 ('MetaCons"Right"
'PrefixI 'False) (S1 ('MetaSel 'Nothing 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) Par1))