A "bit" of information is definable as a difference that makes a difference. — Gregory Bateson, Steps to an Ecology of Mind
Act always so as to increase the number of choices. — Heinz von Foerster
Probabilistic inference in forkable worlds, for Clojure.
A Förster is a forester: someone who tends a forest, grows branches, prunes them, and decides which trees continue. That is what inference over spindel worlds does. Particles branch from a world, resampling prunes the unlikely ones and copies the likely ones, and Markov chains walk the tree of worlds. The name also honours Heinz von Foerster, whose cybernetics put the observer inside the system it observes, as agents inferring inside the worlds they act in are here.
A probabilistic program is a spindel spin with sample, observe and
factor sites. Every site is a spindel savepoint, so an inference algorithm
is a handler that decides, scores, forks, copies or abandons those savepoints:
(infer/infer model {:method :smc :particles 1000})k/cycle and k/mixturefoerster.learn)mem, Chinese restaurant processes, nested
inference (infer/conditional)foerster.steer), with
the trajectories as training data (foerster.learn):proposal draws from a distribution the
program computes, weighted by log p − log qdo), selectors over sites(require '[org.replikativ.foerster.core :as infer]
'[org.replikativ.foerster.dist :as dist]
'[org.replikativ.foerster.effects :refer [sample observe]]
'[org.replikativ.spindel.core :as sp]
'[org.replikativ.spindel.spin.cps :refer [spin]])
;; programs run in a spindel world (an execution context)
(def world (sp/create-execution-context))
(defn model []
(spin
(let [mu (sample (dist/normal 0.0 1.0) :id :mu)]
(observe (dist/normal mu 1.0) 1.0 :id :y)
mu)))
;; inference returns a spin; at the REPL, deref it
(def posterior (sp/with-context world @(infer/infer (model) {:method :smc :particles 1000})))
(:mean (infer/query posterior identity)) ; ≈ 0.5, the posterior is N(0.5, 0.707²)
Inside another spin, await it instead of dereferencing
(org.replikativ.spindel.effects.await).
Pure models run in fresh worlds (:world-policy :fresh, the default). The
particle methods (importance sampling, SMC, particle MCMC, BBVI) also run in
canonical forks of the caller's world (:world-policy :fork), for models
that read or change the systems of the world they run in (databases,
repositories, a business book); Markov chains run in fresh worlds only:
See the worlds guide.
A block is a group of latents sampled at one site, with a log density and its gradient. HMC moves blocks jointly. foerster-raster compiles block densities with raster (JVM, WASM, GPU) and reverse-mode AD.
The sources are .cljc, and inference runs on the JVM and in JavaScript.
Distributions (foerster.dist) are portable Clojure, named and
parameterized like raster's, and the random generator draws the same
numbers for a seed on both platforms. Copying worlds for canonical particles is
JVM-only; in ClojureScript canonical particles are forks.
Monte Carlo began on ENIAC: Stanisław Ulam's idea (1946), John von Neumann's design, Klára Dán von Neumann's code for the first runs (1948), and Nicholas Metropolis's name for it. The Metropolis algorithm followed in 1953.
The idea was to try out thousands of such possibilities and, at each stage, to select by chance, by means of a "random number" with suitable probability, the fate or kind of event, to follow it in a line, so to speak, instead of considering all branches. — Stanisław Ulam
foerster stands on earlier probabilistic programming systems:
sample and
observe are checkpoints, and inference is a continuation-passing
interpreter over them (SMC, PIMH, PGibbs, PGAS, IPMCMC, LMH, BBVI).
foerster's sites are those checkpoints as spindel savepoints, and its
benchmarks reuse Anglican's ground truths.simulate, generate, assess, update, regenerate over traces — which
foerster implements (foerster.gfi), and involutive MCMC.foerster grew inside spindel and was split out with its history.
Copyright © 2026 Christian Weilbach. Apache License 2.0.
Can you improve this documentation?Edit on GitHub
cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |