Lean4
/-- `mkComp v e` checks whether `e` is a sequence of nested applications `f (g (h v))`, and if so,
returns the expression `f ∘ g ∘ h`. If `e = v` it returns `id`. -/
def mkComp (v : Expr) : Expr → MetaM Expr
| .app f e =>
if e.equal v then return f
else do
if v.occurs f then
throwError"mkComp failed occurs check"
let e' ← mkComp v e
mkAppM ``Function.comp #[f, e']
| e => do
guard (e.equal v)
let t ← inferType e
mkAppOptM ``id #[t]