
Just do It: Simple Monadic Equational Reasoning Jeremy Gibbons and Ralf Hinze Department of Computer Science, University of Oxford Wolfson Building, Parks Road Oxford, OX1 3QD, England http://www.cs.ox.ac.uk/fjeremy.gibbons,ralf.hinzeg/ Abstract Nevertheless, little work has been done on the combination of One of the appeals of pure functional programming is that it is so equational reasoning and programs exhibiting computational ef- amenable to equational reasoning. One of the problems of pure fects. Current practice involves simulating an effectful computation functional programming is that it rules out computational effects. as a pure function, and conducting the reasoning on this pure value; Moggi and Wadler showed how to get round this problem by us- for example, a recent paper by Hutton and Fulger [9] presents a ing monads to encapsulate the effects, leading in essence to a phase proof of correctness of a stateful computation using equational rea- distinction—a pure functional evaluation yielding an impure im- soning in terms of pure state-transforming functions. This works, perative computation. Still, it has not been clear how to reconcile but it is unsatisfactory in a number of ways: for one thing, it that phase distinction with the continuing appeal of functional pro- breaches the abstraction boundary provided by the monadic inter- gramming; does the impure imperative part become inaccessible face, inhibiting any reuse of proof efforts across programs using to equational reasoning? We think not; and to back that up, we different classes of effect; and for another, not all computational present a simple axiomatic approach to reasoning about programs effects can be adequately simulated in this way. with computational effects. In this paper, we present a simple axiomatic approach to equa- tional reasoning with monadic programs, preserving the monadic Categories and Subject Descriptors D.2.4 [Software/Program abstraction. The key idea is to exploit the algebraic properties of Verification]: Correctness proofs, Programming by contract; F.3.1 both the generic monad interface (the ‘return’ and ‘bind’ operators, [Specifying and Verifying and Reasoning about Programs]: Asser- and their associativity and unit laws) and the specific operations tions, Logics of programs, Pre- and post-conditions, Specification used to support a particular class of effects (for example, the ‘put’ techniques; F.3.3 [Studies of Program Constructs]: Functional and ‘get’ operations of mutable state, or the ‘choice’ points in non- constructs. deterministic computations). In essence, this is an approach based more on the ‘algebraic theory’ interpretation of universal algebra General Terms Languages, Theory, Verification. within category theory [13] than on the later ‘monad’ interpretation [14] more familiar to functional programmers. Either can be used Keywords Monads, equational reasoning, Lawvere theories, alge- to model computational effects in a pure setting [10], with nearly braic specification. equivalent expressiveness, but the ‘algebraic theory’ interpretation emphasizes the specifics of a particular class of effects, whereas the 1. Introduction ‘monad’ interpretation focusses on the general notion of effectful computations and says little about specific effects. Pure functional programming languages are good for equational In passing, we present (what we believe to be) a novel approach reasoning [36]: non-strict semantics supports algebraic manipula- to reasoning about programs that exploit both nondeterministic and tion through the principle of ‘substitution of equals for equals’. But probabilistic choice. The monad of nondeterminism (that is, the on the face of it, purity is very limiting: many programs of inter- list functor, or more accurately the finite powerset functor) is very est involve impure computational effects, such as mutable state and familiar to functional programmers [38, 20]. Less well known in nondeterminism. Famously, Moggi [16] and Wadler [38] showed functional programming circles, but nevertheless well established how monads can be used to neatly encapsulate these effects. A pure in programming language semantics, is the monad of probability program can assemble a representation of an effectful computation distributions [5, 11, 27, 3]. We show that these two monads com- as a plain value, which can then be executed at the top level instead bine neatly, providing a simple unified model of nondeterminism of being printed out—‘Haskell is the world’s finest imperative pro- and probability, supporting the same simple equational reasoning gramming language’ [21]. as any other monad. Models for this combination of effects have been given before (see for example [15]), but we believe that none are as straightforward as ours. The remainder of the paper is structured as follows. We warm up Permission to make digital or hard copies of all or part of this work for personal or in Section 3 with a discussion of a simple problem involving effect- classroom use is granted without fee provided that copies are not made or distributed ful computation—counting the disc moves in the Towers of Hanoi for profit or commercial advantage and that copies bear this notice and the full citation puzzle. In Sections 4, 5, and 6 we consider some more interest- on the first page. To copy otherwise, to republish, to post on servers or to redistribute ing effects: nondeterminism, exceptions, and mutable state, respec- to lists, requires prior specific permission and/or a fee. tively. In Section 7 we look at programs that combine two classes ICFP’11, September 19–21, 2011, Tokyo, Japan. Copyright c 2011 ACM 978-1-4503-0865-6/11/09. $5.00 of effect, nondeterminism and state; and in Section 8 we look at probabilistic computations, and their combination with nondeter- pair (mx;my) = do fx mx ; y my ; return (x;y)g minism. Finally, we return to Hutton and Fulger’s tree relabelling problem in Section 9, and Section 10 concludes. But we start in (More generally, the pattern match against a generated value might Section 2 with some background on monads. be refutable; then some mechanism for handling failed matches is necessary. In Haskell, the Monad class has an additional operation fail for this purpose; we will do without.) 2. Background The do notation makes it clearer that the monad laws are not As is well known [16, 38], the categorical notion of a monad pre- awkward impositions, but properties essential for manipulating se- cisely expresses an abstraction of sequential computations, which quential compositions and blocks: is necessary for controlling the consequences of computational ef- do fy return x ; k yg = do fk xg fects in a lazy functional programming language. The ‘return’ and do fx mx ; return xg = do fmxg ‘bind’ methods model the identity and sequential composition of do fx mx ; y k x ; k0 yg = do fy do fx mx ; k xg ; k0 yg computations, respectively. They are captured in the following type class: where, in the third law, x is not free in k0. The first two laws state that return is a unit of sequential composition, and the third that class Monad m where nested blocks can be flattened, given appropriate care over bound return :: a ! m a variables. (>>=) :: m a ! (a ! m b) ! m b The two operations are required to satisfy three laws, corresponding 3. A counter example: Towers of Hanoi to the monoidal properties of sequential composition: The Monad class specifies only the very basic general-purpose return x >>= k = k x plumbing of sequential composition. To obtain any interesting mx >>= return = mx computational effects, one must augment the interface with ad- (mx >>= k) >>= k0 = mx >>= (lx ! k x >>= k0) ditional methods. In this paper, we will consistently do this by Monad We will make use of two important specializations of the operations defining subclasses of , rather than by declaring instances of Monad associated with a monad, which more precisely match the idea of with additional operations; and we will studiously program the identity computation and sequential composition: and reason according to the interface, not to a particular implemen- tation. skip :: Monad m ) m () For example, here is a class of monads supporting a simple skip = return () effect of counting: (>>) :: Monad m ) m a ! m b ! m b class Monad m ) MonadCount m where mx >> my = mx >>= const my tick :: m () We will also make significant use of the derived operator And here is a program for solving the Towers of Hanoi problem—it liftM :: Monad m ) (a ! b) ! m a ! m b ticks the counter once for each move of a disc. liftM f mx = mx >>= return ◦ f hanoi :: MonadCount m ) Int ! m () The reader may enjoy checking that the unit and associativity hanoi 0 = skip properties imply that liftM satisfies the map laws of a functor: hanoi (n + 1) = hanoi n >> tick >> hanoi n liftM id = id We claim that liftM (f ◦ g) = liftM f ◦ liftM g hanoi n = rep (2n − 1) tick An uncurried version of Haskell’s liftM2 can be defined as liftM f ◦ where rep repeats a unit computation a fixed number of times: pair, where pair sequences a pair of monadic computations: rep :: Monad m ) Int ! m () ! m () pair :: Monad m ) (m a;m a) ! m (a;a) rep 0 mx = skip pair (mx;my) = mx >>= lx ! my >>= ly ! return (x;y) rep (n + 1) mx = mx >> rep n mx (This is a type specialization of the function replicateM in the 2.1 Imperative functional programming Haskell standard library.) Note that The return and bind operations of the Monad class are sufficient rep mx = mx to support a very convenient monad comprehension or ‘do’ nota- 1 tion for computations, offering an elegant imperative programming rep (m + n) mx = rep m mx >> rep n mx style [37, 23]. The body of a do expression consists of a non-empty The verification of hanoi is by induction on n. The base case is sequence of qualifiers, which may be expressions, generators, or trivial; for the inductive step, we assume the result for n, and local definitions—except for the last qualifier, which must be an calculate: expression.
Details
-
File Typepdf
-
Upload Time-
-
Content LanguagesEnglish
-
Upload UserAnonymous/Not logged-in
-
File Pages13 Page
-
File Size-