Zulip Chat Archive

Stream: general

Topic: Nerd sniping: free monads without the universe bump


Paul Reichert (Apr 19 2025 at 21:36):

It has come up a few times that we can construct a free monad from a functor f in Lean:

inductive FreeMonad (f : Type v  Type v) : Type v  Type (v + 1) where
| pure :  {α}, α  FreeMonad f α
| lift :  {α}, f α  FreeMonad f α
| bind :  {α β}, FreeMonad f α  (α  FreeMonad f β)  FreeMonad f β

We can then take a suitable quotient so that FreeMonad f is indeed a lawful monad, and if f is a lawful functor, then I think that FreeMonad f is indeed the free monad we were looking for.

Unfortunately, FreeMonad f suffers a universe bump since its codomain is Type (v + 1). After I was angry at Lean about this for some time, I finally convinced myself that this bump is unavoidable for some choices of f. For example, let f α := α → Bool. If we had a free monad FreeMonad f : Type v → Type v, then we could lift elements from f (FreeMonad f α) into FreeMonad f (FreeMonad f α) and flatten this into FreeMonad f α. I think, without having a formal proof, that this mapping is injective. But the cardinality of the power set f (FreeMonad f α) = (FreeMonad f α → Bool) is strictly larger than that of FreeMonad f α, so this injection is impossible. Contradiction.

However, I can't help but ask whether we can avoid the universe bump in the following more restricted situation: Let m : Type v → Type v be any lawful monad. Can we construct the most general monad m' : Type v → Type v, without universe bump, that extends m by a new operation op : m' PUnit? By "most general", I mean that we don't assume any equations involving op except those we need to obtain a lawful monad.

More formal problem statement

Motivation

The following obvious construction almost solves the problem but it requires a universe bump:

inductive FreeMonad (m : Type v  Type v) : Type v  Type (v + 1) where
| lift :  {α}, m α  FreeMonad m α
| bind :  {α β}, FreeMonad m α  (α  FreeMonad m β)  FreeMonad m β
| op : FreeMonad m PUnit.{v + 1}

I feel like m being a lawful monad should help us prevent paradoxes like the one from the power set example above. However, I couldn't come up with a concrete construction. Any ideas?

Quang Dao (Apr 19 2025 at 22:36):

I came up against the same limitation in my own project! One answer is that the free monad of a polynomial functor PFunctor does not require a universe bump.

import Mathlib.Data.PFunctor.Univariate.Basic

universe u v

/-- The free monad on a polynomial functor.
This extends the `W`-type construction with an extra `pure` constructor. -/
inductive FreeM (P : PFunctor.{u}) : Type v  Type (max u v)
  | pure {α} (x : α) : FreeM P α
  | roll {α} (a : P.A) (r : P.B a  FreeM P α) : FreeM P α
deriving Inhabited

/-- Lift an object of the base polynomial functor into the free monad. -/
@[always_inline, inline]
def lift (x : P.Obj α) : FreeM P α := FreeM.roll x.1 (fun y  FreeM.pure (x.2 y))

/-- Bind operator on `FreeM P` operation used in the monad definition. -/
@[always_inline, inline]
protected def bind : FreeM P α  (α  FreeM P β)  FreeM P β
  | FreeM.pure x, g => g x
  | FreeM.roll x r, g => FreeM.roll x (λ u  FreeM.bind (r u) g)

Lots of functors are polynomials, though I'm not sure if they apply to your use case

Paul Reichert (Apr 20 2025 at 18:44):

Thanks! Very interesting! Unfortunately, I fear that that construction won't help in the general case of adjoining some new operation to an arbitrary monad. I find it more and more plausible that even such a modest extension can require a universe bump... quite surprising if you ask me.


Last updated: May 02 2025 at 03:31 UTC