Zulip Chat Archive
Stream: new members
Topic: Puzzled by MonadState and Pure
Nicolas Rouquette (Jul 18 2022 at 02:58):
Lean4 has an interesting implementation of strongly connected components in Util/SCC.lean that begins like this:
import Std.Data.HashMap
namespace Lean.SCC
/-
Very simple implementation of Tarjan's SCC algorithm.
Performance is not a goal here since we use this module to
compiler mutually recursive definitions, where each function
(and nested let-rec) in the mutual block is a vertex.
So, the graphs are small. -/
open Std
section
variable (α : Type) [BEq α] [Hashable α]
structure Data where
index? : Option Nat := none
lowlink? : Option Nat := none
onStack : Bool := false
structure State where
stack : List α := []
nextIndex : Nat := 0
data : Std.HashMap α Data := {}
sccs : List (List α) := []
abbrev M := StateM (State α)
end
variable {α : Type} [BEq α] [Hashable α]
private def getDataOf (a : α) : M α Data := do
let s ← get
match s.data.find? a with
| some d => pure d
| none => pure {}
When I read getDataOf
, it is unclear to me how this code typechecks properly.
VSCode seems to have determined somehow that M
is an instance of MonadState
so that get
is really MonadState.get
and that M
is also an instance of Pure
so that pure
is really Pure.pure
.
Can someone explain this?
It would be really nice if the VS Code tooling could explain what makes a reference resolve the way it does and why some code typechecks properly.
Kyle Miller (Jul 18 2022 at 03:22):
Here's the instance definition for StateM
being a MonadStateOf
(which gives MonadState
by another instance). Click "source" to the right to see where it is inside the prelude.
Kyle Miller (Jul 18 2022 at 03:22):
These docs also have lists of instances when you go to a class, so that can help you find where things are actually defined.
Matt Diamond (Jul 18 2022 at 03:23):
VSCode seems to have determined somehow that
M
is an instance ofMonadState
My guess is that the determination is based on abbrev M := StateM (State α)
Kyle Miller (Jul 18 2022 at 03:24):
It's helpful to know some Haskell to be able to deal with this part of the library, since it's still rather light on documentation, and these are all Haskell-like idioms.
Chris Bailey (Jul 18 2022 at 03:25):
I think it's just typeclass inference. StateT
has an instance of MonadStateOf
, which is MonadState
where the state type is set as an output parameter.
Chris Bailey (Jul 18 2022 at 03:25):
Oh they beat me to it.
Kyle Miller (Jul 18 2022 at 03:27):
The point of StateM
is that you can use get
to get the "current" State α
value and then put
to change it for code that runs "after." It's a functional programming trick to get something like mutable state.
Chris Bailey (Jul 18 2022 at 03:29):
There are some spartan trace facilities, like set_option trace.Meta.synthInstance
and some other ones discoverable via autocomplete if you type set_option trace.
Kyle Miller (Jul 18 2022 at 03:30):
Concretely, StateM
is a way to concisely write code for functions that have types like σ → α × σ
, where σ
is the type for some state that you'd otherwise have to thread through everything manually.
Kyle Miller (Jul 18 2022 at 03:31):
(Making things more complicated, StateM
is defined in terms of StateT
, a so-called "monad transformer," where you can compose multiple monad transformers to achieve multiple effects.)
Last updated: Dec 20 2023 at 11:08 UTC