On the Relationship between Dijkstra Monads and Higher-Order Fixpoint Logic
We study the relationship between two approaches to higher-order program verification: a semi-automated method using Dijkstra monads and a fully automated method using a higher-order fixpoint logic called HFL(Z). Although the origins of both approaches are quite different, there are some striking similarities: both convert programs to corresponding predicate transformers, and the conversion is essentially obtained by a CPS transformation. After reviewing the two approaches, we formalize an exact correspondence between the two for a restricted fragment of a functional language. We also point out that, outside the restricted fragment, there are some important differences between the two approaches, suggesting the need for cross-fertilization to obtain the best of the two approaches. As an example of the cross-fertilization, we also propose a semi-automated verification method, which requires less annotations than the Dijkstra monad approach and can scale to larger programs than the HFL(Z) approach.
Keywords
Program Verification Dijkstra Monad Higher-Order Fixpoint Logic Predicate Transformer

1 Introduction
This paper studies the relationship between two approaches to the verification of higher-order functional programs: one based on Dijkstra monads [1, 12, 15] and the other based on HFL(Z) [9, 17].
The Dijkstra monad approach, introduced by Swamy et al. [15], is a semi-automated verification method for programs with higher-order functions and monadic effects. It associates a program with a corresponding predicate transformer in the form of a monad. Using the monad, the verification condition for a program can be computed through type inference, and discharged by SMT solvers. The method is only semi-automated; the type inference procedure requires type annotations for recursive functions. Kobayashi et al.’s approach based on HFL(Z) [9, 17] is a fully-automated approach to the verification of temporal properties of higher-order programs. In this approach, a functional program is automatically transformed to a formula of HFL(Z), a higher-order logic with fixpoint operators and integer arithmetic, so that the program satisfies a given temporal property just if the formula is valid. The validity of the formula is then checked by an automated solver for HFL(Z) validity checking [5, 6, 8].
The two approaches above are seemingly different, but there are some strong similarities. Consider the successor function defined by \(\texttt {let~succ~x = x+1}\).1 The Dijkstra monad approach (DM approach, for short) assigns the type \(x\mathbin {:}\texttt {int}\rightarrow \texttt{D}\;\texttt {int}\;\lambda p.p(x+1)\) to the function, where \(\texttt{D}\;\texttt {int}\;\lambda p.p(x+1)\) is a monadic type indexed by the predicate transformer \(\lambda p.p(x+1): (\texttt {int}\rightarrow \texttt {prop}) \rightarrow \texttt {prop}\). The type means that the function takes an integer \(x\), and for the return value \(r\) to satisfy the postcondition \(p(r)\), it suffices that the precondition \(p(x+1)\) holds. Thus, if we wish to prove \(\forall x.x>0\Rightarrow \texttt {succ}\ x>0\), it suffices to prove \(\forall x.x>0 \Rightarrow (\lambda p.p(x+1))(\lambda r.r>0)\), which is equivalent to \(\forall x.x>0 \Rightarrow x+1>0\).2
In the HFL(Z) approach, for the same program, the call-by-value CPS transformation is first applied to obtain a corresponding call-by-name program \(\texttt {let~succ\_cps~x~k = k(x+1)}\). Then the function succ_cps is converted to the corresponding predicate \(\textsf{Succ} := \lambda x.\lambda k.k(x+1)\), and the specification \(\forall x.x>0\Rightarrow \texttt {succ}\; x>0\) is mapped to the HFL(Z) formula \(\forall x.x>0\Rightarrow \textsf{Succ}\;x\;(\lambda r.r>0)\). In the example above, one can observe that the predicate \(\textsf{Succ}\;x\) is essentially a predicate transformer of the original function \(\texttt {succ}\); indeed, \(\textsf{Succ}\;x = (\lambda x.\lambda k.k(x+1))x\) is \(\alpha \beta \)-equal to the predicate transformer \(\lambda p.p(x+1)\) obtained in the DM approach. The key translation used to obtain \(\textsf{Succ}\) was a CPS transformation.3 Incidentally, Ahman et al. [1] have shown that various Dijkstra monads can automatically be obtained from effect monads by using the CPS transformation. In spite of these similarities, the two approaches have been studied independently.
In this paper, we first formalize a precise correspondence between the DM and HFL(Z) approaches, for a restricted fragment of a higher-order functional language parameterized by effect monads. We show that, for every predicate transformer derived in the HFL(Z) approach, an equivalent predicate transformer can be obtained also in the DM approach, and that, conversely for every predicate transformer derivable in the DM approach, an at least equally good predicate transformer can be obtained in the HFL(Z) approach.4 We also show that, outside the restricted fragment, there are at least two important differences between the two approaches. One is for programs containing “nested monads”, for which we point out some awkwardness in the DM approach: information about the program behavior is scattered and replicated in types. The other difference is for recursive programs: in the DM approach, a user has to specify the type of every recursive function, while in the HFL(Z) approach, there is no such need and predicate transformers are computed fully automatically, thanks to the use of a higher-order fixpoint logic. The latter difference yields some trade-offs: whilst the fully automatic approach of HFL(Z) frees users from burdens of annotating programs, it imposes a heavy burden on the backend HFL(Z) solver and thus makes the verification time highly unpredictable. Based on the latter difference, we also propose an integration of the two approaches, to take the best of two worlds. In the integrated approach, a user may provide type annotations for recursive functions selectively; thanks to the use of the fixpoint logic, not all recursive functions need to be annotated. Based on a refinement type system for HFL(Z) [6], we can automatically extract verification conditions from partially annotated programs. We have implemented a prototype tool, and confirmed its effectiveness: there are programs for which the verification tool based on the original HFL(Z) approach times out, but our tool succeeds without (unlike the DM approach) requiring full annotations for recursive functions.
Our main contributions are summarized as follows.
-
A formalization of the correspondence between the DM approach and the HFL(Z) approach, which have been studied independently.
-
Analysis of the differences between the two approaches, which suggests cross-fertilization of the two approaches.
-
A proposal of a semi-automated verification method to get the best of the two approaches. Our method is more scalable and predictable than the HFL(Z) approach, and works with fewer annotations than the DM approach.
In addition to these main contributions, our formalization includes generalized translation rules for the HFL(Z) approach to handle monadic effects, extending the example-based sketch of Kobayashi et al. [9, 17].
The rest of this paper is structured as follows. Section 2 reviews the two approaches based on Dijkstra monads and HFL(Z) and informally observes their similarities. Section 3 considers a restricted fragment of a higher-order functional language, and proves an exact correspondence between the two approaches. Section 4 discusses the differences between the two approaches. Section 5 presents our semi-automated verification method and reports preliminary experimental results. Section 6 discusses related work and Section 7 concludes the paper.
2 Overview of Dijkstra Monads, HFL(Z), and Their Relationship
This section reviews the Dijkstra monad approach and the HFL(Z) approach for higher-order program verification, and observes their similarities.
2.1 The Dijkstra Monad Approach
As mentioned already, Swamy et al. [15] introduced a semi-automated verification method targeting higher-order programs with monadic effects, based on a monad of predicate transformers called the Dijkstra monad. The types of effectful computations has the form \(\texttt{D}\; t\; w\), where \(\texttt{D}\) is the Dijkstra monad defined for each kind of effect, \(t\) is the pure type of the result, and \(w\) is a predicate transformer that describes the behavior of the computation by mapping postconditions to preconditions.

