I was afraid because Free is u + 1 since it quantifies on β which is a Type u, but it works.
That's great, but if I understand the first link I provided it yields code that's asymptotically slower than necessary.
So I went for the Yoneda/Rec encoding discussed in the second blog post reference (beware the aggressive background), which goes like this unless I messed something up.
Church-encoded
/-! # Defining `Fre` through `Yoneda` and `Rec` -/abbrevYoneda(F:Typeu→Typeu)(α:Typeu):=∀{β:Typeu},(α→β)→FβnamespaceYonedadefdrop(y:YonedaFα):Fα:=yidinstanceinstMonad[MonadM]:Monad(YonedaM)wherepurea:=funk=>returnkabindyf:=funk=>y.drop>>=(f·k)endYonedaabbrevRec(M:Typeu→Typev)(α:Typeu):Type(maxuv):=(Mα→α)→αabbrevFre(M:Typeu→Typeu):=-- `∀ {β : Type u}, (α → β) → (M β → β) → β`Yoneda(RecM)namespaceFreinstanceinstMonad:Monad(FreM)wherepurea:=funk_k'=>kabindselff:=funkk'=>self(f·kk')k'instanceinstMonadLift[FunctorM]:MonadLiftM(FreM)wheremonadLiftm:=funkk'=>k<$>m|>k'deflift[FunctorM]:Mα→FreMα:=monadLift/-! ## Now I can define `Pause` -/inductivePause.Op(σ:Typeu)(α:Typeu)|mutate:(σ→σ)→α→Opσα|yield:α→Opσα/-- Needed to use `Fre.lift` directly. -/instancePause.Op.instFunctor:Functor(Opσ)wheremapf|mutatega=>mutateg(fa)|yielda=>fa|>yielddefPause(σ:Typeu):=Fre(Pause.Opσ)namespacePausedefmutate(f:σ→σ)(next:α):Pauseσα:=Op.mutatefnext|>Fre.liftdefyield(a:α):Pauseσα:=funconvtail=>Op.yield(conva)|>taildefdone(a:α):PauseMα:=Fre.instMonad.pureainstanceinstMonad:Monad(Pauseσ):=byunfoldPauseexactinferInstancedefstep(code:Pauseσα)(state:σ):σ×Option(Pauseσα):=sorry-- code (fun _ => (state, none))-- fun-- | .mutate f (state, res?) => sorry-- | .yield res => sorryendPauseendFre
But now I don't see how I can write the Fre.Pause.step function. My understanding is that I need to get code to produce the result I want, meaning the (hidden) β : Type u in Fre's definition must be σ × Option (Pause σ α) or something similar.
But that can't work since β : Type u and σ × Option (Pause σ α) : Type (u + 1).
At this point I assume I discovered something well-known about type constructors like Fre in constructive languages and/or languages with non-cumulative type universes. Probably that if allowed this would bring untyped lambda-calculus or something.
Is it the case, or did I mess something up?
If it's the former, is there a way around it? Like using Free but doing something tricky with SeqLeft/SeqRight?
If it's the latter, I would appreciate if anyone had time to elaborate.