ORACLE-APPLY

call a function argument on the given list of arguments
Major Section:  ACL2-BUILT-INS

Oracle-apply evaluates its first argument to produce an ACL2 function symbol, FN, and then applies FN to the value of the second argument, which should be a true list whose length is the number of inputs for FN. The return value is of the form (mv call-result state).

Examples:
(oracle-apply 'cons '(3 4) state) = (mv '(3 . 4) <state>)
(oracle-apply (car '(floor foo)) (list (+ 6 7) 5) state) = (mv 2 <state>)

Also see oracle-funcall for a related utility.

Note that calls of oracle-funcall and oracle-apply return two values: the result of the function application, and a modified state.

Oracle-apply is defined in :logic mode, and in fact is guard-verified. However, you will not be able to prove much about this function, because it is defined in the logic using the acl2-oracle field of the ACL2 state. The behavior described above -- i.e., making a function call -- takes place when the third argument is the ACL2 state, so during proofs (when that can never happen), a term (oracle-apply 'fn '...) will not simplify using a call of fn.

The guard for (oracle-apply fn args state) is the term (oracle-apply-guard fn args state), which says the following: fn and args must satisfy symbolp and true-listp, respectively; fn must be a known function symbol other than return-last that is not untouchable (see push-untouchable) and has no stobj arguments (not even state); and the length of args must equal the arity of fn (see signature). The requirement that fn be a known function symbol may be a bit onerous for guard verification, but this is easily overcome by using ec-call, for example as follows.

(defun f (x state)
  (declare (xargs :stobjs state))
  (ec-call (oracle-apply 'car (list x) state)))
This use of ec-call will, however, cause the guard of oracle-apply to be checked at runtime.

If the guard for oracle-apply fails to hold but there is no guard violation because guard-checking is suppressed (see set-guard-checking), then the value returned is computed using its logical definition -- which, as mentioned above, uses the ACL2 oracle -- and hence the value computed is unpredictable (indeed, the function argument will not actually be called).

The value returned by oracle-apply is always a single value obtained by calling the executable counterpart of its function argument, as we now explain. Consider a form (oracle-apply fn args state) that evaluates to (mv VAL state'), where fn evaluates to the function symbol F. If F returns multiple values, then VAL is the first value computed by the call of F on the value of args. More precisely, oracle-apply actually invokes the executable counterpart of F; thus, if args is the expression (list x1 ... xk), then VAL is the same as (first) value returned by evaluating (ec-call (F x1 x2 ... xk)). See ec-call.

(Remark. If you identify a need for a version of oracle-apply to return multiple values, we can perhaps provide such a utility; feel free to contact the ACL2 implementors to request it.)

A subtlety is that the evaluation takes place in so-called ``safe mode'', which avoids raw Lisp errors due to calls of :program mode functions. The use of safe mode is unlikely to be noticed if the value of the first argument of oracle-apply is a :logic mode function symbol. However, for :program mode functions with side effects due to special raw Lisp code, as may be the case for built-in functions or for custom functions defined with active trust tags (see defttag), use of the following function may be preferable:

See oracle-apply-raw for a much less restrictive version of oracle-apply, which avoids safe mode and (for example) can apply a function that has a definition in the host Lisp but not in the ACL2 world.