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:
Apply the memory interface before invoking the supplied continuation:
get :: Location -> M Value
get a k s = k (contents s a) s

put :: Location -> Value -> M ()
put a v k s = k () (update s a v)

new :: M Location
new k s = let (a,s') = fresh s in k a s'
A read preserves computer memory; a write changes it but returns the unit type value; an allocation uses the updated computer memory returned by fresh. The continuation always receives the latest computer memory: