Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for local state in meta programs #2948

Merged
merged 3 commits into from
Nov 29, 2023
Merged

Support for local state in meta programs #2948

merged 3 commits into from
Nov 29, 2023

Conversation

aseemr
Copy link
Collaborator

@aseemr aseemr commented May 29, 2023

This PR adds support for local state in metaprograms. In particular, it adds three primitives:

(** The following primitives provide support for local state
    during execution of a tactic.
    The local state is monotonic, it is not
    reverted when the tactic backtracks (using catch e.g.)
 *)
val alloc (#a:Type) (x:a) : Tac (tref a)
val read (#a:Type) (r:tref a) : Tac a
val write (#a:Type) (r:tref a) (x:a) : Tac unit

Metaprograms can use these to maintain local state during execution.

Under the hood we use native OCaml heap to allocate these references.

Copy link
Member

@mtzguido mtzguido left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi Aseem, this looks good to me. I have one question though.

In interpreted mode, we use e_any, so the reference points to a term, even if it's a tref int or whatever. But in native tactics, a tref int will be exactly ref int, and use the native alloc/read/write. So they cannot interoperate, right? A reference can only be used in the "mode" it's created.

I don't think it's terrible. We could fix this by deprecating e_any and instead trying to generate an embedding for the type of the reference, but that requires some plumbing.

let write (r:tref 'a) (x:'a) : tac unit =
r := x;
ret ()

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It may be better to "thunk" these to prevent them from reducing before being applied to a proofstate, like so:

let alloc (x:'a) : tac (tref 'a) =
  idtac;!
  ret (BU.mk_ref x)
let read (r:tref 'a) : tac 'a =
  idtac;!
  ret (!r)
let write (r:tref 'a) (x:'a) : tac unit =
  idtac;!
  r := x;
  ret ()

@mtzguido
Copy link
Member

Come to think of it, since there is no embedding for tref, I don't think references can cross the native/interpreted boundary...

@TWal
Copy link
Contributor

TWal commented May 30, 2023

Could this be used to store state across meta-program calls, e.g. to memoize typeclass resolution?
The example don't showcase this right now.

@nikswamy
Copy link
Collaborator

What's the status of this? I would find it convenient to use a bit of local state in the Pulse checker.

@mtzguido
Copy link
Member

mtzguido commented Sep 1, 2023

I think we can merge this. I updated it to the current master and pushed to this branch.

@aseemr aseemr marked this pull request as ready for review September 1, 2023 12:59
aseemr and others added 3 commits November 29, 2023 10:54
@mtzguido mtzguido merged commit 383bbcf into master Nov 29, 2023
2 checks passed
@mtzguido mtzguido deleted the _aseem_meta_refs branch November 29, 2023 19:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants