///|
/// Evaluate Foreach
fn eval_foreach(
  gen_expr : Expr,
  var_name : String,
  init_expr : Expr,
  update_expr : Expr,
  extract_expr : Expr?,
  input : Json,
  env : Env,
) -> Iter[Json] raise InterpreterError {
  let gen_results = eval_with_env(gen_expr, input, env).collect()
  let init_value = match eval_with_env(init_expr, input, env).collect() {
    [] => return Iter::empty()
    [first, ..] => first
  }
  let (_acc, results) : (Json, Array[Json]) = gen_results.fold(
    init=(init_value, []),
    fn(state, gen_result) raise InterpreterError {
      let (acc, results) = state
      let new_env = env.with_binding(var_name, gen_result)
      let update_results = eval_with_env(update_expr, acc, new_env).collect()
      match update_results {
        [] => (acc, results)
        [next, ..] => {
          let output = match extract_expr {
            Some(extract) => {
              let extract_results = eval_with_env(extract, next, new_env).collect()
              match extract_results {
                [] => next
                [first, ..] => first
              }
            }
            None => next
          }
          results.push(output)
          (next, results)
        }
      }
    },
  )
  results.iter()
}