Either and recoverable errors

Contents
Two sides
A parsing example
either and chain
Either or exceptions

Two sides

Maybe says that something failed but not why. Either carries a reason on the left and the result on the right:

data Either a b = Left a | Right b half :: Int -> Either String Int half n | even n = Right (n `div` 2) | otherwise = Left "odd number"

By convention Left is the failure and Right is the success, which is why mapping over an Either touches only the right side.

A parsing example

Reading a number from text is the classic fallible step. With readMaybe the failure is explicit, and the message can say what was wrong:

import Text.Read (readMaybe) parseAge :: String -> Either String Int parseAge s = case readMaybe s of Nothing -> Left ("not a number: " ++ s) Just n | n < 0 -> Left "negative age" | otherwise -> Right n

The signature promises a number or a message, and the caller cannot ignore the second possibility without writing a branch for it.

either and chain

The either function collapses both sides into one type, and >>= chains fallible steps while keeping the first error:

either length id (Right "abc") -- 3 either length id (Left "bad") -- 3 chain s = parseAge s >>= half -- chain "42" == Right 21 -- chain "x" == Left "not a number: x"

Note that half takes an Int and returns Either String Int, while parseAge already returns that type. The operator is what makes the two fit together.

Either or exceptions

An exception is invisible in the signature and can escape from any call. An Either is in the type, so the compiler knows about it and the caller must decide. Lesson 46 covers the cases where exceptions are still the right tool.

-- invisible failure readAge :: String -> Int -- failure is part of the contract readAge :: String -> Either String Int

Prefer the second in library code and at module boundaries. Keep the first for a scratch script where a crash is an acceptable answer.

Next: data: product types

Article author: Arthur Isaev

Related articles
Haskell
Haskell course: zero to hero in 50 lessons
What is Haskell and why it matters
Install the toolchain with GHCup
GHCi: the interactive shell
Your first program
Values with let and where
Types and type signatures
Functions and application
Currying and partial application
Operators, sections, and fixity
if, guards, and pattern guards
case expressions
Pattern matching
Tuples
Lists
Ranges and enumeration
List comprehensions
Recursion replaces loops
map, filter, and foldr
Lambdas and composition
Type classes
Parametric polymorphism
Maybe and null safety
Either and recoverable errors
data: product types
data: sum types
Records
newtype and type synonyms
Recursive data: binary trees
Functor
Applicative
Monad
do notation
IO and purity
Files and IO
Modules and imports
Cabal projects
Dependencies
Testing with HUnit
Property testing with QuickCheck
Laziness and infinite lists
Strictness and space leaks
Folds
Monoids
Traversable
Monad transformers
Errors and exceptions
Concurrency
Parsing with Megaparsec
Capstone: a todo CLI
Hero roadmap: the whole course on one page

Search this site

Channel @aofeed Chat @aofeedchat

Contacts and cooperation:
I recommend our hosting beget.com
Write to info@aredel.com if you:
1. Want to write an article for our site or translate an article into your native language.
2. Want to place thematically relevant ads on the site.
3. Ads on my site pass maximum censorship. If you see an ad block unsuitable for school-age children, shocking or misleading - please contact us by e-mail
4. Found a mistake, inaccuracy, bug, etc. on the site. ... .......
5. Articles can be shared on social media by clicking a network icon: