;; lib/minikanren/relations.sx — Phase 4 standard relations. ;; ;; Programs use native SX lists as data. Relations decompose lists via the ;; tagged cons-cell shape `(:cons h t)` because SX has no improper pairs; ;; the unifier treats `(:cons h t)` and the native list `(h . t)` as ;; equivalent, and `mk-walk*` flattens cons cells back to flat lists for ;; reification. ;; --- pair / list shape relations --- (define nullo (fn (l) (== l (list)))) (define pairo (fn (p) (fresh (a d) (== p (mk-cons a d))))) (define caro (fn (p a) (fresh (d) (== p (mk-cons a d))))) (define cdro (fn (p d) (fresh (a) (== p (mk-cons a d))))) (define conso (fn (a d p) (== p (mk-cons a d)))) (define firsto caro) (define resto cdro) (define listo (fn (l) (conde ((nullo l)) ((fresh (a d) (conso a d l) (listo d)))))) ;; --- appendo: the canary --- ;; ;; (appendo l s ls) — `ls` is the concatenation of `l` and `s`. ;; Runs forwards (l, s known → ls), backwards (ls known → all (l, s) pairs), ;; and bidirectionally (mix of bound + unbound). (define appendo (fn (l s ls) (conde ((nullo l) (== s ls)) ((fresh (a d res) (conso a d l) (conso a res ls) (appendo d s res)))))) ;; --- membero --- ;; (membero x l) — x appears (at least once) in l. (define appendo3 (fn (l1 l2 l3 result) (fresh (l12) (appendo l1 l2 l12) (appendo l12 l3 result)))) (define partitiono (fn (pred l yes no) (conde ((nullo l) (nullo yes) (nullo no)) ((fresh (a d y-rest n-rest) (conso a d l) (conde ((pred a) (conso a y-rest yes) (== no n-rest) (partitiono pred d y-rest n-rest)) ((nafc (pred a)) (== yes y-rest) (conso a n-rest no) (partitiono pred d y-rest n-rest)))))))) (define foldr-o (fn (rel l acc result) (conde ((nullo l) (== result acc)) ((fresh (a d r-rest) (conso a d l) (foldr-o rel d acc r-rest) (rel a r-rest result)))))) (define foldl-o (fn (rel l acc result) (conde ((nullo l) (== result acc)) ((fresh (a d new-acc) (conso a d l) (rel acc a new-acc) (foldl-o rel d new-acc result)))))) (define flat-mapo (fn (rel l result) (conde ((nullo l) (nullo result)) ((fresh (a d a-result rest-result) (conso a d l) (rel a a-result) (flat-mapo rel d rest-result) (appendo a-result rest-result result)))))) (define nub-o (fn (l result) (conde ((nullo l) (nullo result)) ((fresh (a d r-rest) (conso a d l) (conde ((membero a d) (nub-o d result)) ((nafc (membero a d)) (conso a r-rest result) (nub-o d r-rest)))))))) (define take-while-o (fn (pred l result) (conde ((nullo l) (nullo result)) ((fresh (a d r-rest) (conso a d l) (conde ((pred a) (conso a r-rest result) (take-while-o pred d r-rest)) ((nafc (pred a)) (== result (list))))))))) (define drop-while-o (fn (pred l result) (conde ((nullo l) (nullo result)) ((fresh (a d) (conso a d l) (conde ((pred a) (drop-while-o pred d result)) ((nafc (pred a)) (== result l)))))))) (define membero (fn (x l) (conde ((fresh (d) (conso x d l))) ((fresh (a d) (conso a d l) (membero x d)))))) (define not-membero (fn (x l) (conde ((nullo l)) ((fresh (a d) (conso a d l) (nafc (== a x)) (not-membero x d)))))) (define subseto (fn (l1 l2) (conde ((nullo l1)) ((fresh (a d) (conso a d l1) (membero a l2) (subseto d l2)))))) (define reverseo (fn (l r) (conde ((nullo l) (nullo r)) ((fresh (a d res-rev) (conso a d l) (reverseo d res-rev) (appendo res-rev (list a) r)))))) (define rev-acco (fn (l acc result) (conde ((nullo l) (== result acc)) ((fresh (a d acc-prime) (conso a d l) (conso a acc acc-prime) (rev-acco d acc-prime result)))))) (define rev-2o (fn (l result) (rev-acco l (list) result))) (define palindromeo (fn (l) (fresh (rev) (reverseo l rev) (== l rev)))) (define prefixo (fn (p l) (fresh (rest) (appendo p rest l)))) (define suffixo (fn (s l) (fresh (front) (appendo front s l)))) (define subo (fn (s l) (fresh (front-and-s back front) (appendo front-and-s back l) (appendo front s front-and-s)))) (define selecto (fn (x rest l) (conde ((conso x rest l)) ((fresh (a d r) (conso a d l) (conso a r rest) (selecto x r d)))))) (define lengtho (fn (l n) (conde ((nullo l) (== n :z)) ((fresh (a d n-1) (conso a d l) (== n (list :s n-1)) (lengtho d n-1)))))) (define inserto (fn (a l p) (conde ((conso a l p)) ((fresh (h t pt) (conso h t l) (conso h pt p) (inserto a t pt)))))) (define permuteo (fn (l p) (conde ((nullo l) (nullo p)) ((fresh (a d perm-d) (conso a d l) (permuteo d perm-d) (inserto a perm-d p)))))) (define flatteno (fn (tree flat) (conde ((nullo tree) (nullo flat)) ((pairo tree) (fresh (h t hf tf) (conso h t tree) (flatteno h hf) (flatteno t tf) (appendo hf tf flat))) ((nafc (nullo tree)) (nafc (pairo tree)) (== flat (list tree)))))) (define rembero (fn (x l out) (conde ((nullo l) (nullo out)) ((fresh (a d) (conso a d l) (== a x) (== out d))) ((fresh (a d res) (conso a d l) (nafc (== a x)) (conso a res out) (rembero x d res)))))) (define removeo-allo (fn (x l result) (conde ((nullo l) (nullo result)) ((fresh (a d) (conso a d l) (== a x) (removeo-allo x d result))) ((fresh (a d r-rest) (conso a d l) (nafc (== a x)) (conso a r-rest result) (removeo-allo x d r-rest)))))) (define assoco (fn (key pairs val) (fresh (rest) (conde ((conso (list key val) rest pairs)) ((fresh (other) (conso other rest pairs) (assoco key rest val))))))) (define nth-o (fn (n l elem) (conde ((== n :z) (fresh (d) (conso elem d l))) ((fresh (n-1 a d) (== n (list :s n-1)) (conso a d l) (nth-o n-1 d elem)))))) (define samelengtho (fn (l1 l2) (conde ((nullo l1) (nullo l2)) ((fresh (a d a-prime d-prime) (conso a d l1) (conso a-prime d-prime l2) (samelengtho d d-prime)))))) (define mapo (fn (rel l1 l2) (conde ((nullo l1) (nullo l2)) ((fresh (a d a-prime d-prime) (conso a d l1) (conso a-prime d-prime l2) (rel a a-prime) (mapo rel d d-prime)))))) (define iterate-no (fn (rel n x result) (conde ((== n :z) (== result x)) ((fresh (n-1 mid) (== n (list :s n-1)) (rel x mid) (iterate-no rel n-1 mid result)))))) (define pairlisto (fn (l1 l2 pairs) (conde ((nullo l1) (nullo l2) (nullo pairs)) ((fresh (a1 d1 a2 d2 d-pairs) (conso a1 d1 l1) (conso a2 d2 l2) (conso (list a1 a2) d-pairs pairs) (pairlisto d1 d2 d-pairs)))))) (define zip-with-o (fn (rel l1 l2 result) (conde ((nullo l1) (nullo l2) (nullo result)) ((fresh (a1 d1 a2 d2 a-result d-result) (conso a1 d1 l1) (conso a2 d2 l2) (rel a1 a2 a-result) (conso a-result d-result result) (zip-with-o rel d1 d2 d-result)))))) (define swap-firsto (fn (l result) (fresh (a b rest mid-l mid-r) (conso a mid-l l) (conso b rest mid-l) (conso b mid-r result) (conso a rest mid-r)))) (define everyo (fn (rel l) (conde ((nullo l)) ((fresh (a d) (conso a d l) (rel a) (everyo rel d)))))) (define someo (fn (rel l) (conde ((fresh (a d) (conso a d l) (rel a))) ((fresh (a d) (conso a d l) (someo rel d)))))) (define lasto (fn (l x) (conde ((conso x (list) l)) ((fresh (a d) (conso a d l) (lasto d x)))))) (define init-o (fn (l init) (conde ((fresh (x) (conso x (list) l) (== init (list)))) ((fresh (a d d-init) (conso a d l) (conso a d-init init) (init-o d d-init)))))) (define tako (fn (n l prefix) (conde ((== n :z) (== prefix (list))) ((fresh (n-1 a d p-rest) (== n (list :s n-1)) (conso a d l) (conso a p-rest prefix) (tako n-1 d p-rest)))))) (define dropo (fn (n l suffix) (conde ((== n :z) (== suffix l)) ((fresh (n-1 a d) (== n (list :s n-1)) (conso a d l) (dropo n-1 d suffix)))))) (define repeato (fn (x n result) (conde ((== n :z) (== result (list))) ((fresh (n-1 r-rest) (== n (list :s n-1)) (conso x r-rest result) (repeato x n-1 r-rest)))))) (define concato (fn (lists result) (conde ((nullo lists) (nullo result)) ((fresh (h t r-rest) (conso h t lists) (appendo h r-rest result) (concato t r-rest))))))