Dummy
To derive a predicate transformer from a program, Swamy et al. [15] proposed a kind of a dependent type system and an inference algorithm. For programs without recursion, predicate transformers and the associated verification conditions can automatically be inferred, although users may optionally provide type annotations to specify the behavior of sub-expressions. For recursive functions, however, those annotations must be provided, as in other deductive (verification-condition-generation) approaches to program verification.
2.2 The HFL(Z) Approach
Kobayashi et al. [9, 17] proposed an approach to higher-order program verification based on HFL(Z), an extension of Viswanathan and Viswanathan’s higher-order fixpoint logic [16] with integers. In that approach, a higher-order functional program with a regular-temporal-property specification is automatically translated into a formula of HFL(Z), so that the program satisfies the property just if the formula is valid. The validity of the formula is undecidable in general, but automated (but inevitably incomplete due to the undecidability) validity checkers for HFL(Z) have been implemented since then [5, 6, 8]; the approach thus realizes fully automated verification of higher-order programs.

Dummy

Dummy
2.3 The Similarity between Dijkstra Monads and HFL(Z)

Dummy
Correspondence between DM types and HFL(Z) formulas

Dummy
3 Correspondence between the Two Approaches
In the previous section, we reviewed the two approaches to higher-order program verification and observed their similarities informally. In this section, we formalize a concrete correspondence between the two approaches for a restricted fragment of a higher-order functional language.
We first set up a common language for comparing the two approaches in Section 3.1. We then formalize the derivation of predicate transformers in the DM approach in Section 3.2, and the derivation of logical formulas in the HFL(Z) approach in Section 3.3. We then state and prove a correspondence in Section 3.4.
3.1 Language
This subsection introduces a simple call-by-value, effectful higher-order functional language, which shall be used as the common language for formally comparing the two approaches.
We exclude recursion and restrict the shape of types; as discussed in Section 4, some important differences show up for recursion and certain types.




