leanprover / leanprover/lean4

Incorrect `MonadControl m (StateRefT' ω σ m)` instance

Open
#3,001 0 comments 1 reaction 0 assignees View on GitHub

Nobody has claimed this yet.

bug P-low
Dominant language
Lean
Stars
9.2k
Forks
990
Avg merge
1d 17h
Merged PRs (30d)
175

Description

Prerequisites
  • Put an X between the brackets on this line if you have done all of the following:
    • Check that your issue is not already filed.
    • Reduce the issue to a minimal, self-contained, reproducible test case. Avoid dependencies to mathlib4 or std4.
Description

The MonadControl instance for StateRefT' doesn't work as intended. Specifically, the instance is inferred as ReaderT, which means that the state is not restored by restoreM. Consider the following MWE for TacticM = ReaderT Context $ StateRefT State TermElabM, where the ref state is the goal list:

import Lean

open Lean Meta Elab Tactic

def traceNumGoalsInCoreM {α} (k : TacticM α) : TacticM α := do
  let x ← liftWith (m := CoreM) (fun run => run do
    let a ← k
    logInfo m!"{(← getGoals).length}" -- see the number of goals after `k`
    pure a)
  setGoals [] -- should have no effect, since we restore the tactic state created by `k`
  restoreM x

-- The following close the goal due to `setGoals []`, but shouldn't:

elab "test₁" : tactic => traceNumGoalsInCoreM <| pure ()

example : True := by -- (kernel) declaration has metavariables '_example'
  test₁ -- 1

elab "test₂" : tactic => traceNumGoalsInCoreM do
  appendGoals [(← mkFreshExprMVar none).mvarId!]

example : True := by -- (kernel) declaration has metavariables '_example'
  test₂ -- 2

If we add the following instance above traceNumGoalsInCoreM, patterned off of StateT, the tests do not close the goal, but instead match the logged number of goals as intended:

instance (ω σ : Type) (m : Type → Type) [MonadLiftT (ST ω) m] [Monad m] :
    MonadControl m (StateRefT' ω σ m) where
  stM α      := α × σ
  liftWith f := do let s ← get; liftM (f (fun x => x.run s))
  restoreM x := do let (a, s) ← liftM x; set s; pure a

However, I'm not sure if more care needs to be taken to handle the ref.

Note that this also applies to MonadFunctor.

Context

This caused issues when reducing definitions for hint; see this thread for the discovery of the issue, and this thread for discussion on this issue.

Steps to Reproduce
  1. Attempt to restore the state of a monad constructed using StateRefT' using restoreM.

Expected behavior: The state is restored.

Actual behavior: The state is not restored.

Versions

4.3.0; persists in 4.6.0-rc1

Impact

Add 👍 to issues you consider important. If others are impacted by this issue, please ask them to add 👍 to it.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Locate the StateRefT' MonadControl and MonadFunctor instances, then run the minimal Lean example using traceNumGoalsInCoreM. Compare the behavior of restoreM with the expected goal-list state restoration, including the suggested StateT-patterned instance. Done means the reproduced tests retain the tactic state instead of closing the goal unexpectedly.

Written by the indexing model from the issue text.

Assessment

Domain
compilers
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
38/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.