Proving functional correctness of monadic programs using separation logic