pub fn fuse_loops_horizontal(expr: &mut Expr) {
    expr.transform(&mut |ref mut expr| {
        let mut sym_gen = SymbolGenerator::from_expression(expr);
        if let For {
            iters: ref all_iters,
            builder: ref outer_bldr,
            func: ref outer_func,
        } = expr.kind
        {
            if all_iters.len() > 1 {
                // Vector of tuples containing the params and expressions of functions in nested lambdas.
                let mut lambdas = vec![];
                let mut common_data = None;
                // Used to check if the same rows of each output are touched by the outer for.
                let first_iter = (&all_iters[0].start, &all_iters[0].end, &all_iters[0].stride);
                // First, check if all the lambdas are over the same vector and have a pattern we can merge.
                // Below, for each iterator in the for loop, we checked if each nested for loop is
                // over the same vector and has the same Iter parameters (i.e., same start, end, stride).
                let iters_same = all_iters.iter().all(|ref iter| {
                    if (&iter.start, &iter.end, &iter.stride) == first_iter {
                        // Make sure each nested for loop follows the ``result(for(a, appender, ...)) pattern.
                        if let Res {
                            builder: ref res_bldr,
                        } = iter.data.kind
                        {
                            if let For {
                                iters: ref iters2,
                                builder: ref bldr2,
                                func: ref lambda,
                            } = res_bldr.kind
                            {
                                if common_data.is_none() {
                                    common_data = Some(iters2.clone());
                                }
                                if iters2 == common_data.as_ref().unwrap() {
                                    if let NewBuilder(_) = bldr2.kind {
                                        if let Builder(ref kind, _) = bldr2.ty {
                                            if let Appender(_) = *kind {
                                                if let Lambda {
                                                    params: ref args,
                                                    ref body,
                                                } = lambda.kind
                                                {
                                                    if let Merge {
                                                        ref builder,
                                                        ref value,
                                                    } = body.kind
                                                    {
                                                        if let Ident(ref n) = builder.kind {
                                                            if *n == args[0].name {
                                                                // Save the arguments and expressions for the function so
                                                                // they can be used for fusion later.
                                                                lambdas.push((
                                                                    args.clone(),
                                                                    value.clone(),
                                                                ));
                                                                return true;
                                                            }
                                                        }
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                    // The pattern doesn't match for some Iter -- abort the transform.
                    false
                });

                if iters_same {
                    // All Iters are over the same range and same vector, with a pattern we can
                    // transform. Produce the new expression by zipping the functions of each
                    // nested for into a single merge into a struct.

                    // Zip the expressions to create an appender whose merge (value) type is a struct.
                    let merge_type = Struct(
                        lambdas
                            .iter()
                            .map(|ref e| e.1.ty.clone())
                            .collect::<Vec<_>>(),
                    );
                    // TODO(Deepak): Fix this to something meaningful.
                    let builder_type =
                        Builder(Appender(Box::new(merge_type.clone())), Annotations::new());
                    // The element type remains unchanged.
                    let func_elem_type = lambdas[0].0[2].ty.clone();

                    // Parameters for the new fused function. Symbols names are generated using symbol
                    // names for the builder and element from an existing function.
                    let new_params = vec![
                        Parameter {
                            ty: builder_type.clone(),
                            name: sym_gen.new_symbol(&lambdas[0].0[0].name.name()),
                        },
                        Parameter {
                            ty: Scalar(ScalarKind::I64),
                            name: sym_gen.new_symbol(&lambdas[0].0[1].name.name()),
                        },
                        Parameter {
                            ty: func_elem_type.clone(),
                            name: sym_gen.new_symbol(&lambdas[0].0[2].name.name()),
                        },
                    ];

                    // Generate Ident expressions for the new symbols and substitute them in the
                    // functions' merge expressions.
                    let new_bldr_expr = Expr {
                        ty: builder_type.clone(),
                        kind: Ident(new_params[0].name.clone()),
                        annotations: Annotations::new(),
                    };
                    let new_index_expr = Expr {
                        ty: Scalar(ScalarKind::I64),
                        kind: Ident(new_params[1].name.clone()),
                        annotations: Annotations::new(),
                    };
                    let new_elem_expr = Expr {
                        ty: func_elem_type,
                        kind: Ident(new_params[2].name.clone()),
                        annotations: Annotations::new(),
                    };
                    for &mut (ref mut args, ref mut expr) in lambdas.iter_mut() {
                        expr.substitute(&args[0].name, &new_bldr_expr);
                        expr.substitute(&args[1].name, &new_index_expr);
                        expr.substitute(&args[2].name, &new_elem_expr);
                    }

                    // Build up the new expression. The new expression merges structs into an
                    // appender, where each struct field is an expression which was merged into an
                    // appender in one of the original functions. For example, if there were two
                    // zipped fors in the original expression with lambdas |b1,e1| merge(b1,
                    // e1+1) and |b2,e2| merge(b2, e2+2), the new expression would be merge(b,
                    // {e+1,e+2}) into a new builder b of type appender[{i32,i32}]. e1, e2, and e
                    // refer to the same element in the expressions above since we check to ensure
                    // each zipped for is over the same input data.
                    let new_merge_expr = Expr {
                        ty: builder_type.clone(),
                        kind: Merge {
                            builder: Box::new(new_bldr_expr),
                            value: Box::new(Expr {
                                ty: merge_type.clone(),
                                kind: MakeStruct {
                                    elems: lambdas
                                        .iter()
                                        .map(|ref lambda| *lambda.1.clone())
                                        .collect::<Vec<_>>(),
                                },
                                annotations: Annotations::new(),
                            }),
                        },
                        annotations: Annotations::new(),
                    };
                    let new_func = Expr {
                        ty: Function(
                            new_params
                                .iter()
                                .map(|ref p| p.ty.clone())
                                .collect::<Vec<_>>(),
                            Box::new(builder_type.clone()),
                        ),
                        kind: Lambda {
                            params: new_params,
                            body: Box::new(new_merge_expr),
                        },
                        annotations: Annotations::new(),
                    };
                    let new_iter_expr = Expr {
                        ty: Vector(Box::new(merge_type)),
                        kind: Res {
                            builder: Box::new(Expr {
                                ty: builder_type.clone(),
                                kind: For {
                                    iters: common_data.unwrap(),
                                    builder: Box::new(Expr {
                                        ty: builder_type,
                                        kind: NewBuilder(None),
                                        annotations: Annotations::new(),
                                    }),
                                    func: Box::new(new_func),
                                },
                                annotations: Annotations::new(),
                            }),
                        },
                        annotations: Annotations::new(),
                    };

                    // TODO(shoumik): Any way to avoid the clones here?
                    return Some(Expr {
                        ty: expr.ty.clone(),
                        kind: For {
                            iters: vec![Iter {
                                data: Box::new(new_iter_expr),
                                start: all_iters[0].start.clone(),
                                end: all_iters[0].end.clone(),
                                stride: all_iters[0].stride.clone(),
                                kind: all_iters[0].kind.clone(),
                                shape: all_iters[0].shape.clone(),
                                strides: all_iters[0].strides.clone(),
                            }],
                            builder: outer_bldr.clone(),
                            func: outer_func.clone(),
                        },
                        annotations: Annotations::new(),
                    });
                }
            }
        }
        None
    });
}
Fuses for loops over the same vector in a zip into a single for loop which produces a vector of
structs directly.

Some examples:

for(zip(
result(for(a, appender, ...))
result(for(a, appender, ...))
), ...)

will become for(result(for(a, ...))) where the nested for will produce a vector of structs with
two elements.

Caveats:
- Like all Zip-based transforms, this function currently assumes that the output of each
expression in the Zip is the same length.
weld/src/optimizer/transforms/loop_fusion.rs