• Top
    • Documentation
    • Books
    • Boolean-reasoning
    • Projects
    • Debugging
    • Std
    • Proof-automation
    • Macro-libraries
    • ACL2
      • Theories
      • Rule-classes
      • Proof-builder
      • Recursion-and-induction
      • Hons-and-memoization
      • Events
        • Defun
        • Verify-guards
        • Table
        • Mutual-recursion
          • Defines
            • Make-flag
            • Mutual-recursion-proof-example
            • Def-doublevar-induction
            • Set-bogus-mutual-recursion-ok
            • Defuns
          • Memoize
          • Make-event
          • Include-book
          • Encapsulate
          • Defun-sk
          • Defttag
          • Defstobj
          • Defpkg
          • Defattach
          • Defabsstobj
          • Defchoose
          • Progn
          • Verify-termination
          • Redundant-events
          • Defmacro
          • Defconst
          • Skip-proofs
          • In-theory
          • Embedded-event-form
          • Value-triple
          • Comp
          • Local
          • Defthm
          • Progn!
          • Defevaluator
          • Theory-invariant
          • Assert-event
          • Defun-inline
          • Project-dir-alist
          • Partial-encapsulate
          • Define-trusted-clause-processor
          • Defproxy
          • Defexec
          • Defun-nx
          • Defthmg
          • Defpun
          • Defabbrev
          • Set-table-guard
          • Name
          • Defrec
          • Add-custom-keyword-hint
          • Regenerate-tau-database
          • Defcong
          • Deftheory
          • Defaxiom
          • Deftheory-static
          • Defund
          • Evisc-table
          • Verify-guards+
          • Logical-name
          • Profile
          • Defequiv
          • Defmacro-untouchable
          • Add-global-stobj
          • Defthmr
          • Defstub
          • Defrefinement
          • Deflabel
          • In-arithmetic-theory
          • Unmemoize
          • Defabsstobj-missing-events
          • Defthmd
          • Fake-event
          • Set-body
          • Defun-notinline
          • Functions-after
          • Macros-after
          • Dump-events
          • Defund-nx
          • Defun$
          • Remove-global-stobj
          • Remove-custom-keyword-hint
          • Dft
          • Defthy
          • Defund-notinline
          • Defnd
          • Defn
          • Defund-inline
          • Defmacro-last
        • Parallelism
        • History
        • Programming
        • Operational-semantics
        • Real
        • Start-here
        • Debugging
        • Miscellaneous
        • Output-controls
        • Macros
        • Interfacing-tools
      • Interfacing-tools
      • Hardware-verification
      • Software-verification
      • Math
      • Testing-utilities
    • Std/util
    • Mutual-recursion

    Defines

    A very fine alternative to mutual-recursion.

    Defines is a sophisticated macro for introducing mutually recursive functions using define. It gives you:

    • The usual benefits of define—extended-formals, concise xargs syntax, returns-specifiers, xdoc integration, easy inlining, and so on.
    • Automatic ACL2::make-flag integration, so you can easily prove inductive theorems about your new definitions.

    Examples

      (defines terms
        :parents (syntax)
        :short "Example of terms in some simple, numeric language."
    
        (define my-termp (x)
          (if (atom x)
              (natp x)
            (and (symbolp (car x))
                 (my-term-listp (cdr x))))
          ///
          (defthm natp-when-my-termp
            (implies (atom x)
                     (equal (my-termp x)
                            (natp x))))
          (defthm my-termp-of-cons
            (equal (my-termp (cons fn args))
                   (and (symbolp fn)
                        (my-term-listp args)))))
    
        (define my-term-listp (x)
          (if (atom x)
              t
            (and (my-termp (car x))
                 (my-term-listp (cdr x))))
          ///
          (deflist my-term-listp (x)
            (my-termp x)
            :already-definedp t)))
    
    (defines flattening
      :parents (terms)
      :short "Collect up the arguments of terms."
    
      (define my-flatten-term ((x my-termp))
        :flag term
        :returns (numbers true-listp :rule-classes :type-prescription)
        (if (atom x)
            (list x)
          (my-flatten-term-list (cdr x))))
    
      (define my-flatten-term-list ((x my-term-listp))
        :flag list
        :returns (numbers true-listp :rule-classes :type-prescription)
        (if (atom x)
            nil
          (append (my-flatten-term (car x))
                  (my-flatten-term-list (cdr x)))))
      ///
      (defthm-flattening-flag
        (defthm nat-listp-of-my-flatten-term
          (implies (my-termp x)
                   (nat-listp (my-flatten-term x)))
          :flag term)
        (defthm nat-listp-of-my-flatten-term-list
          (implies (my-term-listp x)
                   (nat-listp (my-flatten-term-list x)))
          :flag list)))

    Usage

    The general form of defines is:

    (defines clique-name
      [global options]
      (define f1 ...)
      ...
      (define fN ...)
      [/// other-events])

    The clique-name may be any symbol—we often just use the name of the first function in the clique, but this is not required. The name is used for documentation purposes, and also (by default) is used to name the flag function that will be introduced by ACL2::make-flag.

    The global options each have the form :name value, and we describe these options below. We usually prefer to put these options at the front of the defines form, as shown above, but the options can be put anywhere until the /// form.

    There must be at least two define forms. These can use the usual define syntax, and mostly this all works out naturally. The most significant caveats have to do with how we try to prove the theorems for :returns specifiers (see below).

    The other-events are a structuring device that allow you to associate any arbitrary events. These events are submitted after the definitions, flag function, etc., have been processed. All of the functions in the clique are left enabled while processing these events.

    Note that individual defines can have their own other-events. All of these individual sections are processed (with their own local scopes) before any global other-events.

    Global Options

    :verbosep bool
    Normally most output is suppressed, but this can make it hard to understand failures. You can enable :verbosep t for better debugging.
    :mode
    :guard-hints, :guard-debug
    :verify-guards val
    The value val may be one of the following: t, nil, or :after-returns. The first two correspond to what is described in xargs. The keyword :after-returns indicates that the guards of the functions are to be verified after the returns-specifiers.
    :well-founded-relation, :measure-debug, :hints, :otf-flg
    :ruler-extenders
    In an ordinary mutual-recursion, each of these xargs style options can be attached to any defun in the clique. But we usually think of these as global options to the whole clique, so we make them available as top-level options to the defines form. In the implementation, we just attach these options to the first defun form generated, except for :ruler-extenders, which we apply to all of the defuns.
    :prepwork
    Arbitrary events to be submitted before the definitions. Typically this might include in-theory calls, one-off supporting lemmas, etc. Prepwork is not automatically local, so lemmas and theory changes should usually be explicitly made local.
    Note that each individual define may have its own :prepwork section. All of these sections will be appended together in order, with the global :prepwork coming first, and submitted before the definitions.
    :returns-hints hints
    :returns-no-induct bool
    You can give hints for the inductive :returns theorem. Alternately, if you know you don't need to prove the returns theorems inductively, you can set :returns-no-induct t, which may improve performance.
    :parents, :short, :long
    These are global xdoc options that will be associated with the clique-name for this defines.
    Note that each individual define may separately have its own documentation and rest-events. As a convenience, if global documentation is provided while individual documentation is not, a basic topic will be created whose :parents point at the clique-name.
    A corner case is when the clique-name agrees with an individual function's name. In this case we try to grab the documentation from either the named function or the global options. To prevent confusion, we cause an error if documentation is provided in both places.
    :ignore-ok val
    :irrelevant-formals-ok val
    :bogus-ok val
    Submit set-ignore-ok, set-irrelevant-formals-ok, and/or set-bogus-mutual-recursion-ok forms before the definitions. These options are local to the definitions; they do not affect the other-events or any later events.
    :flag name
    You can also use :flag nil to suppress the creation of a flag function. Alternately, you can use this option to customize the name of the flag function. The default is inferred from the clique-name, i.e., it will look like <clique-name>-flag.
    :flag-var var
    :flag-defthm-macro name
    :flag-hints hints
    Control the flag variable name, flag macro name, and hints for ACL2::make-flag.
    :flag-local bool
    By default the flag function is created locally. This generally improves performance when later including your book, and is appropriate when all of your flag-based reasoning about the function is done in :returns specifiers and in the /// section. If you need the flag function and its macros to exist beyond the defines form, set :flag-local nil.
    :progn bool
    By default everything is submitted in an (encapsulate nil ...). If you set :progn t, then we will instead submit everything in a progn. This mainly affects what local means within the /// section. This may slightly improve performance by avoiding the overhead of encapsulate, and is mainly meant as a tool for macro developers.