Неправильно рассматривать чисто техническую конструкцию как какие-то рецепты или другие аналогии.
Давай посмотрим как IO устроен: это банально тип вида
newtype IO a
= GHC.Types.IO (GHC.Prim.State# GHC.Prim.RealWorld
-> (# GHC.Prim.State# GHC.Prim.RealWorld, a #))
Просто функция с каким-то риалворд токеном, который определяет порядок выполнения действий и обеспечивает ссылочную прозрачность по её определению