Either: errors that carry a message
When a failure needs to explain itself, Either brings the reason back as a value: one half for the problem, one half for the answer, both written in the type.
A failure that carries a reason
Maybe tells the caller that there is no answer, and nothing more. Either tells them why as well: Left reason is the failure and Right value is the good answer. A type like Either String Int names both possibilities, and the reason travels with the value.
Both halves are ordinary values, so an Either can be stored in a list, mapped over with a function, or handed to another function that expects one. Nothing about it is special to printing or to errors.
One place decides what counts as wrong
A function like checkQty decides, once, what a valid quantity is, and answers either the number or a sentence describing the problem. Every caller then gets the same treatment, and no rule is repeated in two places where the two copies could drift apart.
Nothing stops the program on the way, so a failed check is just a value that flows back up. The caller decides whether to print a line, use a default, or hand the problem on.
Chaining checks
A case with one branch for each half is how one check is followed by another: if the first half is a Left, it is passed straight on, and only a Right continues to the next step. Written out, that shape is short and very easy to read.
The type of the failing half can be anything: a text message, a number for a log, or a type of your own for errors that a program handles. The convention is only that Left carries the problem and Right carries the answer.
A check and a report
half :: Int -> Either String Int
half n
| mod n 2 == 0 = Right (div n 2)
| otherwise = Left "odd numbers have no half"
report :: Either String Int -> String
report (Left why) = "problem: " ++ why
report (Right v) = "answer: " ++ show vA quantity check with a reason
Run it and read the three lines. Then add a third rule that rejects a quantity above 200, and work out what the report says for a quantity of 150.
Left for the problem and Right for the answer is a convention, not a rule of the language: the names come from a time when a correct answer was the right one. What matters is that you pick one meaning and keep it the same everywhere in a program.
Two constructors, two jobs
Left and Right are constructors of one type, exactly like Circle and Rect in the chapter before. A value of Either String Int is either a Left holding text or a Right holding a number, and a function that uses it writes a branch for each.
The type has two parameters because the halves can be different types: the first is the failure, the second is the answer. Reading Either String Int aloud as either a text reason or an integer is the habit that makes these signatures easy to scan.
Nothing in the type forces Left to mean failure. The convention is strong and worth keeping, because a program in which the two halves swap meaning is still type-correct and completely wrong.
Prelude has a helper for the common shape: either takes a function for the Left, a function for the Right, and the value, and answers whichever applies. either length show (Left "no") is 2, and the same call on Right 42 is the text 42. It is the two-branch case written as one expression, and it is the quickest way to turn an Either into a report line when both branches already have a function.
The two functions may take different types, one for each half, but they must answer the same type, because either has to produce one value whichever branch runs. That is the same rule as an if, applied to two constructors instead of two conditions.
Chaining keeps the same error type
Following one check with another is a case: a Left is passed straight on, and a Right goes into the next step. The result is a short function that reads like the list of rules it enforces.
For that to work, every step has to agree on the type of the failing half. A check answering Either String Int and another answering Either Int Int cannot be chained without converting one of them, because the two Left values are different types.
Deciding that type once, usually a text message or a type of your own for errors a program handles, keeps a chain of checks from becoming a chain of conversions. The answer type may change from step to step; the failure type stays put.
If Left and Right swap meaning halfway through a program, the types still line up and the report will call every failure a success, so choose the convention once. Returning Right when a check fails hides the problem from every caller, which is worse than stopping. And printing an Either with show gives Left "..." with the quotes still on, so write a report function for anything a reader sees.
Try these next
- Add a check that rejects a quantity which is not a multiple of 5, and decide which branch it belongs in.
- Write
boththat runs two checks and answers the first failure, or both answers as a pair. - Change the failure type to a number and update every signature and message to match.
A check that builds a record
Run it and read the three lines. Then add a rule that rejects a name shorter than two letters, and move the check so both rules report through the same `Left`.
Check what you learned
One question at a time. A wrong answer explains itself — take another go.
Part 1 of 5
In Either String Int, which half carries the failure?
