Check if a term is a (translated) call of mv-let.
(check-mv-let-call term) → (mv yes/no mv-var vars indices hides mv-term body-term)
In translated form,
((lambda (mv) ((lambda (var1 ... varn) body-term-trans) (mv-nth '0 mv) ... (mv-nth 'n-1 mv))) mv-term-trans)
where
This utility checks if a translated term has the form above;
it also checks that
If the input term has the form above,
it is not necessarily the result of translating mv-let.
It could be the translation of
Note, however, that lambda expressions are always closed in translated terms directly obtained from untranslated terms. ACL2 accomplishes this closure by adding formal parameters to the lambda expressions for the otherwise free variables, and adding actual arguments identical to those variables; see remove-trivial-vars. This means that the lambda expressions above may have extra variables. To ``correct'' for this, before examining the two lambda expressions, we remove all their formal parameters that are identical to the corresponding arguments, via remove-trivial-vars's auxiliary function remove-equal-formals-actuals, which does exactly that. We do not use remove-trivial-vars because that one removes the trivial variables at all levels, while here we only want to remove the ones from the two lambda expressions being examined.
Note also that, due to this lambda expression closure,
the
:trans (let ((mv 0)) (mv-let (x y) (f mv) (list x y mv)))
produces a translated term with the symbol `
In translated terms directly obtained from untranslated terms,
mv-lets always have
An additional complication derives from the fact that mv-let
allows the declaration of ignored variables within, e.g.
((lambda (mv) ((lambda (x y z) z) (hide (mv-nth '0 mv)) (hide (mv-nth '1 mv)) (mv-nth '2 mv))) (cons '1 (cons '2 (cons '3 'nil))))
This utility takes this possibility into account, and returns, as an additional result, a list of booleans, of the same length as variables and indices, that says whether the corresponding mv-nth is wrapped by hide or not. This way, the utility returns all the information about the term, which the caller may use as desired.
mv-let also support the declaration of ignorable variables. But these declarations do not introduce any hide wrapper or other change into the translated term.
This utility is a left inverse of make-mv-let-call.
Function:
(defun check-mv-let-call-aux (terms min-index mv-var) (declare (xargs :guard (and (pseudo-term-listp terms) (natp min-index) (symbolp mv-var)))) (let ((__function__ 'check-mv-let-call-aux)) (declare (ignorable __function__)) (b* (((when (endp terms)) (mv t nil nil)) (term (car terms)) ((mv hide term) (if (and (true-listp term) (consp term) (consp (cdr term)) (atom (cddr term)) (eq (car term) 'hide)) (mv t (cadr term)) (mv nil term))) ((unless (and (true-listp term) (consp term) (consp (cdr term)) (consp (cddr term)) (atom (cdddr term)))) (mv nil nil nil)) ((unless (eq (car term) 'mv-nth)) (mv nil nil nil)) (index-term (cadr term)) ((unless (eq (caddr term) mv-var)) (mv nil nil nil)) ((unless (quotep index-term)) (mv nil nil nil)) (index (unquote index-term)) ((unless (natp index)) (mv nil nil nil)) ((unless (>= index min-index)) (mv nil nil nil)) ((mv yes/no indices hides) (check-mv-let-call-aux (cdr terms) (1+ index) mv-var)) ((unless yes/no) (mv nil nil nil))) (mv t (cons index indices) (cons hide hides)))))
Theorem:
(defthm booleanp-of-check-mv-let-call-aux.yes/no (b* (((mv ?yes/no ?indices ?hides) (check-mv-let-call-aux terms min-index mv-var))) (booleanp yes/no)) :rule-classes :rewrite)
Theorem:
(defthm nat-listp-of-check-mv-let-call-aux.indices (b* (((mv ?yes/no ?indices ?hides) (check-mv-let-call-aux terms min-index mv-var))) (nat-listp indices)) :rule-classes :rewrite)
Theorem:
(defthm boolean-listp-of-check-mv-let-call-aux.hides (b* (((mv ?yes/no ?indices ?hides) (check-mv-let-call-aux terms min-index mv-var))) (boolean-listp hides)) :rule-classes :rewrite)
Theorem:
(defthm len-of-check-mv-let-call-aux.indices (b* (((mv ?yes/no ?indices ?hides) (check-mv-let-call-aux terms min-index mv-var))) (implies yes/no (equal (len indices) (len terms)))))
Theorem:
(defthm len-of-check-mv-let-call-aux.hides (b* (((mv ?yes/no ?indices ?hides) (check-mv-let-call-aux terms min-index mv-var))) (implies yes/no (equal (len hides) (len terms)))))
Function:
(defun check-mv-let-call (term) (declare (xargs :guard (pseudo-termp term))) (let ((__function__ 'check-mv-let-call)) (declare (ignorable __function__)) (b* (((when (variablep term)) (mv nil nil nil nil nil nil nil)) ((when (fquotep term)) (mv nil nil nil nil nil nil nil)) ((unless (flambda-applicationp term)) (mv nil nil nil nil nil nil nil)) (outer-lambda-expr (ffn-symb term)) (formals (lambda-formals outer-lambda-expr)) (actuals (fargs term)) ((mv list-mv list-mv-term) (remove-equal-formals-actuals formals actuals)) ((unless (and (consp list-mv) (not (consp (cdr list-mv))))) (mv nil nil nil nil nil nil nil)) (mv-var (car list-mv)) ((unless (and (consp list-mv-term) (not (consp (cdr list-mv-term))))) (mv nil nil nil nil nil nil nil)) (mv-term (car list-mv-term)) (inner-lambda-expr-call (lambda-body outer-lambda-expr)) ((when (variablep inner-lambda-expr-call)) (mv nil nil nil nil nil nil nil)) ((when (fquotep inner-lambda-expr-call)) (mv nil nil nil nil nil nil nil)) ((unless (flambda-applicationp inner-lambda-expr-call)) (mv nil nil nil nil nil nil nil)) (inner-lambda-expr (ffn-symb inner-lambda-expr-call)) (formals (lambda-formals inner-lambda-expr)) (actuals (fargs inner-lambda-expr-call)) ((mv vars mv-nths) (remove-equal-formals-actuals formals actuals)) (body-term (lambda-body inner-lambda-expr)) ((when (dumb-occur-var-open mv-var body-term)) (mv nil nil nil nil nil nil nil)) ((mv okp indices hides) (check-mv-let-call-aux mv-nths 0 mv-var)) ((unless okp) (mv nil nil nil nil nil nil nil))) (mv t mv-var vars indices hides mv-term body-term))))
Theorem:
(defthm booleanp-of-check-mv-let-call.yes/no (b* (((mv ?yes/no ?mv-var ?vars ?indices ?hides ?mv-term ?body-term) (check-mv-let-call term))) (booleanp yes/no)) :rule-classes :rewrite)
Theorem:
(defthm symbolp-of-check-mv-let-call.mv-var (implies (and (pseudo-termp term)) (b* (((mv ?yes/no ?mv-var ?vars ?indices ?hides ?mv-term ?body-term) (check-mv-let-call term))) (symbolp mv-var))) :rule-classes :rewrite)
Theorem:
(defthm symbol-listp-of-check-mv-let-call.vars (implies (and (pseudo-termp term)) (b* (((mv ?yes/no ?mv-var ?vars ?indices ?hides ?mv-term ?body-term) (check-mv-let-call term))) (symbol-listp vars))) :rule-classes :rewrite)
Theorem:
(defthm nat-listp-of-check-mv-let-call.indices (b* (((mv ?yes/no ?mv-var ?vars ?indices ?hides ?mv-term ?body-term) (check-mv-let-call term))) (nat-listp indices)) :rule-classes :rewrite)
Theorem:
(defthm boolean-listp-of-check-mv-let-call.hides (b* (((mv ?yes/no ?mv-var ?vars ?indices ?hides ?mv-term ?body-term) (check-mv-let-call term))) (boolean-listp hides)) :rule-classes :rewrite)
Theorem:
(defthm pseudo-termp-of-check-mv-let-call.mv-term (implies (and (pseudo-termp term)) (b* (((mv ?yes/no ?mv-var ?vars ?indices ?hides ?mv-term ?body-term) (check-mv-let-call term))) (pseudo-termp mv-term))) :rule-classes :rewrite)
Theorem:
(defthm pseudo-termp-of-check-mv-let-call.body-term (implies (and (pseudo-termp term)) (b* (((mv ?yes/no ?mv-var ?vars ?indices ?hides ?mv-term ?body-term) (check-mv-let-call term))) (pseudo-termp body-term))) :rule-classes :rewrite)
Theorem:
(defthm len-of-check-mv-let-call.indices/vars (implies (and (pseudo-termp term)) (b* (((mv ?yes/no ?mv-var ?vars ?indices ?hides ?mv-term ?body-term) (check-mv-let-call term))) (implies yes/no (equal (len indices) (len vars))))))
Theorem:
(defthm len-of-check-mv-let-call.hides/vars (implies (and (pseudo-termp term)) (b* (((mv ?yes/no ?mv-var ?vars ?indices ?hides ?mv-term ?body-term) (check-mv-let-call term))) (implies yes/no (equal (len hides) (len vars))))))
Theorem:
(defthm acl2-count-of-check-mv-let-call.mv-term (b* (((mv ?yes/no ?mv-var ?vars ?indices ?hides ?mv-term ?body-term) (check-mv-let-call term))) (implies yes/no (< (acl2-count mv-term) (acl2-count term)))) :rule-classes :linear)
Theorem:
(defthm acl2-count-of-check-mv-let-call.body-term (b* (((mv ?yes/no ?mv-var ?vars ?indices ?hides ?mv-term ?body-term) (check-mv-let-call term))) (implies yes/no (< (acl2-count body-term) (acl2-count term)))) :rule-classes :linear)