IO is a container for an effect: instead of reading from or writing to the outside world immediately, it stores a function that will perform that work later. This keeps side-effecting steps available as values that can be passed through a functional program. section 5.3
Create an IO value with IO.from for an effect function or IO.of for an existing value. Use map to describe a transformation of the eventual result without running it. Calling run is the explicit boundary where the stored effect happens. section 5.3
Read, transform, then write a DOM value
A DOM update can be assembled without changing the page during construction. readDom returns a deferred read; the first map converts the name to start case; the second maps the result into a deferred write. The page changes only when run is called. section 5.3
<div id="student-name">alonzo church</div>
const changeToStartCase =
IO.from(readDom('student-name')).
map(_.startCase). #1
map(writeDom('student-name'));
This pipeline makes the delay visible: reading, formatting, and writing are described first, while execution is left to run. section 5.3
IO can mark the final effectful step of a larger safe pipeline. After input cleaning, validation, lookup, and formatting use Maybe or Either to handle missing or invalid data, liftIO wraps the resulting value so the composed program still returns an IO action. section 5.4
The small IO interface separates description from execution:
- effect holds the function that performs the effect later. section 5.3
- map returns a new IO whose effect applies a function to the previous result. section 5.3
- chain passes the executed result to a function that returns the next value. section 5.3
- run invokes the stored effect at the chosen program boundary. section 5.3





