@Override protected final Expr unLambda(final Name n) { final Map<Name, Expr> map = defs.unLambda().getMap(); final LinkedList<Set<Name>> sorted = topoSort(map); Expr ex = getBody(); for (final Set<Name> names : sorted) { if (names.size() == 1) { final Name nm = names.iterator().next(); final Expr def = map.get(nm); final int uses = ex.numOfUses(nm); if (uses == 0) { // name unused, ignore it log.info("removing unused definition " + nm + ": " + def); } else if (uses == 1 || def instanceof Value) { // can be inlined log.info("inlining " + nm + ": " + def); ex = ex.inline(nm, def); } else { ex = App.create(new Lambda(nm.toString(), ex), map.get(nm)); } } else { final Name[] na = names.toArray(new Name[names.size()]); Expr funs = NIL, res = K.app(ex); for (final Name element : na) { funs = CONS.app(map.get(element), funs); } funs = K.app(funs); for (final Name element : na) { funs = U.app(new Lambda(element.toString(), funs)); if (res.hasFree(element)) { res = U.app(new Lambda(element.toString(), res)); } else { // name unused, ignore it log.info("rewriting unused name: U { " + element + " -> f } ==> (f . tl)"); final Name nm = Name.createName(); res = new Lambda(nm.toString(), App.create(res, TL.app(nm))); } } ex = App.create(res, Y.app(funs)); } } return ex.unLambda(n); }