-
Notifications
You must be signed in to change notification settings - Fork 0
/
handlers.lagda
2409 lines (2205 loc) · 104 KB
/
handlers.lagda
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
\documentclass[acmsmall,screen]{acmart}\settopmatter{printfolios=true}
%include agda.fmt
%include handlers.fmt
%include preamble.tex
\begin{document}
\title[A Predicate Transformer Semantics for Effects]{A Predicate Transformer Semantics for Effects\\(Functional Pearl)}
\author{Wouter Swierstra}
\email{w.s.swierstra@@uu.nl}
\author{Tim Baanen}
\email{t.baanen@@uu.nl}
\affiliation{
\institution{Universiteit Utrecht}
\country{The Netherlands}
}
\authorsaddresses{Authors' address: Wouter Swierstra, w.s.swierstra@@uu.nl; Tim Baanen, t.baanen@@uu.nl}
% \acmBadgeR{artifacts_evaluated_functional.jpg}
\begin{abstract}
Reasoning about programs that use effects can be much harder than
reasoning about their pure counterparts. This paper presents a
predicate transformer semantics for a variety of effects, including
exceptions, state, non-determinism, and general recursion. The
predicate transformer semantics gives rise to a refinement relation
that can be used to relate a program to its specification, or even
calculate effectful programs that are correct by construction.
\end{abstract}
\keywords{predicate transformers, effects, refinement, program
calculation, weakest precondition semantics, programming with
dependent types, free monads, Agda}
%include ccs.tex
\maketitle
\section{Introduction}
\label{sec:intro}
One of the key advantages of pure functional programming is
\emph{compositionality}. Pure programs may be tested in isolation;
referential transparency---the ability to freely substitute equals for
equals---enables us to employ equational reasoning to prove two
expressions equal~\cite{wadler-critique}. This has resulted in a rich
field of program calculation in the Bird-Meertens
style~\citep*{algebra-of-programming, pearls}, transforming an
inefficient executable specification to an efficient alternative
implementation.
Many programs, however, are \emph{not} pure, but instead rely on a
variety of effects, such as mutable state, exceptions,
general recursion, or non-determinism. Unfortunately, it is less clear
how to reason about such impure programs in a compositional fashion, as we can
no longer exploit referential transparency to reason about
subexpressions regardless of their context.
In recent years, \emph{algebraic effects} have emerged as a technique
to incorporate effectful operations in a purely functional
language~\cite{plotkin2002notions,pretnar2010logic}. Algebraic
effects clearly separate the syntax of effectful operations and their
semantics, described by \emph{effect handlers}. In contrast to monad
transformers~\cite{liang-hudak-jones:transformers}, different effects
may be processed in any given order using a series of handlers.
This paper defines a predicate transformer semantics
for effectful programs, culminating in a constructive framework for
deriving verified effectful programs from their specifications, inspired by
existing work on program calculation in the refinement
calculus~\cite{back2012refinement,morgan1994programming}. We will
briefly sketch the key techniques, before illustrating them with
numerous examples throughout the remainder of the paper.
\begin{itemize}
\item The syntax of effectful computations may be represented
by a free monad in type theory. Assigning meaning to such
free monads amounts to assigning meaning to the syntactic operations
each effect provides.
\item In this paper, we show how to assign \emph{predicate transformer
semantics} to computations arising from the Kleisli arrows on
these free monads. This enables us to compute the weakest
precondition associated with a given postcondition. By defining
these semantics as a \emph{fold} over the free monad, we can
establish \emph{compositionality} results, allowing us to decompose
the verification of a large program into smaller parts. These
results hold for \emph{any} semantics defined as a fold, provided
the predicate transformers are \emph{monotone}.
\item Using these weakest precondition semantics, we can define a
notion of \emph{refinement} on computations. We show how to use this
refinement relation to show a program satisfies its specification,
or indeed, \emph{calculate} a program from its specification. By
allowing specifications to appear in the leaves of our free monad,
we can mix operations and specifications, enabling the step by step
refinement of a specification to a complete program.
\end{itemize}
These principles are applicable to a range of different effects,
including exceptions (Section~\ref{sec:maybe}), state
(Section~\ref{sec:state}), non-determinism
(Section~\ref{sec:non-det}), and general recursion
(Section~\ref{sec:recursion}). Each section is illustrated with
numerous examples, each selected for their portrayal of proof
principles rather than being formidable feats of
formalisation. Besides relating effectful programs to their
specification, we show how programs and specifications may be mixed
freely, allowing verified programs to be calculated from their
specification one step at a time (Section~\ref{sec:stepwise-refinement}).
The definitions, examples, theorems and proofs presented in this paper
have all been formally verified in the dependently typed programming
language Agda~\cite{agda}, but the techniques translate readily to
other proof assistants based on dependent types such as
Idris~\cite{brady} or Coq~\cite{coq}.
\section{Background}
\label{sec:background}
%if style == newcode
\begin{code}
module Check where
open import Prelude hiding (map; all)
open import Level hiding (lift)
module Free where
\end{code}
%endif
\subsection{Free Monads}
\label{sec:free-monads}
We begin by defining a datatype for free monads in the style
of \citet{hancock-setzer-I, hancock-setzer-II}:
\begin{code}
data Free (hidden(l : Level)) (C : Set) (R : C -> Set) (a : (SetL(l))) : (SetL(l)) where
Pure : a -> Free C R a
Step : (c : C) -> (R c -> Free C R a) -> Free C R a
\end{code}
You may want to think of |C| as being the type of \emph{commands}. A
computation described by the free monad |Free C R| either returns a
result of type |a| or issues a command |c : C|. For each |c : C|,
there is a set of responses |R c|. The second argument of the |Step|
constructor corresponds to the continuation, describing how to proceed
after receiving a response of type |R c|. It is straightforward to
show that the |Free C R| datatype is indeed a monad:
\begin{code}
map : (Forall (l l' C R)) (implicit(a : Set l)) (implicit(b : Set l')) (a -> b) -> Free C R a -> Free C R b
map f (Pure x) = Pure (f x)
map f (Step c k) = Step c (\ r -> map f (k r))
return : (Forall (l C R)) (implicit(a : Set l)) a -> Free C R a
return = Pure
_>>=_ : (Forall (l l' C R)) (implicit(a : Set l)) (implicit(b : Set l')) Free C R a -> (a -> Free C R b) -> Free C R b
Pure x >>= f = f x
Step c x >>= f = Step c (\ r -> x r >>= f)
\end{code}
%if style == newcode
\begin{code}
infixr 20 _>>=_
_>>_ : forall {l l' C R} {a : Set l} {b : Set l'} -> Free C R a -> Free C R b -> Free C R b
c1 >> c2 = c1 >>= \_ -> c2
\end{code}
%endif
The examples of effects studied in this paper will be phrased in terms
of such free monads; each effect, described in a separate section,
chooses |C| and |R| differently, depending on its corresponding
operations. This choice of operations---as is usually the case for
algebraic effects---determines a syntax to which we must still assign
semantics~\cite{tensor}.
\subsection{Weakest Precondition Semantics}
The idea of of associating weakest precondition semantics with
imperative programs has a rich history, dating back to
Dijkstra's Guarded Command Language~\citeyearpar{gcl}. In this section, we
recall the key notions that we will use throughout the remainder of
the paper.
There are many different ways to specify the behaviour of a function
|f : a -> b|. One might provide a reference implementation, define a
relation |R : a -> b -> Set|, or write contracts and test cases. In
this paper, we will, however, focus on \emph{predicate transformer
semantics}. Where these predicate transformers traditionally relate
the state space of an (imperative) program, they can be readily
adapted to the functional setting.
In general, we will refer to values of type |a -> Set| as a
\emph{predicate} on the type |a|; \emph{predicate transformers} are
functions between such predicates. The most famous example of a
predicate transformer is the \emph{weakest precondition}, given by the
function |wp| below:
\begin{spec}
wp : (f : a -> b) -> (b -> Set) -> (a -> Set)
wp f P = \ x -> P (f x)
\end{spec}
The |wp| predicate transformer maps a function |f : a -> b| and a
desired postcondition on the function's output, |b -> Set|, to the
weakest precondition |a -> Set| on the function's input that ensures
the postcondition will be satisfied. Its definition, however, is
simply (reverse) function composition.
This notion of weakest precondition semantics is often too
restrictive. In particular, there is no way to specify that the output
is related in a particular way to the input. This can be addressed
easily enough by allowing the function |f| to be \emph{dependent},
yielding the following definition for weakest preconditions:
\begin{code}
wp : (Forall(l l' l'')) (implicit(a : Set l)) (implicit(b : a -> Set l')) (f : (x : a) -> b x) -> ((x : a) -> b x -> (SetL(l''))) -> (a -> (SetL(l'')))
wp f P = \ x -> P x (f x)
\end{code}
Although this type is a bit more complicated, |wp f| still maps a
predicate to a predicate---hence we refer to it as a predicate
transformer semantics for the function |f|.
When working with predicates and predicate transformers, we will
sometimes use the following shorthand notation:
\begin{code}
_⊆_ : (Forall (l')) (implicit(a : Set)) (a -> (SetL(l'))) -> (a -> (SetL(l'))) -> (SetL(l'))
P ⊆ Q = ∀ x -> P x -> Q x
\end{code}
Predicate transformer semantics give rise to a notion of
\emph{refinement}~\cite{back2012refinement,morgan1994programming}:
\begin{code}
_⊑_ : (implicit(a : Set)) (implicit (b : a -> Set)) (pt1 pt2 : ((x : a) -> b x -> Set) -> (a -> Set)) -> (SetOne)
pt1 ⊑ pt2 = forall P -> pt1 P ⊆ pt2 P
\end{code}
This refinement relation is defined between \emph{predicate
transformers}. As we will assign predicate transformer semantics to both
programs and specifications, we can relate them using this refinement
relation. For example, we can use this refinement relation to show a
program satisfies its specification; or to show that one program is
somehow `better' than another, where the notion of `better' arises
from our choice of predicate transformer semantics.
It is straightforward to show that this refinement relation is both transitive and reflexive:
\begin{code}
⊑-trans : (implicit (a : Set)) (implicit (b : a -> Set)) (implicit (P Q R : ((x : a) -> b x -> Set) -> (a -> Set))) P ⊑ Q -> Q ⊑ R -> P ⊑ R
⊑-refl : (implicit (a : Set)) (implicit (b : a -> Set)) (implicit (P : ((x : a) -> b x -> Set) -> (a -> Set))) P ⊑ P
\end{code}
%if style == newcode
\begin{code}
⊑-trans {a} {b} {P} {Q} {R} r1 r2 p x y = r2 p x (r1 p x y)
⊑-refl {a} {b} {P} p x H = H
\end{code}
%endif
In a pure setting, this refinement relation is not particularly
interesting: the refinement relation corresponds to extensional
equality between functions. The following lemma follows from the
`Leibniz rule' for equality in intensional type theory:
\begin{spec}
refinement : forall (f g : a -> b) ->
(wp f ⊑ wp g) ^^ ↔ ^^ (forall x -> f x == g x)
\end{spec}
%if style == newcode
\begin{code}
⊑-eq : {a b : Set} ->
(f g : a -> b) -> wp f ⊑ wp g -> (x : a) -> f x == g x
⊑-eq f g R x = R (\_ y -> f x == y) x refl
eq-⊑ : {a b : Set} ->
(f g : a -> b) -> ((x : a) -> f x == g x) -> wp f ⊑ wp g
eq-⊑ f g eq P x H with f x | g x | eq x
... | _ | _ | refl = H
\end{code}
%endif
In the impure setting, however, we will use different notions of
weakest precondition, which in turn lead to different notions of
refinement.
In the remainder of this paper, we will define predicate transformer
semantics for \emph{Kleisli arrows} of the form |a -> Free C R
b|. While we could use the |wp| function to assign semantics to these
computations directly, we are typically not interested in syntactic
equality between free monads---but rather want to study the semantics
of the effectful programs they represent. To define a predicate
transformer semantics for effects we need to define a function of the
following form:
\begin{center}
\begin{spec}
pt : (a -> Set) -> (Free C R a -> Set)
\end{spec}
\end{center}
These functions show how to lift a predicate on the type |a| over an
effectful computation returning values of type |a|. The definition of
|pt| depends very much on the semantics we wish to assign to the
effects of the free monad; the coming sections will give many examples
of such semantics. Crucially, the choice of |pt| and our weakest
precondition semantics, |wp|, together give us a way to assign weakest
precondition semantics to Kleisli arrows representing effectful
computations. Using these semantics for effectful computations, we can
then specify, verify, and calculate effectful programs.
\section{Partiality}
\label{sec:maybe}
%if style == newcode
\begin{code}
module Maybe where
open import Data.Nat public
using
(_+_; _>_; _*_
)
renaming
( ℕ to Nat
; zero to Zero
; suc to Succ
)
open import Data.Nat.DivMod using (_div_)
open import Data.Nat.Properties using (*-zeroʳ)
open Free
\end{code}
%endif
We can define the datatype for |Partial| computations, corresponding to
the |Maybe| monad, by making the following choice for commands |C| and
responses |R| in our |Free| datatype:
\begin{code}
data C : Set where
Abort : C
R : C -> Set
R Abort = ⊥
Partial : Set -> Set
Partial = Free C R
\end{code}
There is a single command, |Abort|; there is no continuation after
issuing this command, hence there are no valid responses, as denoted
by |⊥|, the empty type. It is sometimes convenient to define a smart
constructor for failure:
\begin{code}
abort : (Forall(a)) Partial a
abort = Step Abort (\ ())
\end{code}
A computation of type |Partial a| will either return a value of type
|a| or fail, issuing the |abort| command. Note that the responses to
the |Abort| command are empty; the smart constructor |abort| uses this
to discharge the continuation in the second argument of the |Step|
constructor. Such smart constructors are sometimes referred to as
\emph{generic effects} in the algebraic effects literature~\cite{plotkin-power-2003}.
With the syntax in place, we can turn our attention to
verifying programs using a suitable predicate transformer semantics.
\subsection{Example: Division}
We begin by defining a small expression language, closed under
division and natural numbers:
\begin{code}
data Expr : Set where
Val : Nat -> Expr
Div : Expr -> Expr -> Expr
\end{code}
We can specify the semantics of this language using an inductively
defined \emph{relation}:
\begin{code}
data _⇓_ : Expr -> Nat -> Set where
Base : (Forall(x)) Val x ⇓ x
Step : (Forall(l r v1 v2)) l ⇓ v1 -> r ⇓ (Succ v2) -> Div l r ⇓ (v1 div (Succ v2))
\end{code}
In this definition, we rule out erroneous results by requiring that
the divisor always evaluates to a non-zero value.
Alternatively we can evaluate expressions by defining a
\emph{monadic} interpreter, using the |Partial| monad to handle
division-by-zero errors:
\begin{code}
⟦_⟧ : Expr -> Partial Nat
⟦ Val x ⟧ = return x
⟦ Div e1 e2 ⟧ = ⟦ e1 ⟧ >>= \ v1 ->
⟦ e2 ⟧ >>= \ v2 ->
v1 ÷ v2
\end{code}
%if style == newcode
\begin{code}
where
\end{code}
%endif
This interpreter uses the following division operator that may fail
when the divisor is |Zero|:
\begin{code}
_÷_ : Nat -> Nat -> Partial Nat
n ÷ Zero = abort
n ÷ (Succ k) = return (n div (Succ k))
\end{code}
The division operator from the standard library (|div|) requires an
implicit proof that the divisor is non-zero. In the case when the
divisor is |Zero|, we fail explicitly using |abort|.
How can we relate these two definitions? We can assign a weakest
precondition semantics to Kleisli arrows of the form |a -> Partial b|
as follows:
\begin{code}
wpPartial : (implicit (a : Set)) (implicit (b : a -> Set)) (f : (x : a) -> Partial (b x)) -> (P : (x : a) -> b x -> Set) -> (a -> Set)
wpPartial f P = wp f (mustPT P)
where
mustPT : (Forall(a : Set)) (implicit(b : a -> Set)) (P : (x : a) -> b x -> Set) -> (x : a) -> Partial (b x) -> Set
mustPT P _ (Pure y) = P _ y
mustPT P _ (Step Abort _) = ⊥
\end{code}
To call the |wp| function we defined previously, we need to show how
to transform a predicate |P : b -> Set| to a predicate on partial
results, |Partial b -> Set|. To do so, we define the auxiliary
function |mustPT|; the proposition |mustPT P c| holds when a
computation |c| of type |Partial b| successfully returns a value of
type |b| that satisfies |P|. The predicate transformer semantics we
wish to assign to partial computations is determined by how we define
|mustPT|. In this case, we wish to rule out failure entirely; hence
the case for the |Abort| constructor returns the empty
type. Alternatively, we could consider a different semantics for
partiality, such as requiring that computations fail or return a
result satisfying some desired property. As we shall see in the rest
of this paper, there is often some freedom to choose different
semantics for a single effect.
Now that we have a predicate transformer semantics for Kleisli arrows
in general, we can study the semantics of our monadic interpreter. To
do so, we pass the interpreter, |⟦_⟧|, and desired postcondition,
|_⇓_|, as arguments to |wpPartial|:
\begin{center}
\begin{spec}
wpPartial ⟦_⟧ _⇓_ : Expr -> Set
\end{spec}
\end{center}
This results in a predicate on expressions. For all expressions
satisfying this predicate, we know that the monadic interpreter and
the relational specification, |_⇓_|, must agree on the result of
evaluation.
But what does this tell us about the correctness of our interpreter?
To understand the resulting predicate better, we might consider
manually defining our own predicate on expressions:
\begin{code}
SafeDiv : Expr -> Set
SafeDiv (Val x) = ⊤
SafeDiv (Div e1 e2) = (e2 ⇓ Zero -> ⊥) ∧ SafeDiv e1 ∧ SafeDiv e2
\end{code}
We would expect that any expression |e| for which |SafeDiv e| holds
can be evaluated without encountering a division-by-zero
error. Indeed, we can prove that |SafeDiv| is a sufficient condition
for our two notions of evaluation to coincide:
\begin{code}
correct : SafeDiv ⊆ wpPartial ⟦_⟧ _⇓_
\end{code}
%if style == newcode
\begin{code}
correct (Val x) h = Base
correct (Div e1 e2 ) (nz , (h1 , h2)) with ⟦ e1 ⟧ | ⟦ e2 ⟧ | correct e1 h1 | correct e2 h2
correct (Div e1 e2) (nz , (h1 , h2)) | Pure v1 | Pure Zero | ih1 | ih2 = magic (nz ih2)
correct (Div e1 e2) (nz , (h1 , h2)) | Pure v1 | Pure (Succ v2) | ih1 | ih2 = Step ih1 ih2
correct (Div e1 e2) (nz , (h1 , h2)) | Pure x | Step Abort x₁ | ih1 | ()
correct (Div e1 e2) (nz , (h1 , h2)) | Step Abort x | v2 | () | ih2
\end{code}
%endif
This lemma relates the two semantics, expressed as a relation and an
evaluator, for those expressions that satisfy the |SafeDiv| property.
We may not want to define predicates such as |SafeDiv|
ourselves. Instead, we can define the more general predicate
characterising the \emph{domain} of a partial function:
\begin{code}
dom : (implicit(a : Set)) (implicit (b : a -> Set)) ((x : a) -> Partial (b x)) -> (a -> Set)
dom f = wpPartial f (\ _ _ -> ⊤)
\end{code}
Once again, we can show that the two semantics agree precisely on the
domain of the interpreter.
\begin{code}
sound : dom ⟦_⟧ ^^ ⊆ ^^ wpPartial ⟦_⟧ _⇓_
complete : wpPartial ⟦_⟧ _⇓_ ^^ ⊆ ^^ dom ⟦_⟧
\end{code}
%if style == newcode
\begin{code}
sound (Val x) h = Base
sound (Div e1 e2) h with ⟦ e1 ⟧ | ⟦ e2 ⟧ | sound e1 | sound e2
sound (Div e1 e2) () | Pure v1 | Pure Zero | ih1 | ih2
sound (Div e1 e2) h | Pure v1 | Pure (Succ v2) | ih1 | ih2 = Step (ih1 tt) (ih2 tt)
sound (Div e1 e2) () | Pure x | Step Abort x₁ | ih1 | ih2
sound (Div e1 e2) () | Step Abort x | v2 | ih1 | ih2
inDom : {v : Nat} -> (e : Expr) -> ⟦ e ⟧ == Pure v -> dom ⟦_⟧ e
inDom (Val x) h = tt
inDom (Div e1 e2) h with ⟦ e1 ⟧ | ⟦ e2 ⟧
inDom (Div e1 e2) () | Pure v1 | Pure Zero
inDom (Div e1 e2) h | Pure v1 | Pure (Succ v2) = tt
inDom (Div e1 e2) () | Pure _ | Step Abort _
inDom (Div e1 e2) () | Step Abort _ | _
aux : (e : Expr) (v : Nat) -> ⟦ e ⟧ ≡ Pure v -> e ⇓ v
aux e v eq with sound e (inDom e eq)
... | H rewrite eq = H
wpPartial1 : {e1 e2 : Expr} -> wpPartial ⟦_⟧ _⇓_ (Div e1 e2) -> wpPartial ⟦_⟧ _⇓_ e1
wpPartial1 {e1} {e2} h with ⟦ e1 ⟧ | inspect ⟦_⟧ e1 | ⟦ e2 ⟧
wpPartial1 {e1} {e2} () | Pure x | eq | Pure Zero
wpPartial1 {e1} {e2} h | Pure x | [[[ eq ]]] | Pure (Succ y) = aux e1 x eq
wpPartial1 {e1} {e2} () | Pure x | eq | Step Abort x₁
wpPartial1 {e1} {e2} () | Step Abort x | eq | ve2
wpPartial2 : {e1 e2 : Expr} -> wpPartial ⟦_⟧ _⇓_ (Div e1 e2) -> wpPartial ⟦_⟧ _⇓_ e2
wpPartial2 {e1} {e2} h with ⟦ e1 ⟧ | inspect ⟦_⟧ e1 | ⟦ e2 ⟧ | inspect ⟦_⟧ e2
wpPartial2 {e1} {e2} h | Pure x | [[[ eqx ]]] | Pure y | [[[ eqy ]]] = aux e2 y eqy
wpPartial2 {e1} {e2} () | Pure x | [[[ eq ]]] | Step Abort x₁ | eq2
wpPartial2 {_} {_} () | Step Abort x | eq1 | se2 | eq2
complete (Val x) h = tt
complete (Div e1 e2) h
with ⟦ e1 ⟧ | inspect ⟦_⟧ e1 | ⟦ e2 ⟧ | inspect ⟦_⟧ e2
| complete e1 (wpPartial1 {e1} {e2} h)
| complete e2 (wpPartial2 {e1} {e2} h)
complete (Div e1 e2) h | Pure x | [[[ eqx ]]] | Pure Zero | [[[ eqy ]]] | p1 | p2
rewrite eqx | eqy = magic h
complete (Div e1 e2) h | Pure x | [[[ eqx ]]] | Pure (Succ y) | [[[ eqy ]]] | p1 | p2 = tt
complete (Div e1 e2) h | Pure x | eq1 | Step Abort x₁ | eq2 | p1 | ()
complete (Div e1 e2) h | Step Abort x | eq1 | se2 | eq2 | () | p2
\end{code}
%endif
Both proofs proceed by induction on the argument expression; despite
the necessity of a handful of auxiliary lemmas, they are
fairly straightforward.
\subsection{Refinement}
The weakest precondition semantics on partial computations defined
above give rise to a refinement relation on Kleisli arrows of the
form |a -> Partial b|. We can characterise this relation by proving
the following lemma:
\begin{spec}
refinement : (f g : a -> Partial b) ->
(wpPartial f ^^ ⊑ ^^ wpPartial g) ^^ ↔ ^^ (forall x -> (f x == g x) ∨ (f x == abort))
\end{spec}
Why care about this refinement relation? Not only can we use it to
relate Kleisli morphisms, but it can also relate a program to a
specification given by a pre- and postcondition, as we shall see
shortly.
\subsection{Example: \textsc{Add}}
Suppose we are writing an interpreter for a simple stack machine. To
interpret the |ADD| instruction, we replace the top two elements of
the stack with their sum; this may fail if the stack has
too few elements. This section shows how to prove that the obvious
definition meets its specification.
We begin by defining a notion of specification in terms of a pre- and
postcondition. In general, the specification of a function of type |(x
: a) -> b x| consists of a precondition on |a| and a postcondition
relating inputs that satisfy this precondition and the corresponding outputs:
\begin{code}
record Spec (hidden(l : Level)) (a : Set) (b : a -> Set) : (SetL(suc l)) where
constructor [[_,_]]
field
pre : a -> (SetL(l))
post : (x : a) -> b x -> (SetL(l))
\end{code}
As is common in the refinement calculus literature, we will write |[[
P , Q ]]| for the specification consisting of the precondition |P| and
postcondition |Q|. In many of our examples, the type |b| does not
depend on |x : a|, motivating the following type synonym:
\begin{code}
SpecK : (implicit(l : Level)) Set -> Set -> (SetL(suc l))
SpecK a b = Spec a (K b)
\end{code}
This definition uses the combinator K to discard the unused argument
of type |a|.
Using this definition, we can define the following specification for
our addition function:
\begin{code}
data Add : List Nat -> List Nat -> Set where
AddStep : (implicit(x1 x2 : Nat)) (implicit(xs : List Nat)) Add (x1 :: x2 :: xs) ((x1 + x2) :: xs)
addSpec : SpecK (List Nat) (List Nat)
addSpec = [[ (\ xs -> length xs > 1) , Add ]]
\end{code}
That is, provided we are given a list with at least two elements, we
should replace the top two elements with their sum. Here we describe
the desired postcondition by introducing a new datatype, |Add|,
relating the input and output stacks.
How can we relate this specification to an implementation? We have
seen how the |wpPartial| function assigns predicate transformer
semantics to functions---but we do not yet have a corresponding
predicate transformer \emph{semantics} for our specifications. The
|wpSpec| function does precisely this:
\begin{code}
wpSpec : (Forall(l a)) (implicit(b : a -> Set)) Spec (hidden(l)) a b -> (P : (x : a) -> b x -> (SetL(l))) -> (a -> (SetL(l)))
wpSpec [[ pre , post ]] P = \ x -> (pre x) ∧ (post x ⊆ P x)
\end{code}
Given a specification, |Spec a b|, the |wpSpec| function computes the
weakest precondition necessary to satisfy an arbitrary postcondition
|P|: namely, the specification's precondition should hold and its
postcondition must imply |P|.
Using this definition we can precisely formulate the problem at
hand: can we find a program |add : List Nat -> Partial (List
Nat)| that refines the specification given by |addSpec|:
\begin{spec}
correctnessAdd : wpSpec addSpec ⊑ wpPartial add
\end{spec}
Defining such a program and verifying its correctness is entirely
straightforward:
\begin{code}
pop : (Forall (a)) List a -> Partial (a × List a)
pop Nil = abort
pop (x :: xs) = return (x , xs)
add : List Nat -> Partial (List Nat)
add xs =
pop xs >>= \{ (x1 , xs) ->
pop xs >>= \{ (x2 , xs) ->
return ((x1 + x2) :: xs)}}
\end{code}
%if style == newcode
\begin{code}
correctnessAdd : wpSpec addSpec ⊑ wpPartial add
correctnessAdd P Nil (() , _)
correctnessAdd P (x :: Nil) (Data.Nat.s≤s () , _)
correctnessAdd P (x :: y :: xs) (_ , H) = H (x + y :: xs) AddStep
\end{code}
%endif
We include this example here to illustrate how to use the refinement
relation to relate a \emph{specification}, given in terms of a pre-
and postcondition, to its implementation. When compared to the
refinement calculus, however, we have not yet described how to mix
code and specifications---a point we will return to later
(Section~\ref{sec:stepwise-refinement}). Before doing so, however, we
will explore several other effects, their semantics in terms of
predicate transformers, and the refinement relation that arises from
these semantics.
\subsection{Alternative Semantics}
\label{alternative-abort}
The predicate transformers arising from the |wpPartial| function are
not the only possible choice of semantics. In particular, sometimes we
may use the |Abort| command to `short-circuit' a computation and
handle the corresponding exception. This section explores how to adapt
our definitions accordingly.
Suppose we have a function that computes the product of the numbers
stored in a list:
\begin{code}
product : List Nat -> Nat
product = foldr _*_ 1
\end{code}
If this list contains a zero, we can short circuit the computation and
return zero immediately. To do so, we define the following
computation:
\begin{code}
fastProduct : List Nat -> Partial Nat
fastProduct Nil = return 1
fastProduct (Zero :: xs) = abort
fastProduct (k :: xs) = map (_*_ k) (fastProduct xs)
\end{code}
To run this computation, we provide a handler that maps |abort| to
some default value.
\begin{code}
defaultHandler : (Forall(a)) a -> Partial a -> a
defaultHandler _ (Pure x) = x
defaultHandler d (Step Abort _) = d
\end{code}
Now the question arises how to assign a suitable predicate transformer
semantics to the |fastProduct| function. We could choose to use the
|wpPartial| function we defined previously; doing so, however, would
require the input list to not contain any zeros. It is clear that we
want to assign a different semantics to our aborting computations. To
do so, we provide the following |wpDefault| function that requires the
desired postcondition |P| holds of the default value when the
computation aborts:
\begin{code}
wpDefault : (Forall (a b : Set)) (d : b) -> (f : a -> Partial b) -> (P : a -> b -> Set) -> (a -> Set)
wpDefault (hidden(a)) (hidden(b)) d f P = wp f defaultPT
where
defaultPT : (x : a) -> Partial b -> Set
defaultPT x (Pure y) = P x y
defaultPT x (Step Abort _) = P x d
\end{code}
The |wpDefault| function computes \emph{some} predicate on the
function's input. But how do we know that this predicate is meaningful
in any way? We could compute simply return a trivial predicate that is
always holds. To relate the predicate transformer semantics to the
|defaultHandler| we need to prove the following soundness result:
\begin{code}
soundness : (Forall (a b)) (P : a -> b -> Set) -> (d : b) -> (c : a -> Partial b) ->
forall x -> wpDefault d c P x -> P x (defaultHandler d (c x))
\end{code}
%if style == newcode
\begin{code}
soundness P d c x H with c x
soundness P d c x H | Pure y = H
soundness P d c x H | Step Abort _ = H
\end{code}
%endif
Put simply, this soundness result ensures that whenever the
precondition computed by |wpDefault| holds, the output returned by
running the |defaultHandler| satisfies the desired postcondition.
Now we can finally use our refinement relation to relate the
|fastProduct| function to the original |product| function:
\begin{code}
correctnessProduct : wp product ⊑ wpDefault 0 fastProduct
\end{code}
%if style == newcode
\begin{code}
correctnessProduct P Nil H = H
correctnessProduct P (Zero :: xs) H = H
correctnessProduct P (Succ x :: xs) H
with fastProduct xs | correctnessProduct (\xs v -> P (Succ x :: xs) _) xs H
correctnessProduct P (Succ x :: xs) H | Pure v | IH = IH
correctnessProduct P (Succ x :: xs) H | Step Abort _ | IH rewrite *-zeroʳ x = IH
\end{code}
%endif
This example shows how to prove soundness of our predicate transformer
semantics with respect to a given handler. The predicate transformers, such as
|wpDefault| and |wpPartial|, return \emph{some} predicate; by proving such soundness
results, we can ensure that the
semantics is meaningful. Furthermore, this example shows how different
choices of handler may exist for the \emph{same} effect---a point we shall
return to when discussing non-determinism (Section~\ref{sec:non-det}).
\section{Mutable State}
\label{sec:state}
%if style == newcode
\begin{code}
module State (s : Set) where
open Free
open Maybe using (SpecK; Spec; [[_,_]]; wpSpec)
\end{code}
%endif
In this section, we will explore how to develop similar predicate
transformer semantics for mutable state, giving rise to a familiar
Hoare logic. In what follows, we will assume a fixed type |s : Set|,
representing the type of the state. As before, we can define the
desired free monad in terms of commands |C| and responses |R|:
\begin{code}
data C : Set where
Get : C
Put : s -> C
R : C -> Set
R Get = s
R (Put _) = ⊤
State : (Forall(l)) (SetL(l)) -> (SetL(l))
State = Free C R
\end{code}
To facilitate writing stateful computations, we can define a pair of
smart constructors:
\begin{code}
get : State s
get = Step Get return
put : s -> State ⊤
put s = Step (Put s) (\_ -> return tt)
\end{code}
The usual handler for stateful computations maps our free monad,
|State s|, to the state monad:
\begin{code}
run : (implicit(a : Set)) State a -> s -> a × s
run (Pure x) s = (x , s)
run (Step Get k) s = run (k s) s
run (Step (Put s) k) _ = run (k tt) s
\end{code}
Inspired by the previous section, we can define the following
predicate transformer that for every stateful computation of type
|State b|, maps a postcondition on |b × s| to the required
precondition on the initial state of type |s|:
\begin{code}
statePT : (Forall(l l')) (implicit(b : Set l)) (b × s -> (SetL(l'))) -> State b -> (s -> (SetL(l')))
statePT P (Pure x) = \ s -> P (x , s)
statePT P (Step Get k) = \ s -> statePT P (k s) s
statePT P (Step (Put s) k) = \ _ -> statePT P (k tt) s
\end{code}
We can generalise this predicate transformer slightly. As we saw
before, we sometimes describe postconditions as a \emph{relation}
between inputs and outputs. In the case for stateful computations,
this amounts to allowing the postcondition to also refer to the
initial state:
%{
%if style == poly
%format statePTR = statePT"^\prime"
%else
%format statePTR = statePT'
%endif
\begin{code}
statePTR : (Forall(l l')) (implicit(b : Set l)) (s -> b × s -> (SetL(l'))) -> State b -> (s -> (SetL(l')))
statePTR P c i = statePT (P i) c i
\end{code}
In the remainder of this section, we will overload the variable name
|statePT| to refer to both variations of the same function; the
context should disambiguate the version being used.
Finally, we can define a weakest precondition semantics for Kleisli
morphisms of the form |a -> State b|:
%}
\begin{code}
wpState : (Forall(l l' l'')) (implicit(a : Set l)) (implicit(b : Set l')) (a -> State b) -> (P : a × s -> b × s -> (SetL(l''))) -> (a × s -> (SetL(l'')))
wpState f P (x , i) = wp f ((hiddenConst (\ c -> statePT' (\ j -> P (x , j)) c i))) x
\end{code}
Given any predicate |P| relating the input, initial state, final state
and result of the computation, the |wpState| function computes the
weakest precondition required of the input and initial state to ensure
|P| holds upon completing the computation. The definition amounts to
composing the |wp| and |statePT| functions we have seen previously.
As we did in the previous section for |wpDefault|, we can prove
soundness of this semantics with respect to the |run| function:
\begin{code}
soundness : (Forall(a b : Set)) (P : a × s -> b × s -> Set) -> (f : a -> State b) ->
forall i x -> wpState f P (x , i) -> P (x , i) (run (f x) i)
\end{code}
%if style == newcode
\begin{code}
soundness {a} {b} P c i x H = lemma i (c x) H
where
lemma : (st : s) -> (statec : State b) -> (statePT (P (x , i)) statec st) -> P (x , i) (run statec st)
lemma i (Pure y) H = H
lemma i (Step Get k) H = lemma i (k i) H
lemma i (Step (Put s) k) H = lemma s (k tt) H
\end{code}
%endif
\subsection{Example: Tree Labelling}
\label{sec:trees}
%if style == newcode
\begin{code}
module Relabel where
open Free
open Maybe using (Spec; SpecK; [[_,_]]; wpSpec)
open import Data.Nat public
using
(_+_; _>_; _*_
)
renaming
( ℕ to Nat
; zero to Zero
; suc to Succ
)
module StateNat = State Nat
open StateNat
\end{code}
%endif
To show how to reason about stateful programs using our weakest
precondition semantics, we revisit a classic verification problem
proposed by \citet{hutton2008reasoning}: given a binary tree as input,
relabel this tree so that each leaf has a unique number associated
with it. A typical solution uses the state monad to keep track of the
next unused label. The challenge that \citeauthor{hutton2008reasoning}
pose is to reason about the program, without expanding the definition
of the monadic operations.
We begin by defining the type of binary trees:
\begin{code}
data Tree (a : Set) : Set where
Leaf : a -> Tree a
Node : Tree a -> Tree a -> Tree a
\end{code}
%if style == newcode
\begin{code}
flatten : ∀ {a} -> Tree a -> List a
flatten (Leaf x) = [ x ]
flatten (Node l r) = flatten l ++ flatten r
size : ∀ {a} -> Tree a -> Nat
size (Leaf x) = 1
size (Node l r) = size l + size r
seq : Nat -> Nat -> List Nat
seq i Zero = Nil
seq i (Succ n) = Cons i (seq (Succ i) n)
\end{code}
%endif
One obvious choice of specification might be the following:
\begin{code}
relabelSpec : (Forall(a)) SpecK (Tree a × Nat) (Tree Nat × Nat)
relabelSpec = [[ K ⊤ , relabelPost ]]
where
relabelPost : (Forall(a)) Tree a × Nat -> Tree Nat × Nat -> Set
relabelPost (t , s) (t' , s') = (flatten t' == (seq (s) (size t))) ∧ (s + size t == s')
\end{code}
The precondition of this specification is trivially true regardless of
the input tree and initial state; the postcondition consists of a
conjunction of two auxiliary statements: first, flattening the
resulting tree |t'| produces the sequence of numbers from |s| to |s +
size t|, where |t| is the initial input tree; furthermore, the output
state |s'| should be precisely |size t| larger than the input state
|s|. Note that our |size| function only counts the number of leaves,
as these are only of interest for relabelling.
We can now define the obvious relabelling function as follows:
%if style == newcode
\begin{code}
fresh : State Nat
fresh = get >>= \ n ->
put (Succ n) >>
return n
\end{code}
%endif
\begin{code}
relabel : (Forall(a)) Tree a -> State (Tree Nat)
relabel (Leaf x) = map Leaf fresh
relabel (Node l r) =
relabel l >>= \ l' ->
relabel r >>= \ r' ->
return (Node l' r')
\end{code}
Here the auxiliary function |fresh| increments the current state and
returns its value.
Next, we would like to show that this definition satisfies the
intended specification. To do so, we can use our |wpState| function to
compute the weakest precondition semantics of the relabelling
function and formulate the desired correctness property:
\begin{code}
correctnessRelabel : (Forall(a : Set)) wpSpec (instantiate (relabelSpec)) ⊑ wpState relabel
\end{code}
The proof is interesting. Initially, it proceeds by induction on the
input tree. The base case for the |Leaf| constructor is easy enough to
discharge; the inductive case, however, poses a greater challenge. In
particular, we assume that the |wpSpec relabelSpec P| holds for some
arbitrary predicate |P|; the goal we wish to prove in the case for the
|Node| constructor amounts to proving the following statement:
\begin{center}
\begin{spec}
statePT (P (Node l r , i)) (relabel l >>= (\ l' → relabel r >>= (\ r' → Pure (Node l' r')))) i
\end{spec}
\end{center}
At first glance, it is not at all obvious how to use our induction
hypothesis! Although we can use our induction hypothesis to show |P|
holds for |l| and |r|---it is not clear how to use this information to
prove the above goal, without knowing anything further about |P|.
\subsection{Compositionality}
\label{sec:compositionality}
To complete the proof, we need an auxiliary lemma that enables us to
prove a property of a composite computation, |c >>= f|, in terms of
the semantics of |c| and |f|:
\begin{code}
compositionality : (Forall(a b : Set)) (c : State a) (f : a -> State b) ->
∀ i P → statePT P (c >>= f) i == statePT (wpState f (hiddenConst(P))) c i
\end{code}
%if style == newcode
\begin{code}
compositionality (Pure x) f i P = refl
compositionality (Step Get k) f i P = compositionality (k i) f i P
compositionality (Step (Put x) k) f i P = compositionality (k tt) f x P
\end{code}
%endif
Most predicate transformer semantics of imperative languages
have a similar rule, mapping sequential composition of programs to the
composition of their associated predicate transformers:
\begin{center}
\begin{spec}
wp(c1 ; c2, R) = wp(c1, wp(c2, R))
\end{spec}
\end{center}
By defining semantics for Kleisli morphisms, |wpState|, in terms of
the predicate transformer semantics of computations, |statePT|, we can
prove this analogous result. The proof, by induction on the stateful
computation |c|, is trivial.
Using this compositionality property, we can massage the proof
obligation of our correctness lemma to the point where we can indeed
apply our induction hypotheses and complete the remaining proof
obligations.
%if style == newcode
\begin{code}
correctnessRelabel = step2
where
open NaturalLemmas
-- Simplify proofs of refining a specification,
-- by first proving one side of the bind, then the second.
-- This is essentially the first law of consequence,
-- specialized to the effects of State and Spec.
prove-bind : ∀ {a b} (mx : State a) (f : a → State b) P i →
statePT (wpState f \ _ → P) mx i → statePT P (mx >>= f) i
prove-bind mx f P i x = coerce {zero} (sym (compositionality mx f i P)) x
prove-bind-spec : ∀ {a b} (mx : State a) (f : a → State b) spec →
∀ P i → (∀ Q → Spec.pre spec i × (Spec.post spec i ⊆ Q) → statePT Q mx i) →
Spec.pre spec i × (Spec.post spec i ⊆ wpState f (\ _ → P)) →
statePT P (mx >>= f) i
prove-bind-spec mx f spec P i Hmx Hf = prove-bind mx f P i (Hmx (wpState f (\ _ → P)) Hf)
-- Partially apply a specification.
applySpec : ∀ {a b s} → SpecK {zero} (a × s) (b × s) → a → SpecK s (b × s)
applySpec [[ pre , post ]] x = [[ (\ s → pre (x , s)) , (\ s → post (x , s)) ]]