Typing rules of the language
We have so far parameterized the language by effects. A concrete language and its semantics are determined by the parameters given below, which we call effect parameters. The semantics of effect operations are given in the form of predicate transformers; we assume the simply-typed lambda calculus with \(a\) and \(\texttt {prop}\) (which is the type of propositions) as base types and also with appropriate constants (such as logical connectives \(\wedge , \vee : \texttt {prop}\rightarrow \texttt {prop}\rightarrow \texttt {prop}\), the predicate \(\texttt{pred}: \texttt {int}^k\rightarrow \texttt {prop}\) for each \(k\)-ary predicate \(\texttt{pred}\) in the source language, and the operator \(\texttt{op}:\texttt {int}^k\rightarrow \texttt {int}\) for each \(k\)-ary operator \(\texttt{op}\) in the source language) for describing predicate transformers.
-
\(\texttt{W}\): The type operator that takes a base type \(a\) and returns the (simple) type of the predicate transformer for computations returning values of type \(a\).
-
\(\mathtt {return^{W}}\mathbin {:}\forall a.a\rightarrow \texttt{W}\;a\): The predicate transformer of a computation that takes a value of type \(a\) and just returns it without any effects.
-
\(\mathtt {bind^{W}}\mathbin {:}\forall a_1,a.(\texttt{W}\;a_1 \rightarrow (a_1\rightarrow \texttt{W}\;a) \rightarrow \texttt{W}\;a)\): The predicate transformer of a computation that takes \(w_1\) and \(w_2\) of types \(\texttt{W}\;a_1\) and \(a_1\rightarrow \texttt{W}\;a\) respectively, and pipes the result of the computation specified by \(w_1\) to the computation specified by \(w_2\).
-
\(\texttt{A}\): A set of (names of) primitive effect actions. We use the metavariable \( act \) to range over this set.
-
\(t^{ act }\): The (monadic) type of each action \( act \in \texttt{A}\). This describes the types of parameters and return values of each action.
-
\(w^{ act }\): The predicate transformer of each action \( act \in \texttt{A}\). It describes the behavior of each action. The simple type of \(w^{ act }\) must be consistent with \(t^{ act }\), in the sense that \(w^{ act }\) must have the type obtained from \(t^{ act }\) by replacing \(\texttt{M}\) with \(\texttt{W}\). For example, if \(t^{ act }= \texttt {unit}\rightarrow \texttt{M}\; \texttt {int}\), then \(w^{ act }\) must have type \(\texttt {unit}\rightarrow \texttt{W}\;\texttt {int}\).
In the field of the DM approach, the former three parameters are called a specification monad, and the latter three yield the DM type of effect actions. Methods to obtain these parameters in a correct-by-construction manner have been studied by Ahman et al. [1] and Maillard et al. [12]. According to Ahman et al.’s result, reinterpreted by Maillard et al., for effects that can be represented as monad transformers, these parameters can be obtained by applying the monad transformer to the continuation monad with \(\texttt {prop}\) as the answer type.
We give examples of effect parameters, some of which can be derived from monad transformers.
Example 1
-
\(\texttt{W}\;a:=(a\rightarrow \texttt {prop})\rightarrow \texttt {prop}\)
-
\(\mathtt {return^{W}}\;(x:a):=\lambda p:(a\rightarrow \texttt {prop}).p\;x\)
-
\(\mathtt {bind^{W}}\;(w_1:\texttt{W}\;a_1)\;(w_2:a_1\rightarrow \texttt{W}\;a):=\lambda p:(a\rightarrow \texttt {prop}). w_1(\lambda x. w_2\; x\; p)\)
These coincide with the identity monad transformer applied to the continuation monad.
Example 2
-
\(\texttt{W}\;a:={\texttt {int}} \rightarrow (a\rightarrow \texttt {int}\rightarrow \texttt {prop}) \rightarrow \texttt {prop}\)
-
\(\mathtt {return^{W}}\;(x:a):=\lambda h:\texttt {int}.\lambda p:(a\rightarrow \texttt {int}\rightarrow \texttt {prop}). p\;x\;h\)
-
\(\begin{aligned}& \mathtt {bind^{W}}\;(w_1:\texttt{W}\;a_1)\;(w_2:a_1\rightarrow \texttt{W}\;a) \\ &\quad :=\lambda h:\texttt {int}.\lambda p:(a_2\rightarrow \texttt {int}\rightarrow \texttt {prop}). w_1\;h\;(\lambda x:a_2.\lambda h':\texttt {int}. w_2\;x\;h'\;p) \end{aligned}\)
-
\(\texttt{A}=\{get,put\}\)
-
\(t^{get} :=\texttt {unit}\rightarrow \texttt{M}\; \texttt {int}\)
-
\(w^{get}:=\lambda ().\lambda h:\texttt {int}.\lambda p:(\texttt {int}\rightarrow \texttt {int}\rightarrow \texttt {prop}). p\;h\;h\)
-
\(t^{put} :=\texttt {int}\rightarrow \texttt{M}\; \texttt {unit}\)
-
\(w^{put}:=\lambda x:\texttt {int}.\lambda h:\texttt {int}.\lambda p:(\texttt {unit}\rightarrow \texttt {int}\rightarrow \texttt {prop}). p\;\texttt {()}\;x\)
-
These parameters can be obtained by applying the state monad transformer to the continuation monad. Note that \(w^{get}\) and \(w^{put}\) have types \(\texttt {unit}\rightarrow \texttt{W}\;\texttt {int}\) and \(\texttt {int}\rightarrow \texttt{W}\;\texttt {unit}\) respectively, obtained from \(t^{get}\) and \(t^{put}\) by replacing \(\texttt{M}\) with \(\texttt{W}\).
Given the effect parameters above, the semantics of the language can be given as a predicate transformer semantics. We omit the definition here, as the translation from programs to HFL(Z) formulas given in Section 3.3 can actually be viewed as the predicate transformer semantics (although the authors [9, 17] did not provide that observation).
3.2 The Dijkstra Monad Approach

