{
  "category": "Logical functions",
  "display_name": "REDUCE",
  "entry_kind": "built_in_function",
  "eval_api": {
    "method": "POST",
    "url": "https://handbook.dnacalc.com/api/eval"
  },
  "function_id": "FUNC.REDUCE",
  "implementation_state": {
    "answer_bank": null,
    "detail": "Recorded: 16 workbook cells.",
    "dnacalc_commit": "9e1884369a678158dd82d3d74188daf986995e87",
    "in_catalogue": true,
    "state": "matches",
    "state_label": "Matches every recorded Excel answer",
    "summary": "Matches all 16 recorded answers",
    "workbook_corpus": {
      "cells": 16,
      "matched": 16
    }
  },
  "implementations": [
    {
      "commit": "9e1884369a678158dd82d3d74188daf986995e87",
      "flavour": "excel-compatibility-candidate",
      "language": "Rust",
      "name": "CalcFunc",
      "own_code": [
        "https://github.com/DnaCalc/DnaCalc/blob/9e1884369a678158dd82d3d74188daf986995e87/crates/calc-func/src/catalogue/lambda_helpers.rs#L450-L450",
        "https://github.com/DnaCalc/DnaCalc/blob/9e1884369a678158dd82d3d74188daf986995e87/crates/calc-func/src/catalogue/lambda_helpers.rs#L176-L182"
      ],
      "repository": "https://github.com/DnaCalc/DnaCalc",
      "shared_code": [
        "catalogue/lambda_helpers::prepared",
        "catalogue/lambda_helpers::lambda",
        "catalogue/lambda_helpers::item",
        "catalogue/lambda_helpers::cell",
        "catalogue/lambda_helpers::items",
        "catalogue/lambda_helpers::array",
        "catalogue/lambda_helpers::reduce_task",
        "catalogue/lambda_helpers::helper",
        "catalogue/lambda_helpers::HelperTask::advance",
        "catalogue/lambda_helpers::run"
      ],
      "source": "https://github.com/DnaCalc/DnaCalc/blob/9e1884369a678158dd82d3d74188daf986995e87/crates/calc-func/src/catalogue/lambda_helpers.rs#L450-L450",
      "state": "matches",
      "suite": null,
      "summary": "Matches all 16 recorded answers"
    }
  ],
  "json_url": "https://handbook.dnacalc.com/api/functions/FUNC.REDUCE.json",
  "name": "REDUCE",
  "notes": [],
  "schema": "efh.function-reference/v1",
  "section_order": [
    "what-it-does",
    "try-it",
    "quirks",
    "how-to-implement",
    "version-differences",
    "alternatives"
  ],
  "sections": {
    "alternatives": "\n### Relationships\n\n\n- **`SCAN`** is `REDUCE` that keeps every intermediate accumulator instead of only the last, and\n  returns an array shaped like the input. If you want to see the running total rather than the\n  total, `SCAN` is the function.\n- **`MAP`** transforms without accumulating; **`BYROW`** and **`BYCOL`** reduce along one axis.\n  `REDUCE` is the only member of the set that collapses everything to one value.\n- **`SUM`, `PRODUCT`, `CONCAT`, `TEXTJOIN`** are the built-in folds. Prefer them when they fit:\n  they are faster and, for `SUM`, their summation behaviour is the one the rest of the workbook\n  assumes.\n- **`LAMBDA`** supplies the callable; recursion via a named lambda is the alternative route to\n  iteration, and `REDUCE` is usually the clearer one.\n- Readers confuse `REDUCE` with `MAP` (accumulating versus transforming) and with `SCAN` (final\n  versus running).\n\n\n",
    "how-to-implement": "\n### Notes for implementers\n\n2. **Thread the accumulator by value and accept it before preparing the next argument.** Preparing\n   several argument slices ahead of time is the natural optimisation and it is incorrect here.\n3. **Do not assume the accumulator's kind is stable.** Typing the fold to the initial value's kind\n   will fail on the first callable that changes it.\n4. **State the empty-array answer.** Returning `initial_value` is the mathematically obvious\n   choice; make it explicit rather than falling out of a loop that never ran.\n5. **A fast path for all-numeric arrays must produce identical results to the general path**,\n   including the order of operations — otherwise the optimisation is observable.\n\n\n",
    "quirks": "\n### Result and edge cases\n\n\nReturns a single value of whatever kind the last invocation produced. Unlike the other helpers on\nthis shelf, `REDUCE` does not return an array.\n\n- **Empty array.** With nothing to fold, `initial_value` should be the answer. This is the\n  degenerate case most likely to differ between implementations and is unverified here.\n- **Single-cell array.** One invocation.\n- **Accumulator kind changes mid-fold.** Nothing forbids it: a fold that starts with a number and\n  concatenates text will have a text accumulator after the first step. The callable is responsible\n  for coherence.\n- **Errors in the array.** Delivered to the callable as ordinary argument values. Whether the fold\n  continues past an error depends entirely on what the callable returns.\n- **Accumulator becomes an error.** It is threaded onward like any other value unless the callable\n  handles it, so one bad cell typically poisons the whole result — usually the desired behaviour,\n  occasionally a surprise.\n\n\n",
    "sources": "- Handbook call-model chapters\n  [01 The value universe](../model/01-value-universe.md),\n  [02 Coercion and lifting](../model/02-coercion-and-lifting.md),\n  [03 The call pipeline](../model/03-call-pipeline.md).\n- `data/functions/FUNC.REDUCE.json` — arity 3–3, `ReductionFold` error collapse, and the\n  `numerical_reduction_policy=SequentialLeftFold` semantic-kernel marker.\n- `data/presence/FUNC.REDUCE.json`.\n- `data/battery/FUNC.REDUCE.json` — every row records that the function cannot be called by the\n  battery runner because it requires a callable argument.\n\n\n",
    "version-differences": "No comparison between specific Excel builds is recorded here yet. This does not establish that all builds behave alike.",
    "what-it-does": "\n`REDUCE` folds an array into a single value by threading an **accumulator** through it, one cell at\na time.\n\nThe rule:\n\n1. The accumulator starts at `initial_value`.\n2. The array is enumerated in row-major order.\n3. For each cell, the callable is invoked with two arguments — the current accumulator and the\n   cell's value — and its result becomes the new accumulator.\n4. When the enumeration ends, the accumulator is the result.\n\nOrder matters here in a way it does not for `MAP`, `BYROW`, or `BYCOL`, and for two distinct\nreasons:\n\n- **Semantically**, because the callable need not be associative or commutative. Building a\n  delimited string, or subtracting each element in turn, gives different answers under a different\n  order.\n- **Numerically**, because floating-point addition is not associative. A left fold over an array of\n  doubles is a specific summation algorithm with a specific error behaviour, and it is not the same\n  algorithm `SUM` uses. `REDUCE(0, range, LAMBDA(a,v,a+v))` and `SUM(range)` are not required to\n  agree in the last bits, and expecting them to is a mistake worth naming explicitly.\n\n\n\n### Arguments\n\n\n`REDUCE(initial_value, array, lambda)`\n\n- **`initial_value`** — required. The accumulator's starting value. It is the *first* argument, not\n  the last, which is the position most easily misremembered.\n- **`array`** — required. The values to fold over.\n- **`lambda`** — required, and always third. It takes exactly two parameters, in the order\n  `(accumulator, value)`.\n\nThe commonly misunderstood positions are the first argument and the callable's parameter order.\nSwapping `(accumulator, value)` for `(value, accumulator)` produces a lambda that runs without\ncomplaint and computes something else.\n\n\n"
  },
  "signature": {
    "display": "REDUCE(initial_value, array, lambda)",
    "parameters": [
      {
        "description": null,
        "name": "initial_value",
        "optional": false,
        "repeats": false
      },
      {
        "description": null,
        "name": "array",
        "optional": false,
        "repeats": false
      },
      {
        "description": null,
        "name": "lambda",
        "optional": false,
        "repeats": false
      }
    ],
    "trailing_repeats": false
  },
  "sources": {
    "metadata": {
      "admission": {
        "label": "implemented",
        "reason": null
      },
      "arity": {
        "max": 3,
        "min": 3
      },
      "category": "Logical functions",
      "classification": {
        "arg_preparation_profile": "ValuesOnlyPreAdapter",
        "coercion_lift_profile": "Custom",
        "determinism_class": "Deterministic",
        "error_collapse_profile": "ReductionFold",
        "fec_dependency_profile": "None",
        "host_interaction_class": "None",
        "kernel_signature_class": "Custom",
        "rich_value_usage": "RichBlind",
        "surface_fec_dependency_profile": "RefOnly",
        "thread_safety_class": "SafePure",
        "volatility_class": "NonVolatile"
      },
      "descriptions": {
        "long": null,
        "short": "A running total built by a LAMBDA over each item of an array, giving the final value",
        "short_source": "dna-calc-own"
      },
      "docs": {
        "english_description": "Reduces an array to an accumulated value by applying a LAMBDA to each value and returning the total value in the accumulator",
        "microsoft_url": "https://support.microsoft.com/en-us/office/reduce-function-42e39910-b345-45f3-84b8-0642b568b7cb"
      },
      "entry_kind": "built_in_function",
      "localized_family_names": null,
      "localized_names": [
        {
          "locale": "ar-SA",
          "name": "REDUCE"
        },
        {
          "locale": "bg-BG",
          "name": "REDUCE"
        },
        {
          "locale": "cs-CZ",
          "name": "REDUCE"
        },
        {
          "locale": "da-DK",
          "name": "REDUCE"
        },
        {
          "locale": "de-DE",
          "name": "REDUCE"
        },
        {
          "locale": "el-GR",
          "name": "REDUCE"
        },
        {
          "locale": "en-AU",
          "name": "REDUCE"
        },
        {
          "locale": "en-GB",
          "name": "REDUCE"
        },
        {
          "locale": "en-US",
          "name": "REDUCE"
        },
        {
          "locale": "es-ES",
          "name": "REDUCE"
        },
        {
          "locale": "et-EE",
          "name": "REDUCE"
        },
        {
          "locale": "fi-FI",
          "name": "REDUCE"
        },
        {
          "locale": "fr-FR",
          "name": "REDUCE*"
        },
        {
          "locale": "he-IL",
          "name": "REDUCE"
        },
        {
          "locale": "hr-HR",
          "name": "REDUCE"
        },
        {
          "locale": "hu-HU",
          "name": "REDUCE"
        },
        {
          "locale": "id-ID",
          "name": "REDUCE"
        },
        {
          "locale": "it-IT",
          "name": "REDUCE"
        },
        {
          "locale": "ja-JP",
          "name": "REDUCE"
        },
        {
          "locale": "ko-KR",
          "name": "REDUCE"
        },
        {
          "locale": "lt-LT",
          "name": "REDUCE"
        },
        {
          "locale": "lv-LV",
          "name": "REDUCE"
        },
        {
          "locale": "nb-NO",
          "name": "REDUCE"
        },
        {
          "locale": "nl-NL",
          "name": "REDUCEREN"
        },
        {
          "locale": "pl-PL",
          "name": "REDUCE"
        },
        {
          "locale": "pt-BR",
          "name": "REDUZIR"
        },
        {
          "locale": "pt-PT",
          "name": "REDUCE"
        },
        {
          "locale": "ro-RO",
          "name": "REDUCE"
        },
        {
          "locale": "ru-RU",
          "name": "REDUCE"
        },
        {
          "locale": "sk-SK",
          "name": "REDUCE"
        },
        {
          "locale": "sl-SI",
          "name": "REDUCE"
        },
        {
          "locale": "sr-Latn-RS",
          "name": "SMANJITI"
        },
        {
          "locale": "sv-SE",
          "name": "REDUCE"
        },
        {
          "locale": "th-TH",
          "name": "REDUCE"
        },
        {
          "locale": "tr-TR",
          "name": "REDUCE"
        },
        {
          "locale": "uk-UA",
          "name": "REDUCE"
        },
        {
          "locale": "vi-VN",
          "name": "REDUCE"
        },
        {
          "locale": "zh-CN",
          "name": "REDUCE"
        },
        {
          "locale": "zh-HK",
          "name": "REDUCE"
        },
        {
          "locale": "zh-TW",
          "name": "REDUCE"
        }
      ],
      "signature": {
        "display": "REDUCE(initial_value, array, lambda)",
        "parameters": [
          {
            "description": null,
            "name": "initial_value",
            "optional": false,
            "repeats": false
          },
          {
            "description": null,
            "name": "array",
            "optional": false,
            "repeats": false
          },
          {
            "description": null,
            "name": "lambda",
            "optional": false,
            "repeats": false
          }
        ],
        "trailing_repeats": false
      },
      "surface_name": "REDUCE",
      "version_marker": null,
      "xlcall": null
    },
    "microsoft": "https://support.microsoft.com/en-us/office/reduce-function-42e39910-b345-45f3-84b8-0642b568b7cb"
  },
  "try_it": {
    "formula": "=REDUCE(0,{1;2;3},LAMBDA(a,b,a+b))"
  },
  "url": "https://handbook.dnacalc.com/functions/REDUCE.html",
  "variants": [],
  "versions": []
}