···8383 let set = freeVarsIn(subst, term)
8484 set->Belt.Set.has(idx)
8585}
8686-// f might map an index to a new one or to a term. when mapping to a term the real index without shifting is passed
8686+// f might map an index to a new one (Ok(newIdx)) or to a term (Error(t) with t(from)).
8787+// Note that Ok and Error here are not used for success or failure; they are just two cases distinguishing between an index and a term.
8788let rec mapbind0 = (term: t, f: int => result<int, int => t>, ~from: int=0): t =>
8889 switch term {
8990 | Symbol(_) => term
···208209 | Unallowed => Unallowed
209210 }
210211// beta reduced and eta reduced
211211-let rec reduceFull = (term: t, subst: subst): t => {
212212+let rec reduce = (term: t): t => {
212213 switch term {
213213- | Schematic({schematic}) if subst->substHas(schematic) =>
214214- let found = subst->substGet(schematic)->Option.getExn
215215- reduceFull(found, subst)
216216- | Lam({body: App({func, arg: Var({idx: 0})})}) if !(func->freeVarsContains(subst, 0)) =>
217217- reduceFull(downshift(func, 1), subst)
214214+ | Lam({body: App({func, arg: Var({idx: 0})})}) if !(func->freeVarsContains(emptySubst, 0)) =>
215215+ reduce(downshift(func, 1))
218216 | App({func, arg}) =>
219219- switch reduceFull(func, subst) {
220220- | Lam({body}) => reduceFull(substDeBruijn(body, [arg]), subst)
221221- | func => App({func, arg: reduceFull(arg, subst)})
217217+ switch reduce(func) {
218218+ | Lam({body}) => reduce(substDeBruijn(body, [arg]))
219219+ | func => App({func, arg: reduce(arg)})
222220 }
223221 | Lam({name, body}) =>
224222 Lam({
225223 name,
226226- body: reduceFull(body, subst),
224224+ body: reduce(body),
227225 })
228226 | Symbol(_) | Var(_) | Schematic(_) => term
229227···231229 }
232230}
233231let reduceSubst = (subst: subst): subst => {
234234- subst->Belt.Map.Int.map(x => reduceFull(x, subst))
232232+ subst->Belt.Map.Int.map(x => reduce(substitute(x, subst)))
235233}
236234let rec lams = (amount: int, term: t): t => {
237235 assert(amount >= 0)