Typing rules of DM for expressions


Typing rules of DM for predicate transformers
The rules DM-Ret and DM-LetIn reveal that the Dijkstra monad \(\texttt{D}\; a\; w\) is a monad indexed by the monad \(\texttt{W}\) of predicate transformers. The monadic operators \(\mathtt {return^{W}}\) and \(\mathtt {bind^{W}}\) of \(\texttt{W}\) are used in the typing rules of return expressions and let-in expressions, respectively. When a pure expression is lifted to an effectful computation using the return expression, it is injected into the predicate transformer using \(\mathtt {return^{W}}\). The predicate transformer of a let-expression is computed by composing the two predicate transformers of its two sub-expressions using \(\mathtt {bind^{W}}\).



Example 3

Dummy
3.3 The HFL(Z) Approach
This subsection formalizes a translation from a program to a HFL(Z) formula, which represents the predicate transformer of the program. HFL(Z) is a higher-order logic with least/greatest fixpoints and integers, introduced by Kobayashi et al. [9] as an extension of higher-order modal fixpoint logic [16].
HFL(Z) [9] has an associated simple type system to exclude ill-formed formulas. The type system is essentially that of the simply-typed \(\lambda \)-calculus with operators, constant predicates, and logical connectives. A concrete definition of the type system is deferred to the longer version [19]. We assume that HFL(Z) contains, as a sublanguage, the simply-typed \(\lambda \)-calculus assumed in Section 3.1 for describing predicate transformers.
Reduction from Program Verification In this section, we introduce the translation from programs to HFL(Z) formulas.
Example 4
3.4 Formalization of the Correspondence
Now we are ready to formalize the correspondence between the two approaches. We first show that there is a type derivation in the Dijkstra monad approach corresponding to the program transformation of the HFL(Z) approach.

