Notion of general folds for fixtypes.
The FTY library provides event macros to introduce algebraic data types. Algebraic data types have a naturally associated notion of general folds. Thus, it makes sense for the FTY library to also provide event macros to introduce folds. This manual page describes, via an example, the notion of general folds for algebraic data types; it also discusses ideas for FTY event macros to introduce folds.
Consider the following mutually recursive data types, for a form of arithmetic and boolean expressions:
(deftypes exprs (deftagsum aexpr (:const ((value acl2::int))) (:var ((name string))) (:add ((left aexpr) (right aexpr))) (:cond ((test bexpr) (left aexpr) (right aexpr))) :pred aexprp) (deftagsum bexpr (:true ()) (:false ()) (:and ((left bexpr) (right bexpr))) (:less ((left aexpr) (right aexpr))) :pred bexprp))
This introduces two mutually recursive data types, which we can write as follows in more common notation, where the constructors are curried:
type aexpr = const int | var string | add aexpr aexpr | neg aexpr | cond bexpr aexpr aexpr type bexpr = true | false | and bexpr bexpr | less aexpr aexpr
A general fold over these two types consists of two higher-order functions, one per type, with the following types:
afold<A,B> : (int -> A) -> (string -> A) -> (A -> A -> A) -> (A -> A) -> (B -> A -> A -> A) -> (aexpr -> A) bfold<A,B> : B -> B -> (B -> B -> B) -> (A -> A -> B) -> (bexpr -> B)
These functions are parameterized over types
These functions are defined as follows:
afold f_const f_var f_add f_neg f_cond (const i) = f_const i afold f_const f_var f_add f_neg f_cond (var s) = f_var s afold f_const f_var f_add f_neg f_cond (add a1 a2) = f_add (afold f_const f_var f_add f_neg f_cond a1) (afold f_const f_var f_add f_neg f_cond a2) afold f_const f_var f_add f_neg f_cond (neg a) = f_neg (afold f_const f_var f_add f_neg f_cond a1) afold f_const f_var f_add f_neg f_cond (cond b a1 a2) = f_cond (bfold c_true c_false f_and f_less b) (afold f_const f_var f_add f_cond a1) (afold f_const f_var f_add f_cond a2) bfold c_true c_false f_and f_less true = c_true bfold c_true c_false f_and f_less false = c_false bfold c_true c_false f_and f_less (and b1 b2) = f_and (bfold c_true c_false f_and f_less b1) (bfold c_true c_false f_and f_less b2) bfold c_true c_false f_and f_less (less a1 a2) = f_less (afold f_const f_var f_add f_cond a1) (afold f_const f_var f_add f_cond a2)
In other words, the folds ``replace'' each constructor of the data types with the corresponding constant or function passed as argument. Recall that every value of the data types is expressible as a ground term over the constructors. For instance, we have
afold ... (add (const 3) (var "x")) = (f_add (f_const 3) (f_var "x"))
where
There are many different possible choices for the folds'
result types (
The deffold-reduce event macro generates reducing folds. We plan to add an event macro to generate mapping folds as well.