CHR Reference
CHR constraints are predicates stored in the state and checked lazily. They are deferred while variables are unbound and evaluated when answers are collected by chrRun.
Use chrRun instead of run when your goals include constrain, typeOf, or diseq.
constrain
Section titled “constrain”constrain :: (state -> bool) -> goalRecords a predicate in the state’s constraints list. Always succeeds immediately — the predicate is not checked until chrRun collects answers.
let mustBePositive = ukanren.constrain (state: let v = ukanren.reify state.subst myVar; in ukanren.isVar v || v > 0);Pattern: return true if the variable is still unbound (isVar), or if the constraint is satisfied when ground. Return false to prune the branch.
chrRun
Section titled “chrRun”chrRun :: int -> (var -> goal) -> [term]Like run, but initialises constraints = [] in the state and filters the stream: only answers where all constraints pass are returned.
ukanren.chrRun 5 (q: ukanren.conj (ukanren.typeOf q "int") (ukanren.disj (ukanren.eq q 1) (ukanren.eq q "oops")))# => [ 1 ]typeOf
Section titled “typeOf”typeOf :: var -> string -> goalConstrains var to have a specific Nix type when ground. Valid type strings: "int", "string", "bool", "list", "set", "float", "null".
Uses builtins.typeOf for ground values. Passes silently while the variable is unbound.
ukanren.chrRun 3 (q: ukanren.conj (ukanren.typeOf q "string") (ukanren.disj (ukanren.eq q "hello") (ukanren.eq q 99) # pruned ))# => [ "hello" ]diseq :: term -> term -> goalAsserts that two terms are not equal when both are ground. Deferred while either term contains an unbound variable.
ukanren.chrRun 5 (q: ukanren.conj (ukanren.diseq q 2) (ukanren.disj (ukanren.eq q 1) (ukanren.eq q 2) # pruned ))# => [ 1 ]Custom constraints
Section titled “Custom constraints”Any state -> bool function works with constrain. Access the substitution via state.subst and reify variables with ukanren.reify:
let between = lo: hi: var: ukanren.constrain (state: let v = ukanren.reify state.subst var; in ukanren.isVar v || (v >= lo && v <= hi) );inukanren.chrRun 10 (q: ukanren.conj (between 3 7 q) (ukanren.disj (ukanren.eq q 2) (ukanren.disj (ukanren.eq q 5) (ukanren.eq q 9))))# => [ 5 ]