Terms are fully-shared via hash-consing. Alpha-equivalent terms have the same identifier.
*)
signature ARGO_TERM = sig (* data types *) type meta datatype term = T of meta * Argo_Expr.kind * term list
(* term operations *) val id_of: term -> int val expr_of: term -> Argo_Expr.expr val type_of: term -> Argo_Expr.typ val eq_term: term * term -> bool val term_ord: term ord
(* context *) type context val context: context
(* identifying expressions *) datatype item = Expr of Argo_Expr.expr | Term of term datatype identified = New of term | Known of term val identify_item: item -> context -> identified * context end
structure Argo_Term: ARGO_TERM = struct
(* data types *)
(* The type meta is intentionally hidden to prevent that functions outside of this structure are able to build terms. Meta stores the identifier of the term as well as the complete expression underlying the term.
*)
datatype meta = M of int * Argo_Expr.expr datatype term = T of meta * Argo_Expr.kind * term list
(* term operations *)
fun id_of (T (M (id, _), _, _)) = id fun expr_of (T (M (_, e), _, _)) = e fun type_of t = Argo_Expr.type_of (expr_of t)
(* Comparing terms is fast as only the identifiers are compared. No expressions need to be taken into account.
*)
fun eq_term (t1, t2) = (id_of t1 = id_of t2) fun term_ord (t1, t2) = int_ord (id_of t1, id_of t2)
(* sharing of terms *)
(* Kinds are short representation of expressions. Constants and numbers carry additional information and have no arguments. Their kind is hence similar to them. All other expressions are stored in a flat way with identifiers of shared terms as arguments instead of expression as arguments.
*)
datatype kind =
Con ofstring * Argo_Expr.typ |
Num of Rat.rat |
Exp of int list
fun kind_of (Argo_Expr.E (Argo_Expr.Con c, _)) _ = Con c
| kind_of (Argo_Expr.E (Argo_Expr.Num n, _)) _ = Num n
| kind_of (Argo_Expr.E (k, _)) is = Exp (Argo_Expr.int_of_kind k :: is)
(* The context keeps track of the next unused identifier as well as all shared terms, which are indexed by their unique kind. For each term, a boolean marker flag is stored. When set to true on an atom, the atom is already asserted to the solver core. When set to true on an if-then-else term, the term has already been lifted.
Zero is intentionally avoided as identifier, since literals use term identifiers with a sign as literal identifiers.
*)
fun with_unique_id kind is_atom (e as Argo_Expr.E (k, _)) ts ({next_id, terms}: context) = letval t = T (M (next_id, e), k, ts) in ((t, false), mk_context (next_id + 1) (Kindtab.update (kind, (t, is_atom)) terms)) end
fun unique kind is_atom e ts (cx as {terms, ...}: context) =
(case Kindtab.lookup terms kind of
SOME tp => (tp, note_atom is_atom kind tp cx)
| NONE => with_unique_id kind is_atom e ts cx)
(* identifying expressions *)
(* Only atoms, i.e., boolean propositons, and if-then-else expressions need to be identified. Other terms are identified implicitly. The identification process works bottom-up.
The solver core needs to know whether an atom has already been added. Likewise, the clausifier needs to know whether an if-then-else expression has already been lifted. Therefore, the identified term is marked as either "new" when identified for the first time or "known" when it has already been identified before.
*)
datatype item = Expr of Argo_Expr.expr | Term of term datatype identified = New of term | Known of term
fun identify_head is_atom e (ts, cx) = unique (kind_of e (map id_of ts)) is_atom e ts cx
fun identify is_atom (e as Argo_Expr.E (_, es)) cx =
identify_head is_atom e (fold_map (apfst fst oo identify false) es cx)
fun identified (t, true) = Known t
| identified (t, false) = New t
fun identify_item (Expr e) cx = identify true e cx |>> identified
| identify_item (Term (t as T (_, _, ts))) cx =
identify_head true (expr_of t) (ts, cx) |>> identified
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.