v0.8.3 tutorial · reusable model code

Declare, overload, and call Stan functions

Organize a model with typed functions, forward declarations, lexical locals, checked overloads, data-only arguments, probability suffixes, and guarded recursion.

Source-compatible function core

Definition order

Forward-declare before a later definition

functions {
  real penalty(real x);
  real penalty(real x) { return square(x); }
}
model { target += -0.1 * penalty(theta); }

A declaration and definition must have the same return type, name, argument types, dimensions, and data qualifiers. Duplicate or unresolved declarations are compile errors.

Typed dispatch

Use overloads without runtime guessing

functions {
  real score(real x) { return square(x); }
  real score(vector x) { return dot_product(x, x); }
  vector predict(data matrix X, vector beta) { return X * beta; }
}

Overload selection uses declared container type and shape, with integer-to-real promotion where unambiguous. A data-qualified argument accepts values proven to originate only from data or transformed data; passing a parameter-dependent expression produces a no-matching-overload diagnostic.

Distribution syntax

Follow Stan suffix and target rules

functions {
  real robust_lpdf(real y, real mu) {
    return student_t_lpdf(y | 5, mu, 1);
  }
  real shrink_lp(real x) {
    target += normal_lpdf(x | 0, 2);
    return 0;
  }
}
model {
  y ~ robust(mu);
  target += shrink_lp(mu);
}

_lpdf and _lpmf functions return real and expose sampling-statement shorthand. _lp functions may increment target. The vertical bar in probability calls is accepted.

Finite work

Recursion is supported with a guard

real polynomial_sum(real x, int degree) {
  if (degree == 0) return 1;
  return pow(x, degree) + polynomial_sum(x, degree - 1);
}

Calls have lexical local scope and may recurse, but JDistlib enforces a depth guard so malformed source cannot consume the Java stack indefinitely. Loops have analogous work guards.

Cross the Java boundary explicitly

Bind external declarations or pass functions to solvers

A declaration without a source body may be supplied through ExternalFunctionRegistry. Its Java callback returns an ExternalFunctionResult containing flattened values, result shape, and a full Jacobian; JDistlib inserts it as an atomic reverse node. Tuple arguments/returns participate in ordinary user-function overloads. Function-name arguments are supported by integrate_1d, algebraic solvers, RK45/BDF ODEs, and index-1 DAEs. See examples 34, 35, and 38–41 and the solver tutorial.

Current boundary

Know which services are intentionally narrower

Top-level tuple data/parameters, arrays of tuples, external tuple returns, modern variadic solver signatures, and Stan's parallel reduce_sum/map_rect runtime are not part of the 0.8.3 contract. Unsupported overloads fail explicitly. Examples 11, 14, 15, 29, and 31–41 in the checked Stan catalog are runnable companions.