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"
Instances72Bifoldable, Bifoldable1, Bitraversable, Eq2, Ord2, Read2, …
Bifoldable EitherDefined in base-4.20.2.0 · Data.BifoldableBifoldable1 EitherDefined in base-4.20.2.0 · Data.Bifoldable1Bifunctor EitherDefined in base-4.20.2.0 · Data.BifunctorBitraversable EitherDefined in base-4.20.2.0 · Data.BitraversableEq2 EitherDefined in base-4.20.2.0 · Data.Functor.ClassesOrd2 EitherDefined in base-4.20.2.0 · Data.Functor.ClassesRead2 EitherDefined in base-4.20.2.0 · Data.Functor.ClassesShow2 EitherDefined in base-4.20.2.0 · Data.Functor.ClassesNFData2 EitherDefined in deepseq-1.5.0.0 · Control.DeepSeqArbitrary2 EitherDefined in QuickCheck-2.15.0.1 · Test.QuickCheck.ArbitraryHashable2 EitherDefined in hashable-1.4.7.0 · Data.Hashable.ClassBifunctor EitherDefined in linear-base-0.4.0 · Data.Bifunctor.Linear.Internal.BifunctorSymmetricMonoidal Either VoidDefined in linear-base-0.4.0 · Data.Bifunctor.Linear.Internal.SymmetricMonoidalApplicative f => Strong Either Void (Kleisli f)Defined in linear-base-0.4.0 · Data.Profunctor.LinearApplicative f => Strong Either Void (Kleisli f)Defined in linear-base-0.4.0 · Data.Profunctor.Kleisli.LinearStrong Either Void (CoKleisli (Const x))Defined in linear-base-0.4.0 · Data.Profunctor.Kleisli.LinearFunctor f => Monoidal Either Void (Kleisli f)Defined in linear-base-0.4.0 · Data.Profunctor.LinearFunctor f => Monoidal Either Void (Kleisli f)Defined in linear-base-0.4.0 · Data.Profunctor.Kleisli.LinearStrong Either Void (->)Defined in linear-base-0.4.0 · Data.Profunctor.LinearStrong Either Void (Market a b)Defined in linear-base-0.4.0 · Data.Profunctor.LinearMonoidal Either Void (->)Defined in linear-base-0.4.0 · Data.Profunctor.LinearStrong Either Void (FUN 'One)Defined in linear-base-0.4.0 · Data.Profunctor.LinearMonoidal Either Void (FUN 'One)Defined in linear-base-0.4.0 · Data.Profunctor.LinearGeneric1 (Either a)Defined in ghc-internal-9.1003.0 · GHC.Internal.GenericsMonadError e (Either e)Defined in mtl-2.3.1 · Control.Monad.Error.ClassGeneric1 (Either a)Defined in linear-generics-0.2.3 · Generics.Linear.Instances.Base · orphan(Lift a, Lift b) => Lift (Either a b)Defined in template-haskell-2.22.0.0 · Language.Haskell.TH.SyntaxMonad (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.TraversableEq a => Eq1 (Either a)Defined in base-4.20.2.0 · Data.Functor.ClassesOrd a => Ord1 (Either a)Defined in base-4.20.2.0 · Data.Functor.ClassesRead a => Read1 (Either a)Defined in base-4.20.2.0 · Data.Functor.ClassesShow a => Show1 (Either a)Defined in base-4.20.2.0 · Data.Functor.ClassesNFData a => NFData1 (Either a)Defined in deepseq-1.5.0.0 · Control.DeepSeqArbitrary a => Arbitrary1 (Either a)Defined in QuickCheck-2.15.0.1 · Test.QuickCheck.Arbitrarye ~ SomeException => MonadCatch (Either e)Defined in exceptions-0.10.9 · Control.Monad.Catche ~ SomeException => MonadMask (Either e)Defined in exceptions-0.10.9 · Control.Monad.Catche ~ SomeException => MonadThrow (Either e)Defined in exceptions-0.10.9 · Control.Monad.CatchHashable a => Hashable1 (Either a)Defined in hashable-1.4.7.0 · Data.Hashable.ClassFunctor (Either e)Defined in linear-base-0.4.0 · Data.Functor.Linear.Internal.FunctorTraversable (Either a)Defined in linear-base-0.4.0 · Data.Functor.Linear.Internal.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.Either(NFData a, NFData b) => NFData (Either a b)Defined in deepseq-1.5.0.0 · Control.DeepSeq(Pretty a, Pretty b) => Pretty (Either a b)Defined in pretty-1.1.3.6 · Text.PrettyPrint.Annotated.HughesPJClass(Pretty a, Pretty b) => Pretty (Either a b)Defined in pretty-1.1.3.6 · Text.PrettyPrint.HughesPJClass(Finite a, Finite b) => Finite (Either a b)Defined in random-1.2.1.3 · System.Random.GFinite(Arbitrary a, Arbitrary b) => Arbitrary (Either a b)Defined in QuickCheck-2.15.0.1 · Test.QuickCheck.Arbitrary(CoArbitrary a, CoArbitrary b) => CoArbitrary (Either a b)Defined in QuickCheck-2.15.0.1 · Test.QuickCheck.Arbitrary(Function a, Function b) => Function (Either a b)Defined in QuickCheck-2.15.0.1 · Test.QuickCheck.Function(Binary a, Binary b) => Binary (Either a b)Defined in binary-0.8.9.3 · Data.Binary.Class(Hashable a, Hashable b) => Hashable (Either a b)Defined in hashable-1.4.7.0 · Data.Hashable.ClassGeneric (Either a b)Defined in linear-generics-0.2.3 · Generics.Linear.Instances.Base · orphan(Consumable e, Consumable a) => Consumable (Either e a)Defined in linear-base-0.4.0 · Data.Unrestricted.Linear.Internal.Consumable(Dupable a, Dupable b) => Dupable (Either a b)Defined in linear-base-0.4.0 · Data.Unrestricted.Linear.Internal.Dupable(Consumable a, Consumable b) => Semigroup (Either a b)Defined in linear-base-0.4.0 · Data.Monoid.Linear.Internal.Semigroup(Movable a, Movable b) => Movable (Either a b)Defined in linear-base-0.4.0 · Data.Unrestricted.Linear.Internal.Movable(Consumable a, Consumable b, Eq a, Eq b) => Eq (Either a b)Defined in linear-base-0.4.0 · Data.Ord.Linear.Internal.Eq(Consumable a, Consumable b, Ord a, Ord b) => Ord (Either a b)Defined in linear-base-0.4.0 · Data.Ord.Linear.Internal.Ordtype 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))type Rep (Either a b) = D1 ('MetaDataDefined in linear-generics-0.2.3 · Generics.Linear.Instances.Base · orphan"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 linear-generics-0.2.3 · Generics.Linear.Instances.Base · orphan"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))