Zulip Chat Archive
Stream: lean4
Topic: Using ref in lean 4 (basic q)
Thomas Murrills (Oct 17 2022 at 22:41):
What's the analogue of Lean 3's tactic.ref
in Lean 4? I looked in the analogous spot, but couldn't find it. (Also, whatever the analogue is, how should I then actually import/open the relevant files to use it?)
Henrik Böving (Oct 17 2022 at 22:54):
Several possiblities.
- If you wish to have local mutability use the
let mut
keyword in do notation - If you wish to have monadic stuff (that is mutable variables shared across fucntion calls) you can start building your own monad stack with
StateRefT
or the underlyingST
monad. - You can also go very funky and use a global IO.Ref for example although this is most likely not what you want to do
Mario Carneiro (Oct 17 2022 at 22:58):
The direct analogue of tactic.ref
is IO.Ref
Mario Carneiro (Oct 17 2022 at 22:59):
and you don't have to import anything, it's already in Init
Thomas Murrills (Oct 17 2022 at 23:30):
oh, ok! so does it make sense to use IO.Ref
in tauto
just as a drop-in replacement for ref
? it’s not clear to me that IO is actually happening there, unless it’s managed internally or something… (Or would it make more sense to use a StateRefT
type of deal there?)
Mario Carneiro (Oct 17 2022 at 23:40):
I think it's fine to use IO.Ref if you want to keep the structure of the original code
Mario Carneiro (Oct 17 2022 at 23:41):
StateRefT is basically the same thing, it uses ST.Ref instead of IO.Ref but there isn't much difference between these except the API
Gabriel Ebner (Oct 17 2022 at 23:57):
The direct analogue of
tactic.ref
isIO.Ref
This is not really true: the Lean 3 tactic.ref
is reset when backtracking (it is stored in the tactic state), while the Lean 4 IO.Ref
is an actual reference that exists independently of the tactic state (and thus won't be reset when backtracking).
open tactic
#eval using_new_ref 42 $ λ r, do
(write_ref r 10 >> fail "") <|> skip,
read_ref r >>= trace -- prints 42
Mario Carneiro (Oct 18 2022 at 00:03):
ah yeah, I ran into that issue when implementing squeeze_scope
. I don't think there is any real analogue of tactic.ref
that gets reset along with the tactic state
Sébastien Michelland (Oct 18 2022 at 07:11):
An environment extension maybe?
Mario Carneiro (Oct 18 2022 at 07:17):
That will probably work, but it also clutters up the olean file
Sébastien Michelland (Oct 18 2022 at 07:32):
Aren't normal extensions local to the current file unlike the persistent ones?
Thomas Murrills (Oct 18 2022 at 17:16):
should there be a direct analogue of tactic.ref
? (I mean I’m guessing it’s above my pay grade right now, so to speak, and it’s probably not strictly necessary for tauto
, but I’m still curious what it would take to code it up lean 4…being reset when backtracking in tactics seems useful)
Gabriel Ebner (Oct 18 2022 at 17:35):
I'd rather avoid it, and explicitly use StateT α TacticM
instead (if you want a backtrackable state of type α
).
Thomas Murrills (Oct 18 2022 at 17:40):
ah, ok. I’m guessing this is the “build your own monad stack with StateRefT
” strategy mentioned by @Henrik Böving ? (Asking because I’m trying to figure out what the difference between using StateRefT
vs. StateT
is in this context; might be apparent as soon as I open the metaprogramming book, though… :) )
Henrik Böving (Oct 18 2022 at 17:47):
They behave equivalently to the user but one is a classic state monad pulling the state through as argument and return value while the other stores it as a real reference that gets mutated
Gabriel Ebner (Oct 18 2022 at 18:08):
They do not behave equivalently. It's kind of the same difference as between tactic.ref
and IO.Ref
.
StateT
does backtrackingStateRefT
does not
Thomas Murrills (Oct 20 2022 at 18:10):
Are there efficiency differences between using StateT
and StateRefT
/IO.ref
? If I'm going to be managing a big state, I can imagine it might be better to use a reference instead of passing the whole state around. Then I would just try to work around the non-backtrackability. But I can also imagine that maybe, say, the internals of StateT
make it just as efficient as using a reference.
Henrik Böving (Oct 20 2022 at 18:11):
StateRefT is generally speaking better if your monad stack allows for it.
Last updated: Dec 20 2023 at 11:08 UTC