@chrisamaphone like, genuine question, I don't know haskell's whole feature set, can you do like
def look_no_state_monad (n gas : Nat) : Id Bool := do
let mut n := n
let mut gas := gas
while gas > 0 do
if n == 1 then return true
if n % 2 == 0
then n := n / 2
else n := 3 * n + 1
gas := gas - 1
dbg_trace n
return false
/--
info: 53
---
info: false
-/
#guard_msgs in
#eval look_no_state_monad 27 100
/-- info: true -/
#guard_msgs in
#eval look_no_state_monad 27 200
Id run call around the edges myself normally (or possibly a do Id) not least because unless you're trying to weaken to it the identity monad may as well be any monad. But this is partly a "typeclasses being awkward" thing coupled with me being effect-happy.@jcreed @chrisamaphone I would legit rather have good syntax for unfolds/anamorphisms, though I appreciate Lean probably shouldn't do loops that way!
(I once pushed a list reversal written as a fold through the initial algebra/final coalgebra isomorphism, and by far the hardest bit was not having neat labels for what the seed -> (cons * seed + nil) function was doing in terms of the coalgebra)
def look_no_state_monad : Nat → Nat → Id Bool :=
fun n gas =>
have n := n;
have gas := gas;
do
let r ←
forIn Lean.Loop.mk ⟨none, gas, n⟩ fun x r =>
have r := r.snd;
have gas := r.fst;
have n := r.snd;
if gas > 0 then
have __do_jp := fun gas n y =>
have __do_jp := fun gas n y =>
have gas := gas - 1;
do
pure PUnit.unit
pure (ForInStep.yield ⟨none, gas, n⟩);
if (n % 2 == 0) = true then
have n := n / 2;
do
let y ← pure PUnit.unit
__do_jp gas n y
else
have n := 3 * n + 1;
do
let y ← pure PUnit.unit
__do_jp gas n y;
if (n == 1) = true then pure (ForInStep.done ⟨some true, gas, n⟩)
else do
let y ← pure PUnit.unit
__do_jp gas n y
else pure (ForInStep.done ⟨none, gas, n⟩)
match r.snd with
| ⟨gas, n⟩ =>
have __do_jp := fun y => dbgTrace (toString n) fun x => pure false;
match r.fst with
| none => do
let y ← pure PUnit.unit
__do_jp y
| some a => pure a
In the end it looks a lot like the state monad anyway
@jcreed @chrisamaphone nope, using references to mutable cells is syntactically chonky and there's no room to pun
the state monad doesn't give you references, instead it gives you get/set and interderivable operations on a single mutable cell - plays nicely with lenses though and as it's Just Ordinary Code you can use lenses to use part of the outer cell as your locally relevant cell
no syntactic support for looking like imperative code rather than code with some sequencing though
none of which stopped lennart augustsson from embedding a line-numbered basic into it for the hell of it
@jcreed @chrisamaphone No, the only "magic" that happens with monads in Haskell is the desugaring of do notation into applications of >>=.
What you're describing would need a little more magic than that.