Make an invalid state unrepresentable at the interface
A result type makes success and failure explicit in a function’s interface. In Haskell, Either lets callers distinguish failures by constructor while still requiring validation at untrusted input boundaries.
A Boolean leaves the result implicit
Imagine a lookup function that returns a String and also writes a Boolean flag saying whether the lookup worked. The caller must remember that the string is meaningful only when the flag is true. If the caller forgets, a failure can be mistaken for a successful empty string. Returning a sentinel string such as "MISSING" has a related problem: that value might also be legitimate data, and every caller must know the hidden convention.
The interface has two pieces whose meaning depends on each other. A better type puts the alternatives in one value: either a failure description or a successful result. Haskell’s standard Either type has two constructors, Left and Right, and its parameters let a function choose the types carried by each branch. [1]
Encode the alternatives in the type
For a file lookup, define a small error type with Missing and Unreadable constructors. The lookup can then return Either LookupError String. This type says that every ordinary result is either an error value or text. The example defines how to render each case: Left Missing becomes “No entry,” Left Unreadable becomes “Entry cannot be read,” and Right text passes the content through unchanged.
The important design decision is visible in the function signature. A caller cannot receive a plain String from this function without first handling or transforming the Either value. Pattern matching names each supported outcome, so adding a new error constructor can expose places that need a deliberate response. The Haskell report defines Either as Left a or Right b; using the left side for errors and the right side for success is a convention, not a restriction built into the datatype.
data LookupError = Missing | Unreadable
deriving (Eq, Show)
render :: Either LookupError String -> String
render (Left Missing) = "No entry"
render (Left Unreadable) = "Entry cannot be read"
render (Right text) = text
The supplied renderer is an exhaustive decision point
The renderer’s three patterns correspond to the two error constructors and the success constructor. Give it Left Missing and it produces the missing-entry message; give it Left Unreadable and it produces the read-failure message; give it Right text and it returns that text. Its output is always a String, so it turns a structured outcome into presentation text at a boundary where that loss of structure is intentional.
A downstream layer may prefer to preserve the error distinction instead. It could log Missing differently from Unreadable, retry an unreadable entry, or map both to a broader application error. The algebraic value keeps those choices available until the program chooses to collapse them. That is the practical benefit: the type makes the branch explicit, while pattern matching makes the policy visible where it is applied.
Types do not validate raw input by themselves
An interface can constrain values after construction, but it cannot establish that arbitrary bytes or user input already satisfy the domain rules. A parser still needs to reject malformed data and check conditions such as required fields, allowed ranges, or whether a referenced file exists. Its result can itself use Either, but the validation is work performed by the parser, not a magical property of the type.
Likewise, wrapping a String in a newtype can give it a distinct compile-time identity, but the wrapper does not automatically check that the string is a valid path, username, or identifier. A constructor or smart function must perform that check before producing the domain value, and the program must control which construction paths are exposed if the invariant matters. The design goal is precise: represent validated states clearly and make ordinary callers handle alternatives, while keeping validation at the boundary that receives untrusted values.