; feed/thread — conversation threading. A reply carries :reply-to ; (normalize preserves it). A thread is the transitive closure over :reply-to from ; a root object: root + replies + replies-to-replies, gathered chronologically. ; ; Requires: lib/feed/normalize.sx, lib/feed/stream.sx, lib/feed/fanout.sx ; (feed/-elem?, feed/-distinct). ; direct replies to an object (define feed/replies (fn (stream object) (feed/filter stream (fn (a) (equal? (get a :reply-to) object))))) (define feed/reply-count (fn (stream object) (feed/count (feed/replies stream object)))) ; iterate f from x until the result stops growing (set-closure fixpoint) (define feed/-fixpoint (fn (f x) (let ((nx (f x))) (if (= (len nx) (len x)) x (feed/-fixpoint f nx))))) ; the set of object-ids in the thread rooted at `root` (define feed/thread-objects (fn (stream root) (let ((all (feed/items stream))) (feed/-fixpoint (fn (acc) (feed/-distinct (append acc (map (fn (a) (get a :object)) (filter (fn (a) (feed/-elem? (get a :reply-to) acc)) all))))) (list root))))) ; the full thread as a chronological stream (root + all descendants) (define feed/thread (fn (stream root) (let ((objs (feed/thread-objects stream root))) (feed/sort-by-at (feed/filter stream (fn (a) (feed/-elem? (get a :object) objs))))))) ; how many activities are in the thread (root counts as 1) (define feed/thread-size (fn (stream root) (feed/count (feed/thread stream root))))