Dummy
Theorem 1
If \(\,\mathrel {\vdash }e: r\), then there exists a predicate transformer \(w\) such that \(\,\mathrel {\vdash ^\textrm{DM}}e: \operatorname {toDM}[r, w] \) and \({w}^\dagger = {e}^{\textrm{HFL}}\).
Example 5
To deal with open terms, we also need to rename variables. This is due to the observation that the DM type abstracts over the behavior of functional parameters using universal quantification of its predicate transformer, while the result of the transformation \({(\cdot )}^\textrm{DMWP}\) takes the translated higher-order predicate as an argument. For example, the function \(\lambda f: (\texttt {int}\rightarrow \texttt{M}\; \texttt {int}).\ f\;0\) can be given the type
while the program transformation yields
. As indicated by the red color,
in
actually corresponds to
in the DM type, rather than \(f\). Based on this observation, we rename \(f\) to \(w_{f}\), by using the substitution \(\sigma _\varGamma \), defined by: \(\sigma _\varGamma (x) = w_{x}\) if \(\varGamma (x)\) contains \(\texttt{M}\) and \(\sigma _\varGamma (x) = x\) otherwise.
Now, the correspondence between the typing rules of DM and the program transformation \({(\cdot )}^\textrm{DMWP}\) on open terms can be stated as the following lemma.
Lemma 1
- 1.
If \(\varGamma \mathrel {\vdash }e: a\), then \({\varGamma }^{\textrm{DM}} \mathrel {\vdash ^\textrm{DM}}e: a\) and \(\sigma _\varGamma ({e}^\textrm{DMWP}) = e\).
- 2.
If \(\varGamma \mathrel {\vdash }e: \texttt{M}\; a\), then \({\varGamma }^{\textrm{DM}} \mathrel {\vdash ^\textrm{DM}}e: \texttt{D}\; a\; \sigma _\varGamma ({e}^\textrm{DMWP}) \), and \({\varGamma }^{\textrm{DM}} \mathrel {\vdash ^\textrm{DM}}\sigma _\varGamma ({e}^\textrm{DMWP}) : \texttt{W}\;a\).
- 3.
If \(\varGamma \mathrel {\vdash }e: t\), then \({\varGamma }^{\textrm{DM}} \mathrel {\vdash ^\textrm{DM}}e: \operatorname {toDM}[t, \sigma _\varGamma ({e}^\textrm{DMWP})] \) and \({\varGamma }^{\textrm{DM}} \mathrel {\vdash ^\textrm{DM}}\sigma _\varGamma ({e}^\textrm{DMWP}) : {t}^{\textrm{WP}}\).
The proof is found in the longer version [19]. As a special case of the lemma above, when the type environment \(\varGamma \) is empty, we have \(\,\mathrel {\vdash ^\textrm{DM}}e: \operatorname {toDM}[r, w] \) for \(w= {e}^\textrm{DMWP}\), confirming that \(w={e}^\textrm{DMWP}\) indeed serves as a witness for the condition \(\,\mathrel {\vdash ^\textrm{DM}}e: \operatorname {toDM}[r, w] \) of Theorem 1.
It remains to show \(w={e}^\textrm{DMWP}\) also satisfies \({w}^\dagger = {e}^{\textrm{HFL}}\), the second condition of Theorem 1, as stated in the following lemma.
Lemma 2
If \(\varGamma \mathrel {\vdash }e: r\), then \({{e}^\textrm{DMWP}}^\dagger ={e}^{\textrm{HFL}}\).
We now obtain Theorem 1 as a corollary of the two lemmas above.
Proof
(Theorem 1). Let \(w = {e}^\textrm{DMWP}\). Then by the special cases of Lemmas 1 and 2 where \(\varGamma \) is empty, we have \(\,\mathrel {\vdash ^\textrm{DM}}e: \operatorname {toDM}[r, w] \) and \({w}^\dagger = {e}^{\textrm{HFL}}\).
We now show the converse, i.e., that for every predicate transformer derived in the DM approach, an at least equally good predicate transformer can be obtained in the HFL(Z) approach. We assume that the DM type system is sound with respect to the predicate transformer semantics (as defined in Section 3.3 by the transformation to HFL(Z) formulas), i.e., if \(\mathrel {\vdash ^\textrm{DM}}e: \texttt{D}\; a\; w\) holds, then \(w\) is a sound predicate transformer (even though it may not be the weakest one). Then the following theorem follows immediately from the assumption.
Theorem 2
Suppose \(\vdash e: \texttt{M}\; a\) and \(\mathrel {\vdash ^\textrm{DM}}e:\texttt{D}\; a\; w\). Then for all \(\widetilde{v}\) such that \(\vdash w\,\widetilde{v}:\texttt {prop}\), \(w\;\widetilde{v}\) implies \({e}^{\textrm{HFL}}\ \widetilde{v}\). In particular, in the case of the pure computation monad, \(w\,p\) implies \({e}^{\textrm{HFL}}\ p\) for every predicate \(p\) (that represents the condition on the value returned by \(e\)) of type \(a\rightarrow \texttt {prop}\).
4 Differences between the Two Approaches
In the previous section, we have shown a direct correspondence between the Dijkstra monad approach and the HFL(Z) approach for a restricted fragment of the languages supported by the two approaches. In this section, we discuss what differences arise without the restrictions. The major restrictions on the language considered in the previous section are: (1) Restriction on the inner type of the monad. The type \(a\) inside the monad \(\texttt{M}\; a\) is restricted to \(\texttt {unit}\) or \(\texttt {int}\), and not (pure) functional types such as \(\texttt {int}\rightarrow \texttt {int}\). (2) Restriction to non-nested monads. Nested monadic types like \(\texttt {int}\rightarrow \texttt{M}\; (\texttt {int}\rightarrow \texttt{M}\; \texttt {unit})\) were excluded. (3) Restriction to non-recursive programs. Of the three kinds of restrictions, the first one is not fundamental. The restriction comes from the restriction on the side of HFL(Z). In HFL(Z), the final return type of a function type must be \(\texttt {prop}\) (i.e., the types of functions or predicates are restricted to the form \(\tau _1\rightarrow \cdots \rightarrow \tau _k\rightarrow \texttt {prop}\), and types like \(\texttt {int}\rightarrow \texttt {int}\) are disallowed). That restriction is required in HFL(Z) to ensure that the least/greatest fixpoints always exist. A workaround is to wrap the final return type with a monad, such as using \(\texttt {int}\rightarrow \texttt{M}\; \texttt {int}\) instead of \(\texttt {int}\rightarrow \texttt {int}\). In addition, if we allow only terminating functions by employing a mechanism for checking the termination of functions as in F\(^\star \) , then there would be no problem in removing the restriction on the HFL(Z) side.
The second and third restrictions are more fundamental, revealing important differences between the two approaches, as discussed below.
4.1 On Nested Monads

