Reasoning about imperative and higher-order programs