fn replace_builder(
    lambda: &Expr,
    nested: &Expr,
    sym_gen: &mut SymbolGenerator,
) -> WeldResult<Expr> {
    // Tests whether an identifier and symbol refer to the same value by
    // comparing the symbols.
    fn same_iden(a: &ExprKind, b: &Symbol) -> bool {
        if let Ident(ref symbol) = *a {
            symbol == b
        } else {
            false
        }
    }

    if let Lambda {
        params: ref args,
        ref body,
    } = lambda.kind
    {
        if let Lambda {
            params: ref nested_args,
            ..
        } = nested.kind
        {
            let mut new_body = *body.clone();
            let old_bldr = &args[0];
            let old_index = &args[1];
            let old_arg = &args[2];
            let new_bldr_sym = sym_gen.new_symbol(&old_bldr.name.name());
            let new_index_sym = sym_gen.new_symbol(&old_index.name.name());
            let new_bldr = Expr::new_ident(new_bldr_sym.clone(), nested_args[0].ty.clone())?;
            let new_index = Expr::new_ident(new_index_sym.clone(), nested_args[1].ty.clone())?;

            // Fix expressions to use the new builder.
            new_body.transform_and_continue_res(&mut |ref mut e| match e.kind {
                Merge {
                    ref builder,
                    ref value,
                } if same_iden(&(*builder).kind, &old_bldr.name) => {
                    let params: Vec<Expr> =
                        vec![new_bldr.clone(), new_index.clone(), *value.clone()];
                    let mut expr = Expr::new_apply(nested.clone(), params)?;
                    inline_apply(&mut expr);
                    Ok((Some(expr), true))
                }
                For {
                    iters: ref data,
                    builder: ref bldr,
                    ref func,
                } if same_iden(&(*bldr).kind, &old_bldr.name) => {
                    let expr = Expr::new_for(
                        data.clone(),
                        new_bldr.clone(),
                        replace_builder(func, nested, sym_gen)?,
                    )?;
                    Ok((Some(expr), false))
                }
                Ident(ref mut symbol) if *symbol == old_bldr.name => {
                    Ok((Some(new_bldr.clone()), false))
                }
                Ident(ref mut symbol) if *symbol == old_index.name => {
                    Ok((Some(new_index.clone()), false))
                }
                _ => Ok((None, true)),
            });

            // Fix types to make sure the return type propagates through all subexpressions.
            match_types(&new_bldr.ty, &mut new_body);

            let new_params = vec![
                Parameter {
                    ty: new_bldr.ty,
                    name: new_bldr_sym,
                },
                Parameter {
                    ty: Scalar(ScalarKind::I64),
                    name: new_index_sym,
                },
                Parameter {
                    ty: old_arg.ty.clone(),
                    name: old_arg.name.clone(),
                },
            ];
            return Expr::new_lambda(new_params, new_body);
        }
    }
    return compile_err!("Inconsistency in replace_builder");
}
Given a lambda which takes a builder and an argument, returns a new function which takes a new
builder type and calls nested on the values it would've merged into its old builder. This
allows us to "compose" merge functions and avoid creating intermediate results.
weld/src/optimizer/transforms/loop_fusion.rs