  Lazy evaluation is a powerful tool that enables better compositionality and
potentially better performance in functional programming, but it is challenging
to analyze its computation cost. Existing works either require manually
annotating sharing, or rely on separation logic to reason about heaps of
mutable cells. In this paper, we propose a bidirectional demand semantics that
allows for extrinsic reasoning about the computation cost of lazy programs
without relying on special program logics. To show the effectiveness of our
approach, we apply the demand semantics to a variety of case studies including
insertion sort, selection sort, Okasaki's banker's queue, and the implicit
queue. We formally prove that the banker's queue and the implicit queue are
both amortized and persistent using the Rocq Prover (formerly known as Coq). We
also propose the reverse physicist's method, a novel variant of the classical
physicist's method, which enables mechanized, modular and compositional
reasoning about amortization and persistence with the demand semantics.