Dummy
4.2 On Recursive Programs
For recursive programs, there are clear differences between the two approaches. In the DM approach, each recursive function must be annotated with an appropriate type (which includes the predicate transformer) by a programmer, just like invariants for loops and recursive functions must be provided in deductive verification. The obtained predicate transformer is not necessarily the weakest one, depending on the precision of the annotations. In the HFL(Z) approach, no annotations are required for recursive functions, and (a predicate corresponding to) the weakest predicate transformer can be automatically expressed by using fixpoint operators.
The property above is a safety property, but one can mix the least and greatest fixpoint equations to express arbitrary regular temporal properties [9, 17], and its validity can be automatically checked (though the backend HFL(Z) validity checker is necessarily incomplete) [8].
Despite the advantages mentioned above, the HFL(Z) approach has also a disadvantage: automated HFL(Z) validity checkers used in the approach are much less efficient and less predictable than SMT solvers used in the DM approach. The inefficiency and unpredictability are inevitable because HFL(Z) validity checking is undecidable in general. In contrast, the DM approach uses the annotations to reduce the validity checking problem to simpler problems that can be discharged by ordinary SMT solvers. In fact, there are programs that the HFL(Z) approach cannot verify in realistic time, but given appropriate annotations, the DM approach can verify; see Section 5.2 for such an example. The DM approach allows modular verification; by using type annotations, the whole verification problem can be decomposed into small pieces of verification conditions.
-
In the DM approach, users need to provide a type annotation (including predicate transformers) for each recursive function, whereas in the HFL(Z) approach, there is no such need. The HFL(Z) approach can deal with not only partial/total correctness but also arbitrary regular temporal properties.
-
The DM approach requires only an ordinary SMT solver as a backend, which is more efficient and predictable than a higher fixpoint logic solver required in the HFL(Z) approach. The former is thus more suitable for interactive program development.
-
The DM approach admits modular verification, and thus it is more scalable to large programs than the HFL(Z) approach, by taking advantage of the annotations given by users.
5 Semi-Automated Program Verification Using \(\nu \)HFL(Z)
Based on the observations of the similarities and differences between the DM and HFL(Z) approaches, we introduce a semi-automated verification method to take the best of two approaches in this section.
5.1 Overview of Our Approach
In general, given (i) a main formula \(\varphi \), (ii) a set \(D_1\cup D_2\) of fixpoint equations on \(\nu \)HFL(Z) predicates, and (iii) type environments \(\varDelta _1\) for \(D_1\) (which are automatically derived from type annotations), we can reduce the validity of \(\varphi \) to the following type checking problems, thanks to the soundness of the refinement type system for \(\nu \)HFL(Z) [6, 7].
-
Are the type annotations valid, i.e., does there exist a type environment \(\varDelta _2\) for \( D_2 \), such that \(\varDelta _1,\varDelta _2\vdash ^{\texttt {RT}}{\varphi _P} :\rho \) for each type binding \(P:\rho \) in \(\varDelta _1,\varDelta _2\)?
-
Is the main formula valid, i.e., does there exist a type environment \(\varDelta _2\) for \( D_2 \), such that \(\varDelta _1,\varDelta _2\vdash ^{\texttt {RT}}\varphi :\bullet [\textsf{true}]\) and \(\varDelta _1, \varDelta _2 \vdash ^{\texttt {RT}}{\varphi _P} :\rho \) for each type binding \(P:\rho \) in \(\varDelta _2\)?
Here, \(\varDelta \vdash ^{\texttt {RT}}\varphi :\rho \) is the type judgment relation as defined in [6] (whose details are not important here) and \( \varphi _P \) is the body of \( P \). Thus, partial type annotations enable modular verification, which is expected to be more scalable and predictable than the original HFL(Z) approach. In the above decomposition of the verification problem, the weakest predicate transformers are automatically computed and used for unannotated functions, thanks to the expressive power of HFL(Z). (In contrast, the implementation of DM in F* does seem to allow some type annotations to be omitted, but in that case, very imprecise predicate transformers would be used for unannotated recursive functions.)
5.2 Experiments
We extended the existing type-based \(\nu \)HFL(Z) validity checker, ReTHFL [6] to allow partial type annotations, and conducted experiments to confirm the effectiveness of our approach.8 Currently, the type annotations need to be provided for \(\nu \)HFL(Z) formulas rather than for source programs. As discussed in Section 5.1, it is easy to automatically convert the Hoare-monad-style type annotations for source programs (which may be considered a restricted form of DM-style type annotations) to type annotations for \(\nu \)HFL(Z) formulas; it is left for future work to implement such a converter to make annotations easier.
In the experiment we used a Linux server equipped with Intel Xeon Gold 6242 Processor @ 2.80 GHz, with 16 cores, and 64 GB of RAM. For each (sub-)problem, we ran each tool five times and calculated the average execution time. Since the performance of the validity checker depends strongly on the performance of the underlying Constrained Horn Clause (CHC) solver, we used both Z3/Spacer [10] and HoIce [3] as underlying CHC solvers and show only the best of their results for each problem; in other words, the reported verification times indicate those in case the backend solvers Z3/Spacer [10] and HoIce [3] are called in parallel.
Comparison between the original fully automated method by Katsura et al. [6] and our semi-automated method (timeout = 300 seconds)

