Zulip Chat Archive
Stream: new members
Topic: Type of `let mut`
Josh Cohen (Sep 03 2025 at 15:05):
I am reading through "Functional Programming in Lean" and I tried the following, which surprisingly typechecks:
def two (m: Type -> Type) [Monad m] : m Nat := do
let mut x := 0
x := x + 1
x := x + 1
return x
Namely, why can the type of this be any Monad? From the explanation in the text, I would think that the let mut restricts us to the state monad (or at least a StateT transformer), but the overall expression inside the do block has no such restriction. How does let mut work?
David Renshaw (Sep 03 2025 at 15:08):
Monads are primarily used via do-notation, which is an embedded language for programming in an imperative style. It provides familiar syntax for sequencing effectful operations, early return, local mutable variables, loops, and exception handling. All of these features are translated to the operations of the Monad type class, with a few of them requiring addition instances of classes such as ForIn that specify iteration over containers.
Sebastian Ullrich and Leonardo de Moura, 2022. “
doUnchained: Embracing Local Imperativity in a Purely Functional Language”. In Proceedings of the ACM on Programming Languages: ICFP 2022.
https://lean-lang.org/doc/reference/latest//Functors___-Monads-and--do--Notation/Syntax/#do-notation
Josh Cohen (Sep 03 2025 at 15:27):
Thanks for the pointer. So it seems from the paper (Figure 5) that let mut desugars to a local StateT instance that is then evaluated by StateT.run', is this correct?
David Renshaw (Sep 03 2025 at 15:27):
that's consistent with my understanding
Aaron Liu (Sep 03 2025 at 15:38):
clearly that's not what happens since #print two gives
def two : (m : Type → Type) → [Monad m] → m Nat :=
fun m [Monad m] =>
have x := 0;
have x := x + 1;
have x := x + 1;
pure x
Aaron Liu (Sep 03 2025 at 15:38):
no local instance here
Henrik Böving (Sep 03 2025 at 16:30):
Josh Cohen said:
Thanks for the pointer. So it seems from the paper (Figure 5) that
let mutdesugars to a localStateTinstance that is then evaluated byStateT.run', is this correct?
The paper is not at all what is currently implemented in Lean and more of an ideal world type of situation.
Josh Cohen (Sep 03 2025 at 17:51):
Aaron Liu said:
clearly that's not what happens since
#print twogivesdef two : (m : Type → Type) → [Monad m] → m Nat := fun m [Monad m] => have x := 0; have x := x + 1; have x := x + 1; pure x
In this case, what does the let mut give beyond just have?
Aaron Liu (Sep 03 2025 at 17:52):
it gives nothing (in this case)
Aaron Liu (Sep 03 2025 at 17:53):
but you can do stuff with it if you mutate inside a loop
Last updated: Dec 20 2025 at 21:32 UTC