PromptingIndex
← All posts

PAL: How Writing Code Instead of Prose Makes Language Models Better at Math

2026-08-04

Chain-of-thought prompting made language models dramatically better at multi-step reasoning by asking them to show their work. The technique works well when the work is linguistic: identifying what a problem is asking, breaking it into parts, naming the relevant variables. It works far less well when the work is arithmetic. A model can decompose a word problem perfectly, name each intermediate quantity correctly, and still calculate the wrong number when it gets to the computation step. Program-Aided Language Models, introduced in November 2022, fix this by replacing the computation with Python code that a real interpreter executes. The model writes the steps; the interpreter does the math.

The problem: decomposition is easy, arithmetic is not

When chain-of-thought prompting was evaluated on grade school math problems in 2022, one failure pattern stood out. Models decomposed the problem structure correctly but made arithmetic mistakes when calculating intermediate values. The error did not come from misunderstanding the question. It came from the model treating arithmetic as a next-token prediction task, which it is mechanically, rather than as a computation performed by a deterministic procedure. A model generating '47 plus 83 equals' is not running an adder; it is sampling from a distribution over likely continuations of that string, a distribution that is approximately right on easy sums and unreliable on harder ones.

This suggests a natural division of labor. Language models are good at reading text, identifying relevant quantities, naming variables, and expressing procedural logic. Python interpreters are perfectly reliable at arithmetic, variable assignment, and symbolic operations. PAL is the technique that exploits this division: the model writes a Python function, and an interpreter runs it.

The paper: authors and approach

The paper 'PAL: Program-aided Language Models' was submitted to arXiv on November 18, 2022 (arXiv:2211.10435) by Luyu Gao, Aman Madaan, and Shuyan Zhou as equal first authors, along with Uri Alon, Pengfei Liu, Yiming Yang, Jamie Callan, and Graham Neubig at Carnegie Mellon University. It was accepted at ICML 2023. The core idea is to change what the model is asked to produce. In chain-of-thought, the model generates natural language reasoning steps and a natural language final answer. In PAL, the model generates a Python function that reads the problem's quantities as variables, performs the required computations using Python expressions and control flow, and returns the answer. A Python interpreter then executes the function and returns the result.

The few-shot prompt used in PAL includes complete worked examples where each problem is solved by a Python function rather than a prose derivation. For a problem asking how many apples remain after eating some from a basket, the example shows a function that assigns the initial count to a variable, subtracts the eaten count, and returns the result. The model learns the pattern from these examples and applies it to new problems. The interpreter guarantees that whatever the function returns is arithmetically correct, assuming the model set up the problem structure correctly.

What the benchmarks showed

The paper evaluated PAL across 13 mathematical, symbolic, and algorithmic reasoning tasks drawn from BIG-Bench Hard and other benchmarks. In every task, generating code with a language model and executing it with a Python interpreter outperformed chain-of-thought prompting with larger models. The headline result: PAL using Codex, a code-trained model from OpenAI, achieved state-of-the-art few-shot accuracy on GSM8K, the benchmark of grade school math word problems, surpassing PaLM-540B with chain-of-thought by an absolute 15 percentage points on top-1 accuracy. The Codex model has far fewer parameters than PaLM-540B, yet the PAL approach allowed it to outperform the much larger model using standard chain-of-thought.

  • GSM8K (math word problems): PAL with Codex outperformed PaLM-540B with chain-of-thought by 15 percentage points absolute on top-1 accuracy.
  • The result held across all 13 tasks in the evaluation. No task saw PAL perform worse than chain-of-thought given the same or a smaller backbone model.
  • Symbolic tasks such as those requiring date arithmetic, object counting, and algorithmic manipulation were included alongside arithmetic word problems, and PAL outperformed CoT on all of them.
  • The gains came from the interpreter handling computation reliably. When the model correctly set up a Python function, the answer was exact. The failure mode shifted from arithmetic error to structural error: the model occasionally misread the problem and wrote a function solving a different question than the one asked.

Why an interpreter beats the model's arithmetic

The reliability gap between a language model's arithmetic and a Python interpreter's arithmetic is absolute. Python arithmetic is exact for integers and precisely defined for floats. A language model's arithmetic is probabilistic. On simple single-digit problems the distribution is sharply peaked at the correct answer. On multi-step problems with intermediate carry operations, the distribution spreads, and mistakes accumulate across steps. This is not a property of any specific model. It follows from the architecture: autoregressive token generation is not a calculation procedure, and no amount of scale fully eliminates the mismatch.

Offloading computation to an interpreter also produces auditable steps. A Python function is readable and editable. If a PAL answer is wrong, the cause is typically visible in the function: a wrong variable assignment, a missing subtraction, a misread constraint. In chain-of-thought, the error is embedded in a prose paragraph that can appear confident and coherent even when it is arithmetically incorrect. The code format makes errors easier to catch and correct.

When PAL applies and when it does not

PAL is well suited to problems with a well-defined computational structure: arithmetic word problems, symbolic manipulation, date calculations, combinatorics, and any reasoning task where intermediate values feed into a final numerical or Boolean result. If the answer to a problem can be expressed as the return value of a Python function, PAL is likely to help. The structure of the problem does not need to be obvious to the user. The model infers the structure from the text, assigns variables, and constructs the computation, so PAL generalizes beyond narrowly numeric domains to any problem where quantities combine in a predictable way.

It is less useful for problems that do not have a computational kernel. Summarization, creative generation, open-ended analysis, and argument evaluation do not benefit from offloading computation, because the core of those tasks is linguistic judgment rather than arithmetic. PAL also requires access to a Python runtime. The model produces code; something must execute it. In an API setting, this means the calling application needs to extract the generated code and run it, then return the result. That integration step is straightforward but requires infrastructure that a plain text completion call does not.

How to apply PAL today

The practical implementation of PAL requires three pieces: few-shot examples that show Python solutions to representative problems, a model call that generates a Python function for the new problem, and a runtime that executes the generated code and returns the answer.

  • Write two to four examples in your prompt where each problem is solved by a Python function. Include the function definition, variable assignments for each named quantity, and a return statement. The model will match this pattern for new problems.
  • Use a model with code training in its data. Codex was the original PAL backbone. Current equivalents include GPT-4o, Claude, Gemini, and open models fine-tuned on code. General-purpose instruction models also work well because most now include substantial code training.
  • Execute the generated code in a sandboxed environment. Python's exec or subprocess with a timeout is sufficient for most arithmetic tasks. Sanitize inputs and restrict imports to prevent the model from writing dangerous operations.
  • If code execution fails because the model wrote syntactically broken Python, fall back to chain-of-thought and return its answer. Failure rates are low on structured arithmetic tasks but non-zero.
  • For tasks involving non-integer arithmetic such as percentages or rates, use Python's decimal module or Fraction type rather than floating-point to avoid precision loss in the computed result.

PAL is one of the clearest examples of a prompting technique that improves accuracy by correctly identifying what the model is good at and what it is not. The model is good at reading language and writing code. Python is good at running code. Combining them separates the task along the boundary where each component is most reliable. PromptingIndex covers PAL patterns and code-grounded prompting setups tested across Claude, ChatGPT, and Gemini, including examples for math, date reasoning, and symbolic tasks.

Put these ideas to work.

Browse the prompt library