Dummy
The experimental results are shown in Table 2. In the table, we show the sizes of programs and annotations in terms of bytes for a fair comparison between the sizes of programs and annotations (as it is possible to write a type annotation in one long line). The first row of each program shows the result of the original version of ReTHFL. As it is a fully automated checker, no annotations were provided. The rest of the rows show the results of our method. The “Method” column shows the name of the function annotated and the annotation size. In the rest of the columns, “X / Y” means that X is the result of the sub-problem (a) that checks the correctness of the annotation and Y is the result of the sub-problem (b) that checks the validity of the whole formula.
For all runs of each sub-problem, our tool successfully checked the validity and terminated within a few seconds. This confirms the effectiveness of our approach and the behavior of the tool is much more predictable than the fully-automated verification using the original ReTHFL. We think the size of annotations is acceptable; actually, the annotation size would become smaller, if we allow a user to provide annotations for source programs rather than for HFL(Z) formulas.
The results also support the advantage of our method over the DM approach in reducing the annotation burdens. While the DM approach requires an annotation for every recursive function, our method succeded given only one annotated function for each program.
6 Related Work
The Dijkstra Monad Approach and the HFL(Z) Approach. The framework of Dijkstra monads was first introduced by Swamy et al. [15] as a general method for the verification of higher-order programs with monadic effects. To define a Dijkstra monad that is consistent with the semantics of the effect, Ahman et al. [1] showed that CPS transformation of the monadic model of the effect yields such a correct monad. This result is closely related to our observation of the similarity with the HFL(Z) approach. As we mentioned in Section 3.4, Lemma 1, which is part of the proof of the correspondence theorem, generalizes Theorem 6 of Ahman et al. to be parameterized by effect parameters. A successive study by Maillard et al. [12] reinterpreted and extended the framework by considering a Dijkstra monad as two monads—a computational monad and a specification monad—related by a monad morphism.
The HFL(Z) approach was proposed by Kobayashi et al. [9, 17], which supports the verification of temporal properties of higher-order programs with general recursion. Watanabe et al. [17] extended the approach to the verification of arbitrary regular linear/branching-time properties expressible in alternating parity tree automata. Following those studies, fully automated HFL(Z) validity checkers have been developed [5–8], which, in combination with the above-mentioned reductions [9, 17], yielded fully automated verification tools for higher-order functional programs. As discussed already, while the fully automated approach is attractive for verification of small programs, it suffers from (non-)scalability and unpredictability issues for large programs.
Most of the previous studies on Dijkstra monads have considered only partial or total correctness, while the HFL(Z) approach supports a wide range of temporal properties of possibly divergent programs. An exception is the work of Silver and Zdancewic [14], which can deal with termination-sensitive properties of possibly divergent programs with monadic effects. The behavior of such programs is expressed using interaction trees [18], a coinductive data structure with effects as internal nodes and resulting values as leaves. The idea of expressing computations as possibly infinite trees is shared with the work of Watanabe et al. [17] in the HFL(Z) approach, where the behavior of a possibly non-terminating program is modeled by a possibly infinite tree of (abstract) events. It is left for future work to extend our result in Section 3 to establish a precise relationship between those studies.
Predicate Transformers for Higher-Order Programs. Kura [11] considered a general categorical framework for a higher-order language with effects and recursion, and showed that the (semantically defined) weakest precondition transformer of a program can be obtained by the CPS transformation. He has shown that a fragment of the HFL(Z) approach [9] can be understood as an instance of his result. He did not show, however, a direct correspondence between the DM and HFL(Z) approaches. Another related approach to higher-order program verification based on predicate transformers is Charguéraud’s work [4]. He showed a construction of a characteristic formula \([\![t]\!]\) for a term \(t\), such that \([\![t]\!]\,P\) is valid if and only if \(t\) satisfies the postcondition \(P\). Thus, \([\![t]\!]\) can be viewed as a predicate transformer. Charguéraud’s approach is motivated by interactive verification using a proof assistant, while the HFL(Z) approach is motivated by automated verification. This difference in the motivations seems to have led to the difference in the choice of logics. Charguéraud used a more expressive higher-order logic (like that of Coq) than HFL(Z) to express characteristic formulae so that the characteristic formula \([\![t]\!]\) has almost the same shape as the original term \(t\). In contrast, HFL(Z) is designed to be a minimal higher-order logic for ease of automation.
7 Conclusion
This paper studied the relationship between two approaches to higher-order program verification: the Dijkstra monad approach and the HFL(Z) approach. We showed the correspondence between them in a restricted setting, and discussed the differences between the two approaches outside the restriction. Although the two approaches are closely related in the restricted fragment, the full systems have some different strengths. Based on this observation, we proposed a semi-automated verification method and experimentally confirmed that our method can verify programs that cannot be verified by the existing HFL(Z)-based automated tool, with fewer annotations than in the DM approach. A full integration between the two approaches is left for future work.
Acknowledgment
We would like to thank anonymous referees for useful comments.
This work was supported by JSPS KAKENHI Numbers Grant JP20H05703 and JP24K20731.
Open Access This chapter is licensed under the terms of the Creative Commons Attribution 4.0 International License (http://creativecommons.org/licenses/by/4.0/), which permits use, sharing, adaptation, distribution and reproduction in any medium or format, as long as you give appropriate credit to the original author(s) and the source, provide a link to the Creative Commons license and indicate if changes were made.
The images or other third party material in this chapter are included in the chapter's Creative Commons license, unless indicated otherwise in a credit line to the material. If material is not included in the chapter's Creative Commons license and your intended use is not permitted by statutory regulation or exceeds the permitted use, you will need to obtain permission directly from the copyright holder.