In chapter 1, we introduced the concept of referential transparency, setting the premise for purely functional programming. We declared that pure functions can’t mutate data in place or interact with the external world. In chapter 13, we learned that this isn’t exactly true. We can write purely functional and compositional programs that describe interactions with the outside world. These programs are unaware that they can be evaluated with an interpreter that has an effect on the world.