private Expr cleanupOpExpr(OpExpr opExp) {
    FunctionalRef ref = opExp.getOp();

    List<Expr> args = opExp.getArgs();

    if (args.size() <= 1) return opExp;
    IdOrOp name = ref.getNames().get(0);
    if (!(name instanceof Op)) return bug(name, "The name field of OpRef should be Op.");
    Op qop = (Op) name;

    if (OprUtil.isEnclosing(qop)) return opExp;
    if (OprUtil.isUnknownFixity(qop))
      return bug(opExp, "The operator fixity is unknown: " + ((Op) qop).getText());
    boolean prefix = OprUtil.hasPrefixColon(qop);
    boolean suffix = OprUtil.hasSuffixColon(qop);
    if (!prefix && !suffix) return opExp;
    qop = OprUtil.noColon(qop);
    Iterator<Expr> i = args.iterator();
    Expr res = i.next();
    Span sp = NodeUtil.getSpan(opExp);
    for (Expr arg : Iter.iter(i)) {
      if (prefix) {
        res = thunk(res);
      }
      if (suffix) {
        arg = thunk(arg);
      }
      res = ExprFactory.makeOpExpr(sp, qop, res, arg);
    }
    return res;
  }
  @Override
  public Node forOpExpr(OpExpr that) {
    FunctionalRef op_result = (FunctionalRef) recur(that.getOp());

    /**
     * * For BIG OP <| BIG OT <| f y | y <- ys |> | ys <- gg |> Is this case, BIG <||> is being
     * removed. The nested reduction is replaced with __bigOperator2(BIG OP, BIG OT, gg)
     *
     * <p>by Kento
     */
    String str = op_result.toString();
    String theListEnclosingOperatorName = "BIG <| BIG |>";
    String someBigOperatorName = "BIG";

    // make sure the body is of application of some big operator
    if ((str.length() >= someBigOperatorName.length()
        && str.substring(0, someBigOperatorName.length()).equals(someBigOperatorName))) {
      // make sure that BIG OP (Accumulator (BIG <||>, gs))
      if (that.getArgs().size() == 1
          && that.getArgs().get(0) instanceof Accumulator
          && ((Accumulator) that.getArgs().get(0))
              .getAccOp()
              .toString()
              .equals(theListEnclosingOperatorName)) {

        Accumulator acc = (Accumulator) that.getArgs().get(0);
        Expr body = visitGenerators(NodeUtil.getSpan(acc), acc.getGens(), acc.getBody());
        /**
         * * If the accumulation is a nested reduction like <| BIG OT <| f y | y <- ys |> | ys <- gg
         * |> , visitGenerators returns a tuple of ((BIG OT, f), gg) (this should be refactored,
         * though) In this case, the nested reduction is replaced with __bigOperator2
         */
        if (body instanceof TupleExpr) {
          // a tuple of the inner Accumulator (op, body) and the gg
          TupleExpr tuple = (TupleExpr) body;
          TupleExpr innerAccumTuple = (TupleExpr) tuple.getExprs().get(0);
          Expr opexpI = (Expr) innerAccumTuple.getExprs().get(0);
          Expr innerBody = (Expr) innerAccumTuple.getExprs().get(1);
          FunctionalRef ref = (FunctionalRef) op_result;
          IdOrOp name = ref.getNames().get(0);
          // make sure the operator is actually an operator
          if (!(name instanceof Op)) return null;
          Expr opexpO =
              ExprFactory.makeOpExpr(NodeUtil.getSpan(that), (Op) name, ref.getStaticArgs());
          Expr gg = tuple.getExprs().get(1);
          Expr res =
              ExprFactory.make_RewriteFnApp(
                  NodeUtil.getSpan(that),
                  BIGOP2_NAME,
                  ExprFactory.makeTupleExpr(NodeUtil.getSpan(body), opexpO, opexpI, gg, innerBody));
          return (Expr) recur(res);
        }
      }
    }

    List<Expr> args_result = recurOnListOfExpr(that.getArgs());

    OpExpr new_op;
    if (op_result == that.getOp() && args_result == that.getArgs()) {
      new_op = that;
    } else {
      new_op =
          ExprFactory.makeOpExpr(
              NodeUtil.getSpan(that),
              NodeUtil.isParenthesized(that),
              NodeUtil.getExprType(that),
              op_result,
              args_result);
    }
    return cleanupOpExpr(new_op);
  }