Zulip Chat Archive
Stream: new members
Topic: Steps to take to replace StateT with StateRefT
Kevin Cheung (Nov 20 2024 at 19:39):
From this message https://leanprover.zulipchat.com/#narrow/channel/270676-lean4/topic/Manipulating.20custom.20tactic.20state/near/357172828, I got the impression that StateRefT can be a drop-in replacement for StateT. But I think I'm missing something. For example, I replaced StateT with StateRefT in the following
def fibS (n : Nat) : Nat :=
if n < 2 then n
else
Id.run $ ( do
let rec helper (n : Nat) : StateT (Nat × Nat) Id Nat :=
match n with
| 0 => do
let (x, _) <- StateT.get
return x
| k + 1 => do
let (x, y) <- StateT.get
StateT.set (y, x + y)
helper k
helper n
).run' (0, 1)
#eval fibS <$> List.range 11
to obtain
def fibS' (n : Nat) : Nat :=
if n < 2 then n
else
Id.run $ ( do
let rec helper (n : Nat) : StateRefT (Nat × Nat) Id Nat :=
match n with
| 0 => do
let (x, _) <- StateRefT.get
return x
| k + 1 => do
let (x, y) <- StateRefT.get
StateRefT.set (y, x + y)
helper k
helper n
).run' (0, 1)
But the fifth line (at StateRefT (Nat × Nat) Id
) is underlined with the following error:
failed to synthesize
STWorld ?m.1132 Id
How does one go about fixing the code? Help greatly appreciated.
Kyle Miller (Nov 20 2024 at 19:45):
Basically, you need to use it within a monad that has IO access (it can be used a bit more generally than just IO, but that's a reasonable approximation)
Kevin Cheung (Nov 20 2024 at 20:02):
So, something like this?
def fibS'' (n : Nat) : IO Nat :=
if n < 2 then pure n
else (do
let rec helper (n : Nat) : StateRefT (Nat × Nat) IO Nat :=
match n with
| 0 => do
let (x, _) <- get
return x
| k + 1 => do
let (x, y) <- get
set (y, x + y)
helper k
helper n).run' (0, 1)
#eval List.mapM fibS'' $ List.range 11
Kyle Miller (Nov 20 2024 at 20:07):
Yeah, exactly.
Kevin Cheung (Nov 20 2024 at 20:09):
Basically, StateRefT
is not really a replacement for StateT
in general. Maybe if one is looking for performance, ST.Ref
is a better choice?
Kyle Miller (Nov 20 2024 at 20:10):
Yeah, I think StateRefT is supposed to be a more-performant version of StateT when you have access to ST.Ref
Kevin Cheung (Nov 20 2024 at 20:12):
It is possible to make StateRefT
have access to ST.Ref
?
Kyle Miller (Nov 20 2024 at 20:12):
Yeah, by using monads such as IO that provide the ability to use it.
Kyle Miller (Nov 20 2024 at 20:14):
Unless you mean something else?
Kevin Cheung (Nov 20 2024 at 20:15):
More concretely, if I want to modify my fibS''
to use ST
instead of IO
while sticking to StateRefT
, is there a way to do it? Because for a function like this, I don't want it to be trapped in IO
.
Kyle Miller (Nov 20 2024 at 20:24):
No, the point is that ST.Ref is a mutable reference, and you need an "STWorld" (a.k.a. some access to the runtime environment itself) to manage these mutable references.
Kevin Cheung (Nov 20 2024 at 20:28):
I managed to cook up the following from the Haskell version:
-- Adapted from https://wiki.haskell.org/Monad/ST#A_few_simple_examples
def fibST (n : ℕ) : ℕ :=
if n < 2 then n
else
runST (fun σ => do
let rec fibST' (n : ℕ) (x y : ST.Ref σ ℕ) :=
match n with
| 0 => x.get
| k + 1 => do
let x' <- ST.Ref.get x
let y' <- y.get
ST.Ref.set x y'
y.set (x' + y')
fibST' k x y
let x <- ST.mkRef 0
let y <- ST.mkRef 1
fibST' n x y
)
#eval fibST <$> List.range 11
So, the magic here is in runST
?
Kyle Miller (Nov 20 2024 at 20:28):
Oh, neat, I didn't know about that, sorry for the wrong information.
Kevin Cheung (Nov 20 2024 at 20:28):
Now, I'm confused. :sweat_smile:
Kyle Miller (Nov 20 2024 at 20:31):
It looks like the deal is that getting and setting values from this reference can't be reasoned about, but you're allowed to make use of ST.Ref in pure code by using runST
Mario Carneiro (Nov 20 2024 at 20:34):
yes, and I believe (although I don't have a proof) that the obvious axioms on ST expressions are inconsistent
Mario Carneiro (Nov 20 2024 at 20:35):
ST really doesn't mesh well with lean's semantics, it's brilliant in haskell but it doesn't make that much sense in a dependent type theory with ZFC like semantics
Kevin Cheung (Nov 20 2024 at 20:41):
Then, is it reasonable to say that one should avoid ST
in writing verified software and just stick to StateT
?
Last updated: May 02 2025 at 03:31 UTC