Documentation

VCVio.OracleComp.SimSemantics.Append.Core

Append/Add Operation for Simulation Oracles #

def QueryImpl.add {ι₁ : Type u_4} {ι₂ : Type u_5} {spec₁ : OracleSpec ι₁} {spec₂ : OracleSpec ι₂} {m : Type u → Type u_1} (impl₁ : QueryImpl spec₁ m) (impl₂ : QueryImpl spec₂ m) :
QueryImpl (spec₁ + spec₂) m

Simplest version of adding queries when all implementations are in the same monad. The actual add notation for QueryImpl uses QueryImpl.addLift which adds monad lifting to this definition for greater flexibility.

Instances For
    @[instance_reducible]
    instance QueryImpl.instHAddSumHAddOracleSpec {ι₁ : Type u_4} {ι₂ : Type u_5} {spec₁ : OracleSpec ι₁} {spec₂ : OracleSpec ι₂} {m : Type u → Type u_1} :
    HAdd (QueryImpl spec₁ m) (QueryImpl spec₂ m) (QueryImpl (spec₁ + spec₂) m)

    Add two QueryImpl to get an implementation on the sum of the two OracleSpec.

    theorem QueryImpl.add_eq_hAdd {ι₁ : Type u_4} {ι₂ : Type u_5} {spec₁ : OracleSpec ι₁} {spec₂ : OracleSpec ι₂} {m : Type u → Type u_1} (impl₁ : QueryImpl spec₁ m) (impl₂ : QueryImpl spec₂ m) :
    impl₁.add impl₂ = impl₁ + impl₂

    The HAdd notation for query implementations is their explicit QueryImpl.add operation. This named bridge lets downstream proofs cross the module boundary without requesting stronger reducibility for the instance.

    theorem QueryImpl.add_apply {ι₁ : Type u_4} {ι₂ : Type u_5} {spec₁ : OracleSpec ι₁} {spec₂ : OracleSpec ι₂} {m : Type u → Type u_1} (impl₁ : QueryImpl spec₁ m) (impl₂ : QueryImpl spec₂ m) (t : (spec₁ + spec₂).Domain) :
    (impl₁ + impl₂) t = match t with | Sum.inl t => impl₁ t | Sum.inr t => impl₂ t
    @[simp]
    theorem QueryImpl.add_apply_inl {ι₁ : Type u_4} {ι₂ : Type u_5} {spec₁ : OracleSpec ι₁} {spec₂ : OracleSpec ι₂} {m : Type u → Type u_1} (impl₁ : QueryImpl spec₁ m) (impl₂ : QueryImpl spec₂ m) (t : spec₁.Domain) :
    (impl₁ + impl₂) (Sum.inl t) = impl₁ t
    @[simp]
    theorem QueryImpl.add_apply_inr {ι₁ : Type u_4} {ι₂ : Type u_5} {spec₁ : OracleSpec ι₁} {spec₂ : OracleSpec ι₂} {m : Type u → Type u_1} (impl₁ : QueryImpl spec₁ m) (impl₂ : QueryImpl spec₂ m) (t : spec₂.Domain) :
    (impl₁ + impl₂) (Sum.inr t) = impl₂ t
    def QueryImpl.addLift {ι₁ : Type u_7} {ι₂ : Type u_8} {spec₁ : OracleSpec ι₁} {spec₂ : OracleSpec ι₂} {m : Type u → Type u_4} {n : Type u → Type u_5} {r : Type u → Type u_6} [MonadLiftT m r] [MonadLiftT n r] (impl₁ : QueryImpl spec₁ m) (impl₂ : QueryImpl spec₂ n) :
    QueryImpl (spec₁ + spec₂) r

    Version of QueryImpl.add that also lifts the two implementations to a shared lift monad.

    Instances For
      @[simp]
      theorem QueryImpl.addLift_def {ι₁ : Type u_7} {ι₂ : Type u_8} {spec₁ : OracleSpec ι₁} {spec₂ : OracleSpec ι₂} {m : Type u → Type u_4} {n : Type u → Type u_5} {r : Type u → Type u_6} [MonadLiftT m r] [MonadLiftT n r] (impl₁ : QueryImpl spec₁ m) (impl₂ : QueryImpl spec₂ n) :
      impl₁.addLift impl₂ = liftTarget r impl₁ + liftTarget r impl₂
      theorem QueryImpl.simulateQ_add_liftM_query_left {ι₁' : Type u_4} {ι₂' : Type u_5} {spec₁' : OracleSpec ι₁'} {spec₂' : OracleSpec ι₂'} {m' : Type u → Type v} [Monad m'] [LawfulMonad m'] (impl₁' : QueryImpl spec₁' m') (impl₂' : QueryImpl spec₂' m') (t : spec₁'.Domain) :
      simulateQ (impl₁' + impl₂') (liftM (OracleSpec.query t)) = impl₁' t

      Simulating a query-level lift from the left summand routes it to the left implementation.

      theorem QueryImpl.simulateQ_add_liftM_query_right {ι₁' : Type u_5} {ι₂' : Type u_4} {spec₁' : OracleSpec ι₁'} {spec₂' : OracleSpec ι₂'} {m' : Type u → Type v} [Monad m'] [LawfulMonad m'] (impl₁' : QueryImpl spec₁' m') (impl₂' : QueryImpl spec₂' m') (t : spec₂'.Domain) :
      simulateQ (impl₁' + impl₂') (liftM (OracleSpec.query t)) = impl₂' t

      Simulating a query-level lift from the right summand routes it to the right implementation.

      theorem QueryImpl.simulateQ_add_query_left {ι₁' : Type u_4} {ι₂' : Type u_5} {spec₁' : OracleSpec ι₁'} {spec₂' : OracleSpec ι₂'} {m' : Type u → Type v} [Monad m'] [LawfulMonad m'] (impl₁' : QueryImpl spec₁' m') (impl₂' : QueryImpl spec₂' m') (t : spec₁'.Domain) :
      simulateQ (impl₁' + impl₂') (liftM (OracleSpec.query (Sum.inl t))) = impl₁' t

      A query formed directly against the sum specification routes to its left handler.

      theorem QueryImpl.simulateQ_add_query_right {ι₁' : Type u_5} {ι₂' : Type u_4} {spec₁' : OracleSpec ι₁'} {spec₂' : OracleSpec ι₂'} {m' : Type u → Type v} [Monad m'] [LawfulMonad m'] (impl₁' : QueryImpl spec₁' m') (impl₂' : QueryImpl spec₂' m') (t : spec₂'.Domain) :
      simulateQ (impl₁' + impl₂') (liftM (OracleSpec.query (Sum.inr t))) = impl₂' t

      A query formed directly against the sum specification routes to its right handler.

      theorem QueryImpl.simulateQ_add_query_bind_left {ι₁' : Type u_4} {ι₂' : Type u_5} {spec₁' : OracleSpec ι₁'} {spec₂' : OracleSpec ι₂'} {α : Type u} {m' : Type u → Type v} [Monad m'] [LawfulMonad m'] (impl₁' : QueryImpl spec₁' m') (impl₂' : QueryImpl spec₂' m') (t : spec₁'.Domain) (k : (spec₁' + spec₂').Range (Sum.inl t)OracleComp (spec₁' + spec₂') α) :
      simulateQ (impl₁' + impl₂') (liftM (OracleSpec.query (Sum.inl t)) >>= k) = do let uimpl₁' t simulateQ (impl₁' + impl₂') (k u)

      A query to the left component of a sum handler routes to that component before its continuation is simulated.

      theorem QueryImpl.simulateQ_add_query_bind_right {ι₁' : Type u_5} {ι₂' : Type u_4} {spec₁' : OracleSpec ι₁'} {spec₂' : OracleSpec ι₂'} {α : Type u} {m' : Type u → Type v} [Monad m'] [LawfulMonad m'] (impl₁' : QueryImpl spec₁' m') (impl₂' : QueryImpl spec₂' m') (t : spec₂'.Domain) (k : (spec₁' + spec₂').Range (Sum.inr t)OracleComp (spec₁' + spec₂') α) :
      simulateQ (impl₁' + impl₂') (liftM (OracleSpec.query (Sum.inr t)) >>= k) = do let uimpl₂' t simulateQ (impl₁' + impl₂') (k u)

      A query to the right component of a sum handler routes to that component before its continuation is simulated.

      theorem QueryImpl.simulateQ_add_liftComp_left {ι₁' : Type u_4} {ι₂' : Type u_5} {spec₁' : OracleSpec ι₁'} {spec₂' : OracleSpec ι₂'} {α : Type u} {m' : Type u → Type v} [Monad m'] [LawfulMonad m'] (impl₁' : QueryImpl spec₁' m') (impl₂' : QueryImpl spec₂' m') (oa : OracleComp spec₁' α) :
      simulateQ (impl₁' + impl₂') (oa.liftComp (spec₁' + spec₂')) = simulateQ impl₁' oa
      theorem QueryImpl.simulateQ_add_liftComp_right {ι₁' : Type u_5} {ι₂' : Type u_4} {spec₁' : OracleSpec ι₁'} {spec₂' : OracleSpec ι₂'} {α : Type u} {m' : Type u → Type v} [Monad m'] [LawfulMonad m'] (impl₁' : QueryImpl spec₁' m') (impl₂' : QueryImpl spec₂' m') (ob : OracleComp spec₂' α) :
      simulateQ (impl₁' + impl₂') (ob.liftComp (spec₁' + spec₂')) = simulateQ impl₂' ob
      theorem QueryImpl.simulateQ_add_liftM_left {ι₁' : Type u_4} {ι₂' : Type u_5} {spec₁' : OracleSpec ι₁'} {spec₂' : OracleSpec ι₂'} {α : Type u} {m' : Type u → Type v} [Monad m'] [LawfulMonad m'] (impl₁' : QueryImpl spec₁' m') (impl₂' : QueryImpl spec₂' m') (oa : OracleComp spec₁' α) :
      simulateQ (impl₁' + impl₂') (liftM oa) = simulateQ impl₁' oa

      liftM-normal-form companion of simulateQ_add_liftComp_left. Because liftComp_eq_liftM normalizes liftComp → liftM under simp, the liftComp-keyed lemma never fires inside simp; this liftM-keyed form is what simp actually needs.

      Deliberately not @[simp]: as a global rule it shifts the normal form of simulateQ over an added handler applied to a lifted-in computation, which pre-empts and breaks existing proofs that manage that reduction themselves. Pass it explicitly, e.g. simp [myHandler, simulateQ_add_liftM_left, simulateQ_toQueryImpl].

      theorem QueryImpl.simulateQ_add_liftM_right {ι₁' : Type u_5} {ι₂' : Type u_4} {spec₁' : OracleSpec ι₁'} {spec₂' : OracleSpec ι₂'} {α : Type u} {m' : Type u → Type v} [Monad m'] [LawfulMonad m'] (impl₁' : QueryImpl spec₁' m') (impl₂' : QueryImpl spec₂' m') (ob : OracleComp spec₂' α) :
      simulateQ (impl₁' + impl₂') (liftM ob) = simulateQ impl₂' ob

      liftM-normal-form companion of simulateQ_add_liftComp_right; opt-in, see simulateQ_add_liftM_left.

      theorem QueryImpl.simulateQ_liftComp_left_eq_of_apply {ι₁' : Type u_4} {ι₂' : Type u_5} {spec₁' : OracleSpec ι₁'} {spec₂' : OracleSpec ι₂'} {α : Type u} {m' : Type u → Type v} [Monad m'] [LawfulMonad m'] (impl : QueryImpl (spec₁' + spec₂') m') (impl₁ : QueryImpl spec₁' m') (h : ∀ (t : ι₁'), impl (Sum.inl t) = impl₁ t) (oa : OracleComp spec₁' α) :
      simulateQ impl (oa.liftComp (spec₁' + spec₂')) = simulateQ impl₁ oa
      theorem QueryImpl.simulateQ_liftComp_right_eq_of_apply {ι₁' : Type u_4} {ι₂' : Type u_5} {spec₁' : OracleSpec ι₁'} {spec₂' : OracleSpec ι₂'} {α : Type u} {m' : Type u → Type v} [Monad m'] [LawfulMonad m'] (impl : QueryImpl (spec₁' + spec₂') m') (impl₂ : QueryImpl spec₂' m') (h : ∀ (t : ι₂'), impl (Sum.inr t) = impl₂ t) (oa : OracleComp spec₂' α) :
      simulateQ impl (oa.liftComp (spec₁' + spec₂')) = simulateQ impl₂ oa
      theorem QueryImpl.simulateQ_toQueryImpl {ι : Type u_4} {spec : OracleSpec ι} {α : Type u} (mx : OracleComp spec α) :

      Simulating the trivial HasQuery.toQueryImpl handler back into OracleComp spec is the identity (the composite of HasQuery.toQueryImpl_eq_id' and simulateQ_id').

      Like toQueryImpl_eq_id', this is deliberately not @[simp]: globally it lets simulateQ of a toQueryImpl.liftTarget handler fully reduce, which can re-enable a backward induction-hypothesis rewrite and diverge. Pass it explicitly to simp (alongside the opaque handler definition) to discharge a lifted-in computation, e.g. simp [myHandler, simulateQ_toQueryImpl]; the simulateQ_add_liftM_left/_right and simulateQ_liftTarget rungs are @[simp] and fire on their own.

      theorem QueryImpl.simulateQ_liftM_eq_of_query {ι₁' : Type u_5} {ι₂' : Type u_4} {spec₁' : OracleSpec ι₁'} {spec₂' : OracleSpec ι₂'} {α : Type u} {m' : Type u → Type v} [Monad m'] [LawfulMonad m'] [MonadLiftT (OracleComp spec₁') (OracleComp spec₂')] [LawfulMonadLiftT (OracleComp spec₁') (OracleComp spec₂')] (impl : QueryImpl spec₂' m') (impl₁ : QueryImpl spec₁' m') (h : ∀ (t : ι₁'), simulateQ impl (liftM (liftM (OracleSpec.query t))) = impl₁ t) (oa : OracleComp spec₁' α) :
      simulateQ impl (liftM oa) = simulateQ impl₁ oa

      Query routing through a right-nested sum implementation #

      Routing lemmas for the spec + (spec₁ + spec₂) layout used by stateless protocol simulation oracles (e.g. a base spec plus a pair of message/statement oracle families, the simOracle2 layout): a single query lifted from one component — either at the query level (OracleQuery) or pre-embedded in its own computation monad (OracleComp, the shape produced by reusable query helpers) — resolves under simulateQ to the implementation at the routed index.

      Each left-hand side spells the canonical MonadLiftT chain that typeclass resolution synthesizes for that lift (through the intermediate spec + spec₂ etc.), which is what lets these fire by simp on goals produced by elaborated protocol definitions. All six reduce through simulateQ_spec_query after the component lift is re-expressed as the canonical embedded query at its routed index.

      @[simp]
      theorem QueryImpl.simulateQ_add_add_liftM_query_base {ι' : Type u_4} {ι₁' : Type u_5} {ι₂' : Type u_6} {spec : OracleSpec ι'} {spec₁ : OracleSpec ι₁'} {spec₂ : OracleSpec ι₂'} {m' : Type u → Type v} [Monad m'] [LawfulMonad m'] (implA : QueryImpl spec m') (implB : QueryImpl (spec₁ + spec₂) m') (t : spec.Domain) :
      simulateQ (implA + implB) (liftM (OracleSpec.query t)) = implA t
      @[simp]
      theorem QueryImpl.simulateQ_add_add_liftM_query_left {ι' : Type u_5} {ι₁' : Type u_4} {ι₂' : Type u_6} {spec : OracleSpec ι'} {spec₁ : OracleSpec ι₁'} {spec₂ : OracleSpec ι₂'} {m' : Type u → Type v} [Monad m'] [LawfulMonad m'] (implA : QueryImpl spec m') (implB : QueryImpl (spec₁ + spec₂) m') (t : spec₁.Domain) :
      simulateQ (implA + implB) (liftM (OracleSpec.query t)) = implB (Sum.inl t)
      @[simp]
      theorem QueryImpl.simulateQ_add_add_liftM_query_right {ι' : Type u_5} {ι₁' : Type u_6} {ι₂' : Type u_4} {spec : OracleSpec ι'} {spec₁ : OracleSpec ι₁'} {spec₂ : OracleSpec ι₂'} {m' : Type u → Type v} [Monad m'] [LawfulMonad m'] (implA : QueryImpl spec m') (implB : QueryImpl (spec₁ + spec₂) m') (t : spec₂.Domain) :
      simulateQ (implA + implB) (liftM (OracleSpec.query t)) = implB (Sum.inr t)
      @[simp]
      theorem QueryImpl.simulateQ_add_add_liftM_comp_base {ι' : Type u_4} {ι₁' : Type u_5} {ι₂' : Type u_6} {spec : OracleSpec ι'} {spec₁ : OracleSpec ι₁'} {spec₂ : OracleSpec ι₂'} {m' : Type u → Type v} [Monad m'] [LawfulMonad m'] (implA : QueryImpl spec m') (implB : QueryImpl (spec₁ + spec₂) m') (t : spec.Domain) :
      simulateQ (implA + implB) (liftM (liftM (OracleSpec.query t))) = implA t
      @[simp]
      theorem QueryImpl.simulateQ_add_add_liftM_comp_left {ι' : Type u_5} {ι₁' : Type u_4} {ι₂' : Type u_6} {spec : OracleSpec ι'} {spec₁ : OracleSpec ι₁'} {spec₂ : OracleSpec ι₂'} {m' : Type u → Type v} [Monad m'] [LawfulMonad m'] (implA : QueryImpl spec m') (implB : QueryImpl (spec₁ + spec₂) m') (t : spec₁.Domain) :
      simulateQ (implA + implB) (liftM (liftM (OracleSpec.query t))) = implB (Sum.inl t)
      @[simp]
      theorem QueryImpl.simulateQ_add_add_liftM_comp_right {ι' : Type u_5} {ι₁' : Type u_6} {ι₂' : Type u_4} {spec : OracleSpec ι'} {spec₁ : OracleSpec ι₁'} {spec₂ : OracleSpec ι₂'} {m' : Type u → Type v} [Monad m'] [LawfulMonad m'] (implA : QueryImpl spec m') (implB : QueryImpl (spec₁ + spec₂) m') (t : spec₂.Domain) :
      simulateQ (implA + implB) (liftM (liftM (OracleSpec.query t))) = implB (Sum.inr t)

      Unit tests: a query lifted from a component of a sum spec routes through a sum implementation by simp alone, via the simulateQ_add_add_liftM_* routing lemmas. The shape spec + (spec₁ + spec₂) with an addLifted pair is the simOracle2 layout used by oracle-reduction verifiers downstream.

      Routing through a two-way addLift whose components live in different monads #

      addLift lifts each component handler into a shared target, so a computation lifted from one summand resolves to that component's simulation, re-lifted into the target. Stated with the two sources in distinct monads source₁ / source₂: that is the shape oracle-reduction verifiers produce, where a base-spec handler and a message-oracle handler are combined into one target.

      theorem QueryImpl.simulateQ_addLift_liftM_left {ι₁ : Type u_7} {ι₂ : Type u_8} {spec₁ : OracleSpec ι₁} {spec₂ : OracleSpec ι₂} {target : Type u → Type u_4} [Monad target] [LawfulMonad target] {source₁ : Type u → Type u_5} {source₂ : Type u → Type u_6} [Monad source₁] [LawfulMonad source₁] [MonadLiftT source₁ target] [LawfulMonadLiftT source₁ target] [MonadLiftT source₂ target] (impl₁ : QueryImpl spec₁ source₁) (impl₂ : QueryImpl spec₂ source₂) {α : Type u} (x : OracleComp spec₁ α) :
      simulateQ (impl₁.addLift impl₂) (liftM x) = liftM (simulateQ impl₁ x)

      A computation lifted from the left summand routes to the left component of an addLift, leaving its simulation lifted into the target.

      theorem QueryImpl.simulateQ_addLift_liftM_right {ι₁ : Type u_7} {ι₂ : Type u_8} {spec₁ : OracleSpec ι₁} {spec₂ : OracleSpec ι₂} {target : Type u → Type u_4} [Monad target] [LawfulMonad target] {source₁ : Type u → Type u_5} {source₂ : Type u → Type u_6} [Monad source₂] [LawfulMonad source₂] [MonadLiftT source₁ target] [MonadLiftT source₂ target] [LawfulMonadLiftT source₂ target] (impl₁ : QueryImpl spec₁ source₁) (impl₂ : QueryImpl spec₂ source₂) {α : Type u} (x : OracleComp spec₂ α) :
      simulateQ (impl₁.addLift impl₂) (liftM x) = liftM (simulateQ impl₂ x)

      A computation lifted from the right summand routes to the right component of an addLift, leaving its simulation lifted into the target.

      theorem QueryImpl.simulateQ_addLift_add_liftM_left {ι₁ : Type u_8} {ι₂ : Type u_9} {spec₁ : OracleSpec ι₁} {spec₂ : OracleSpec ι₂} {ι : Type u_7} {spec : OracleSpec ι} {target : Type u → Type u_4} [Monad target] [LawfulMonad target] {source₀ : Type u → Type u_5} [MonadLiftT source₀ target] {source : Type u → Type u_6} [Monad source] [LawfulMonad source] [MonadLiftT source target] [LawfulMonadLiftT source target] (impl : QueryImpl spec source₀) (impl₁ : QueryImpl spec₁ source) (impl₂ : QueryImpl spec₂ source) {α : Type u} (x : OracleComp spec₁ α) :
      simulateQ (impl.addLift (impl₁.add impl₂)) (liftM (liftM x)) = liftM (simulateQ impl₁ x)

      Resolve a simulateQ over a three-way addLift impl (impl₁ + impl₂) applied to a computation x : OracleComp spec₁ α that has been double-liftM'd — first into the inner sum spec₁ + spec₂, then into the outer sum spec + (spec₁ + spec₂). The query routes to the left inner implementation impl₁, leaving liftM (simulateQ impl₁ x).

      This is the computation-level sibling of QueryImpl.simulateQ_add_add_liftM_comp_left: it peels the outer addLift (simulateQ_add_liftComp_right), commutes the inner simulateQ past the target lift (simulateQ_liftTarget), then peels the inner sum (simulateQ_add_liftComp_left). Stated for the inner pair living in a possibly-different monad n lifted into the target m.

      theorem QueryImpl.simulateQ_addLift_add_liftM_right {ι₁ : Type u_8} {ι₂ : Type u_9} {spec₁ : OracleSpec ι₁} {spec₂ : OracleSpec ι₂} {ι : Type u_7} {spec : OracleSpec ι} {target : Type u → Type u_4} [Monad target] [LawfulMonad target] {source₀ : Type u → Type u_5} [MonadLiftT source₀ target] {source : Type u → Type u_6} [Monad source] [LawfulMonad source] [MonadLiftT source target] [LawfulMonadLiftT source target] (impl : QueryImpl spec source₀) (impl₁ : QueryImpl spec₁ source) (impl₂ : QueryImpl spec₂ source) {α : Type u} (x : OracleComp spec₂ α) :
      simulateQ (impl.addLift (impl₁.add impl₂)) (liftM (liftM x)) = liftM (simulateQ impl₂ x)

      Resolve a simulateQ over a three-way addLift impl (impl₁ + impl₂) applied to a computation x : OracleComp spec₂ α that has been double-liftM'd — first into the inner sum spec₁ + spec₂, then into the outer sum spec + (spec₁ + spec₂). The query routes to the right inner implementation impl₂, leaving liftM (simulateQ impl₂ x).

      The right companion of simulateQ_addLift_add_liftM_left.

      theorem QueryImpl.simulateQ_optionT_liftM_run_eq_of_query {ι₁' : Type u_5} {ι₂' : Type u_6} {spec₁' : OracleSpec ι₁'} {spec₂' : OracleSpec ι₂'} {α : Type u} {m' : Type u → Type u_4} [Monad m'] [LawfulMonad m'] [MonadLiftT (OracleComp spec₁') (OracleComp spec₂')] [LawfulMonadLiftT (OracleComp spec₁') (OracleComp spec₂')] (impl : QueryImpl spec₂' m') (impl₁ : QueryImpl spec₁' m') (h : ∀ (t : ι₁'), simulateQ impl (liftM (liftM (OracleSpec.query t))) = impl₁ t) (oa : OracleComp spec₁' α) :
      simulateQ impl (liftM oa) = some <$> simulateQ impl₁ oa

      OptionT companion to QueryImpl.simulateQ_liftM_eq_of_query: simulating an OracleComp-computation oa lifted into OptionT (OracleComp spec₂') (the shape produced by an OptionT-monadic verifier's let _ ← liftM (queryHelper) binds) agrees, at the run (Option) level, with some-mapping the simulation of oa through a per-query-bridged handler impl₁.

      The key step is the OptionT.run_lift law, which collapses the OptionT lift chain to a plain OracleComp lift; the chain-agnostic QueryImpl.simulateQ_liftM_eq_of_query then resolves it.