Thread the explicit program state through the computation, using the base computational monad to sequence its effects:
In Haskell notation, with resultM and bindM standing for the base operations:
result :: Monad m => a -> MemT m a
result x s = resultM (x,s)

bind :: Monad m => MemT m a -> (a -> MemT m b) -> MemT m b
bind p f s = bindM (p s) (\(x,s') -> f x s')
This is the state monad transformer. The first computation's final program state, rather than its initial program state, becomes the second computation's input. The base computational monad decides whether that pair is available at all.
Reading preserves the computer memory; writing returns the unit type value; allocating returns both the fresh memory location and the allocator's updated computer memory:
get :: Monad m => Location -> MemT m Value
get a s = resultM (contents s a,s)

put :: Monad m => Location -> Value -> MemT m ()
put a v s = resultM ((),update s a v)

new :: Monad m => MemT m Location
new s = resultM (fresh s)
These use the memory interface in [ref]. In particular, fresh already returns its outputs in the order required by the state monad transformer: