• Top
    • Documentation
    • Books
    • Boolean-reasoning
    • Projects
    • Debugging
    • Std
    • Proof-automation
    • Macro-libraries
    • ACL2
    • Interfacing-tools
    • Hardware-verification
    • Software-verification
      • Kestrel-books
        • Crypto-hdwallet
        • Apt
        • Error-checking
        • Fty-extensions
        • Isar
        • Kestrel-utilities
        • Set
        • Soft
        • C
        • Bv
        • Imp-language
        • Event-macros
        • Java
          • Atj
            • Atj-implementation
            • Atj-tutorial
              • Atj-tutorial-deep
              • Atj-tutorial-ACL2-values
              • Atj-tutorial-native-functions
              • Atj-tutorial-deep-guards
              • Atj-tutorial-ACL2-terms
              • Atj-tutorial-evaluator
              • Atj-tutorial-background
                • Atj-tutorial-ACL2-environment
                • Atj-tutorial-translated
                • Atj-tutorial-shallow
                • Atj-tutorial-tests
                • Atj-tutorial-customization
                • Atj-tutorial-motivation
                • Atj-tutorial-deep-shallow
                • Atj-tutorial-screen-output
                • Atj-tutorial-shallow-guards
                • Atj-tutorial-simplified-uml
                • Atj-tutorial-aij
            • Aij
            • Language
          • Bitcoin
          • Ethereum
          • Yul
          • Zcash
          • ACL2-programming-language
          • Prime-fields
          • Json
          • Syntheto
          • File-io-light
          • Cryptography
          • Number-theory
          • Lists-light
          • Axe
          • Builtins
          • Solidity
          • Helpers
          • Htclient
          • Typed-lists-light
          • Arithmetic-light
        • X86isa
        • Axe
        • Execloader
      • Math
      • Testing-utilities
    • Atj-tutorial

    Atj-tutorial-background

    ATJ tutorial: Background on the Evaluation Semantics of ACL2.

    In the context of translating from the ACL2 language to Java or any other programming language, it is important to consider not only ACL2's logical semantics, but also ACL2's evaluation semantics. This tutorial page provides some background on ACL2's evaluation semantics. This tutorial page may be perhaps skipped at first reading, especially if the reader is already deeply familiar with ACL2's evaluation semantics; but some of the concepts described in this page are referenced in subsequent pages, so the reader may need to come back to this page if those concepts are not clear.

    Logical Semantics and Evaluation Semantics

    ACL2 has a precisely defined logical semantics, expressed in terms of syntax, axioms, and inference rules, similarly to logic textbooks and other theorem provers. This logical semantics applies to logic-mode functions, not program-mode functions. Guards are not part of the logic, but engender proof obligations in the logic when guard verification is attempted.

    ACL2 also has a documented evaluation semantics, which could be formalized in terms of syntax, values, states, steps, errors, etc., as is customary for programming languages. This evaluation semantics applies to both logic-mode and program-mode functions. Guards affect the evaluation semantics, based on guard-checking settings. Even non-executable functions (e.g. introduced via defchoose or defun-nx) degenerately have an evaluation semantics, because they do yield error results when called; however, the following discussion focuses on executable functions.

    Logic-Mode, Program-Mode, and Primitive Functions

    Most logic-mode functions have definitions that specify both their logical and their evaluation semantics: for the former, the definitions are logically conservative axioms; for the latter, the definitions provide ``instructions'' for evaluating calls of the function. For a defined logic-mode function, the relationship between the two semantics is that, roughly speaking, evaluating a call of the function yields, in a finite number of steps, the unique result value that, with the argument values, satisfies the function's defining axiom; the actual relationship is slightly more complicated, as it may involve guard checking.

    The primitive functions are in logic mode and have no definitions; they are all built-in. Examples are equal, if, cons, car, and binary-+. Their logical semantics is specified by axioms of the ACL2 logic. Their evaluation semantics is specified by raw Lisp code (under the hood). The relationship between the two semantics is as in the above paragraph, with the slight complication that pkg-witness and pkg-imports yield error results when called on unknown package names. The evaluation of calls of if is non-strict, as is customary.

    Most program-mode functions have definitions that specify their evaluation semantics, similarly to the non-primitive logic-mode functions discussed above. Their definitions specify no logical semantics.

    Functions with Raw Lisp Code and Side Effects

    The logic-mode functions listed in the global variable logic-fns-with-raw-code (whose content can be inspected via (@ logic-fns-with-raw-code) in an ACL2 shell; see @) have a logical semantics specified by their ACL2 definitions, but an evaluation semantics specified by raw Lisp code. (They are disjoint from the primitive functions, which have no definitions.) For some of these functions, e.g. len, the raw Lisp code just makes them run faster but is otherwise functionally equivalent to the ACL2 definitions. Others have side effects, carried out by their raw Lisp code but not reflected in their ACL2 definitions. For example, hard-error prints a message on the screen and immediately terminates execution, unwinding the call stack. As another example, fmt-to-comment-window prints a message on the screen, returning nil and continuing execution. But the ACL2 definitions of both of these example functions just return nil.

    The program-mode functions listed in the global variable program-fns-with-raw-code have an evaluation semantics specified by raw Lisp code. Their ACL2 definitions appear to have no actual use.

    Since stobjs are destructively updated, functions that manipulate stobjs may have side effects as well, namely the destructive updates. Because of single-threadedness, these side effects are invisible in the end-to-end input/output evaluation of these functions; however, they may be visible in some formulations of the evaluation semantics, such as ones that comprehend interrupts, for which updating a record field in place involves different steps than constructing a new record value with a changed field. The built-in state stobj is ``linked'' to external entities, e.g. the file system of the underlying machine. Thus, functions that manipulate state may have side effects on these external entities. For example, princ$ (a member of logic-fns-with-raw-code) writes to the stream associated with the output channel argument, and affects the file system.

    The fact that the side effects of the evaluation semantics are not reflected in the logical semantics is a design choice that makes the language more practical for programming while retaining the ability to prove theorems. But when generating Java or other code, these side effects should be taken into consideration: for instance, translating hard-error and fmt-to-comment-window into Java code that returns (a representation of) nil, would be incorrect or at least undesired. As an aside, a similar issue applies to the use of APT transformations: for instance, using the simplify transformation to turn calls of hard-error into nil, while logically correct and within simplify's stipulations, may be undesired or unexpected.

    Macros with Raw Lisp Code

    Macros are normally expanded (the expansion being also according to ACL2's evaluation semantics), and their expansion is then evaluated. However, the macros listed in the global variable macros-with-raw-code have an evaluation semantics specified by raw Lisp code. The evaluation semantics specified by their raw Lisp code may be consistent with the evaluation semantics of their expansion or not, due to side effects or apparent circularities. For instance, the concatenate macro has raw Lisp code, which obviously terminates execution; however, the expansion of concatenate calls string-append, whose :exec part calls concatenate, and therefore execution may not terminate. Thus, macros with raw Lisp code may also need to be taken into account when translating ACL2 code to Java or other programming languages.

    Previous: Motivation for Generating Java Code from ACL2

    Next: Relationship with AIJ