The railway pattern
The railway pattern is a way of chaining operations where each might fail. It is called railway because there are two tracks in this pattern.
- The first track is the happy path
- The second track is the error track
If any of the chained functions fails we move to the error track. From there we get an error at the end of the railway.
For example, let say we want to:
- Parse some external data
- Validate the parsed data
- Transform the data into something else
parseData : String -> Result String ParsedData
validateData : ParsedData -> Result String ValidData
transformData : ValidData -> Result String TransformedData
Pattern
In Elm this is commonly done using Maybe.andThen
and Result.andThen
. These function will run the next function in the chain if the previous function was successful, otherwise they will propagate the error.
process : String -> Result String TransformedData
process data =
parseData data
|> Result.andThen validateData
|> Result.andThen transformData
Here is an excellent post about this with a lot more details.
Variant
A variant of this is where the second track doesn't represent an error, but rather an early exit.
E.g. This process finds recommendations for a user. Each function in the chain can add to the recommendations or choose to exit the process.
type Process
= Continue Recommendation
| Exit Recommendation
andThen : (Recommendation -> Process) -> Process -> Process
andThen callback process =
case process of
Continue document -> callback document
Exit document -> Exit document
findRecommendations user =
Continue emptyRecommendation
|> andThen (findMusic user)
|> andThen (findBooks user)
|> andThen (findMovies user)
|> andThen (findGames user)
findMusic : User -> Recommendation -> Process
...
andThen
is a function that mirrors Result.andThen
but specific for Process
.