fixed a subtle bug in annotator? in the debugger-model -- it was using eq? instead of equal?

added (though it is broken) the dijkstra demo

updated the heap.ss file for frtime -- greg needs a copy of this.

added history-e

svn: r137
This commit is contained in:
Jono Spiro 2004-08-04 10:20:23 +00:00
parent 1bf87542d9
commit 94cc1c3b72
8 changed files with 683 additions and 4 deletions

View File

@ -52,7 +52,7 @@
clients)))]
[annotate-module? (lambda (fn m)
(memf (lambda (sym) (eq? sym fn))
(memf (lambda (sym) (equal? sym fn))
all-used-module-paths))]
[annotator (lambda (fn m stx)

View File

@ -0,0 +1,49 @@
(module dijkstra-solver mzscheme
(require (lib "heap.ss" "frtime")
(lib "list.ss")
"graph.ss")
(provide (all-defined))
(define (make-node label x y weight) (vector label x y weight))
(define (node-label n) (vector-ref n 0))
(define (node-x n) (vector-ref n 1))
(define (node-y n) (vector-ref n 2))
(define (node-weight n) (vector-ref n 3))
(define (set-node-weight! n v) (vector-set! n 3 v))
(define (node< a b) (< (node-weight a) (node-weight b)))
(define (sqr x) (* x x))
(define (distance-to a b)
(sqrt (+ (sqr (- (node-x a) (node-x b)))
(sqr (- (node-y a) (node-y b))))))
(define (hash-table-pairs hash)
(hash-table-map hash (lambda (key val) (list key val))))
(define (relax backtrace heap origin dest)
(let ([candidate-weight
(+ (node-weight origin)
(distance-to origin dest))])
(when (candidate-weight . < . (node-weight dest))
(set-node-weight! dest candidate-weight)
;;(heap-resort heap dest)
(hash-table-put! backtrace dest origin))))
(define (solve graph nodes source)
(let ([backtrace (make-hash-table)]
[heap (make-heap node< eq?)])
(set-node-weight! source 0)
(for-each (lambda (node) (heap-insert heap node))
nodes)
(let loop ()
(unless (heap-empty? heap)
(let* ([node (heap-pop heap)]
[successors (graph-succs graph node)])
(for-each
(lambda (succ) (relax backtrace heap node succ))
successors))
(loop)))
(hash-table-pairs backtrace))))

View File

@ -0,0 +1,40 @@
(require "dijkstra-solver.ss"
(lib "match.ss"))
(mztake-process p
("dijkstra.ss")
((lib "heap.ss" "frtime")
[inserts 49 6 bind 'item]
[removes 67 10 bind 'result]))
(define (not-in-order e)
(filter-e
(match-lambda
[('reset _) false]
[(_ 'reset) false]
[(previous current) (> previous current)])
(history-e 2 e)))
(history-e 5 (history-e 2 (merge-e (removes . ==> . node-weight)
(inserts . -=> . 'reset))))
(define violations
(not-in-order (merge-e (removes . ==> . node-weight)
(inserts . -=> . 'reset))))
(define latest-violation (hold violations))
(define ((insert-in-model item) model) (cons item model))
(define ((remove-from-model item) model) (filter (lambda (i) (eq? i item)) model))
(define inserters (inserts . ==> . insert-in-model))
(define removers (removes . ==> . remove-from-model))
(define model (accum-b (merge-e inserters removers) empty))
(printf-b "latest-violation: ~a" latest-violation)
(printf-b "model: ~a" model)
(start/resume p)

View File

@ -0,0 +1,40 @@
(module dijkstra mzscheme
(require "dijkstra-solver.ss"
"graph.ss"
(lib "list.ss"))
(print-struct #t)
(define g (make-graph 'directed))
(define (m-node label x y) (make-node label x y +inf.0))
(define nodes
(list
(m-node 'J 200 100)
(m-node 's 100 125)
(m-node '1 150 100)
(m-node '2 150 150)
(m-node '4 250 100)
(m-node '5 300 100)
(m-node '6 300 150)))
(for-each (lambda (n) (graph-node-add! g n)) nodes)
(define (n-ref label)
(first (filter (lambda (n) (eq? label (node-label n))) nodes)))
(define edges
(list (list (n-ref 's) (n-ref '1))
(list (n-ref 's) (n-ref '2))
(list (n-ref '1) (n-ref 'J))
(list (n-ref '4) (n-ref '5))
(list (n-ref 'J) (n-ref '4))
(list (n-ref 'J) (n-ref '6))))
(for-each (lambda (e) (graph-edge-add! g (first e) (second e)))
edges)
(require (lib "pretty.ss"))
;(printf "input:~n")
;(pretty-print (graph-to-list g))
(printf "output:~n")
(print-struct #t)
(pretty-print (solve g (reverse nodes) (n-ref 's)))
)

View File

@ -0,0 +1,543 @@
;; -*- compile-command: "mzscheme -M errortrace -u graph.ss" -*-
(module graph mzscheme
(require (lib "more-useful-code.ss" "mztake" "private"))
(provide make-graph
;; --- Constructors :
graph?
graph-directed?
graph-make-similar
graph-copy
graph-add-all!
;; --- Functions on nodes:
graph-nodes
graph-nodes-size
graph-make-node!
graph-node-add!
graph-node-mem?
graph-node-set!
graph-node-remove!
graph-node-collapse!
graph-node-has-label?
graph-node-label
graph-for-each-node
graph-fold-nodes
;; --- Functions on neighbors:
graph-succs
graph-preds
graph-adjs
graph-for-each-adjs
;; --- Functions on edges:
graph-edges
graph-edges-size
graph-edge-add!
graph-edge-mem?
graph-edge-set!
graph-edge-remove!
graph-edge-has-label?
graph-edge-label
graph-for-each-edge
graph-fold-edges
;; --- Simple graph algorithms:
graph-dfs-from-node
graph-dfs-all
graph-components
graph-strongly-connected-components
graph-topological-sort
;; --- Debugging:
graph-to-list
graph-to-string
graph-test
)
(define-struct t (flags nNodes nEdges nodes successors predessessors))
;; Flags can be: 'equal 'directed 'unique-node 'unique-edge 'nodes-must-exists 'safe
;; 'safe is a short for '(unique-node unique-edge nodes-must-exists)
(define (make-graph . flags)
(let ((flag-hash (make-hash)))
(set! flags (expands-safe-flag flags))
(for-each-f flags (lambda (flag) (hash-put! flag-hash flag true)))
(if (member 'equal flags)
(make-t flag-hash 0 0 (make-hash 'equal) (make-hash 'equal) (make-hash 'equal))
(make-t flag-hash 0 0 (make-hash) (make-hash) (make-hash)))))
(define (graph? graph) (t? graph))
(define no-value (box empty))
;; Makes a hash with the same 'equal as the graph
(define (graph-make-hash graph)
(if (graph-has-flag? graph 'equal)
(make-hash 'equal)
(make-hash)))
(define (expands-safe-flag flags)
(let loop ((cur flags) (acc empty))
(cond [(empty? cur) acc]
[(eq? (first cur) 'safe) (loop (rest cur) (append '(unique-node unique-edge nodes-must-exists) flags))]
[true (loop (rest cur) (cons (first cur) acc))])))
;; Make a graph with mostly the same flags as another graph
(define (graph-make-similar graph plus-flags minus-flags)
(set! plus-flags (expands-safe-flag plus-flags))
(set! minus-flags (expands-safe-flag minus-flags))
(apply make-graph
(append plus-flags
(filter (lambda (i) (not (member i minus-flags)))
(hash-keys (t-flags graph))))))
(define (graph-copy graph)
(let* ((rtn-nodes (graph-make-hash graph))
(rtn-successors (graph-make-hash graph))
(rtn-predessessors (graph-make-hash graph))
(rtn (make-t (t-flags graph) (t-nNodes graph) (t-nEdges graph) rtn-nodes rtn-successors rtn-predessessors)))
(hash-add-all! rtn-nodes (t-nodes graph))
(hash-add-all! rtn-successors (t-successors graph))
(hash-add-all! rtn-predessessors (t-predessessors graph))
rtn))
(define (graph-add-all! dest-graph src-graph)
(graph-for-each-node
src-graph
(lambda (node)
(if (graph-node-has-label? src-graph node)
(graph-node-add! dest-graph node (graph-node-label src-graph node))
(graph-node-add! dest-graph node))))
(graph-for-each-edge
src-graph
(lambda (from to)
(if (graph-edge-has-label? src-graph from to)
(graph-edge-add! dest-graph from to (graph-edge-label src-graph from to))
(graph-edge-add! dest-graph from to)))))
(define (graph-has-flag? graph flag)
(hash-mem? (t-flags graph) flag))
(define (graph-directed? graph)
(hash-mem? (t-flags graph) 'directed))
;;; =====================================================================
;;; Nodes
(define (graph-nodes graph) (hash-keys (t-nodes graph)))
(define (graph-nodes-size graph) (t-nNodes graph))
(define graph-make-node!
(case-lambda
[(graph) (graph-make-node! graph no-value)]
[(graph val)
(let ((sym (string->symbol (string-append "node" (number->string (t-nNodes graph))))))
(graph-node-add! graph sym val)
sym)]))
;; Add a node to the graph. If the node already exists,
;; sets its label, unless the graph has the 'unique-node property,
;; in which case this will assert.
(define graph-node-add!
(case-lambda
[(graph node) (graph-node-add! graph node no-value)]
[(graph node val)
(if (hash-mem? (t-nodes graph) node)
(assert (not (graph-has-flag? graph 'unique-node)))
(begin
(set-t-nNodes! graph (+ 1 (t-nNodes graph)))
(hash-put! (t-successors graph) node (graph-make-hash graph))
(if (graph-directed? graph)
(hash-put! (t-predessessors graph) node (graph-make-hash graph)))))
(hash-put! (t-nodes graph) node val)]))
(define (graph-node-mem? graph node)
(hash-mem? (t-nodes graph) node))
(define (graph-node-set! graph node val)
(assert (hash-mem? (t-nodes graph) node))
(hash-put! (t-nodes graph) node val))
(define (graph-node-remove! graph node)
(assert (graph-node-mem? graph node))
(for-each-f (hash-get (t-successors graph) node)
(lambda (i) (graph-edge-remove! graph node i)))
(if (graph-directed? graph)
(for-each-f (hash-get (t-predessessors graph) node)
(lambda (i) (graph-edge-remove! graph i node))))
(hash-remove! (t-nodes graph) node)
(hash-remove! (t-successors graph) node)
(if (graph-directed? graph)
(hash-remove! (t-predessessors graph) node))
(set-t-nNodes! graph (- (t-nNodes graph) 1)))
(define graph-node-collapse!
(case-lambda
[(graph node with-self-loop) (graph-node-collapse! graph node with-self-loop (lambda (pred-label succ-label) no-value))]
[(graph node with-self-loop label-fn)
(let ((is-directed (graph-directed? graph)))
(for-each-f
(if is-directed
(hash-get (t-predessessors graph) node)
(hash-get (t-successors graph) node))
(lambda (pred)
(for-each-f
(hash-get (t-successors graph) node)
(lambda (succ)
(unless (or (and (not is-directed) (eq? pred succ))
(graph-edge-mem? graph pred succ))
(let* ((label-pred (hash-get (hash-get (t-successors graph) pred) node))
(label-succ (hash-get (hash-get (t-successors graph) node) succ))
(new-label (label-fn (if (eq? label-pred no-value) false label-pred)
(if (eq? label-succ no-value) false label-succ))))
(when (or with-self-loop (not (eq? pred succ)))
(hash-put! (hash-get (t-successors graph) pred) succ new-label)
(if is-directed
(hash-put! (hash-get (t-predessessors graph) succ) pred new-label)
(hash-put! (hash-get (t-successors graph) succ) pred new-label))))))))))
(graph-node-remove! graph node)]))
(define (graph-node-has-label? graph node)
(not (eq? (hash-get (t-nodes graph) node) no-value)))
(define (graph-node-label graph node)
(let ((r (hash-get (t-nodes graph) node)))
(if (eq? r no-value) (error "graph-node-label: no value for node" node)
r)))
(define (graph-succs graph node)
(assert (graph-directed? graph))
(hash-keys (hash-get (t-successors graph) node)))
(define (graph-preds graph node)
(assert (graph-directed? graph))
(hash-keys (hash-get (t-predessessors graph) node)))
(define (graph-adjs graph node)
(if (graph-directed? graph)
(append (hash-keys (hash-get (t-successors graph) node))
(hash-keys (hash-get (t-predessessors graph) node)))
(hash-keys (hash-get (t-successors graph) node))))
(define (graph-for-each-adjs graph node fn)
(for-each (lambda (succ) (fn node succ))
(hash-get (t-successors graph) node))
(when (graph-directed? graph)
(for-each (lambda (pred) (fn pred node))
(hash-get (t-predessessors graph) node))))
(define (graph-for-each-node graph fn)
(for-each-f (t-nodes graph) fn))
(define (graph-fold-nodes graph init fn)
(let ((acc init))
(graph-for-each-node
graph
(lambda (node) (set! acc (fn node acc))))
acc))
;;; =====================================================================
;;; Edges
(define (graph-edges graph)
(let ((rtn empty))
(graph-for-each-edge graph (lambda (from to) (set! rtn (cons from to))))
rtn))
(define (graph-edges-size graph) (t-nEdges graph))
;; Add an edge to the graph. If the edge already exists,
;; sets its label, unless the graph has the 'unique-edge property,
;; in which case this will assert.
(define graph-edge-add!
(case-lambda
[(graph from to) (graph-edge-add! graph from to no-value)]
[(graph from to val)
(if (graph-edge-mem? graph from to)
(assert (not (graph-has-flag? graph 'unique-edge)))
(set-t-nEdges! graph (+ (t-nEdges graph) 1)))
(if (graph-has-flag? graph 'nodes-must-exists)
(assert (and (graph-node-mem? graph from) (graph-node-mem? graph to)))
(begin (if (not (graph-node-mem? graph from)) (graph-node-add! graph from))
(if (not (graph-node-mem? graph to)) (graph-node-add! graph to))))
(hash-put! (hash-get (t-successors graph) from) to val)
(if (graph-directed? graph)
(hash-put! (hash-get (t-predessessors graph) to) from val)
(hash-put! (hash-get (t-successors graph) to) from val))]))
(define (graph-edge-mem? graph from to)
(if (graph-has-flag? graph 'nodes-must-exists)
(assert (and (graph-node-mem? graph from)
(graph-node-mem? graph to))))
(and (hash-mem? (t-successors graph) from)
(hash-mem? (hash-get (t-successors graph) from) to)))
(define (graph-edge-set! graph from to val)
(assert (graph-edge-mem? graph from to))
(hash-put! (hash-get (t-successors graph) from) to val)
(if (graph-directed? graph)
(hash-put! (hash-get (t-predessessors graph) to) from val)
(hash-put! (hash-get (t-successors graph) to) from val)))
(define (graph-edge-remove! graph from to)
(assert (graph-edge-mem? graph from to))
(hash-remove! (hash-get (t-successors graph) from) to)
(if (graph-directed? graph)
(hash-remove! (hash-get (t-predessessors graph) to) from)
(hash-remove! (hash-get (t-successors graph) to) from)))
(define (graph-edge-has-label? graph from to)
(not (eq? (hash-get (hash-get (t-successors graph) from) to) no-value)))
(define (graph-edge-label graph from to)
(let ((r (hash-get (hash-get (t-successors graph) from) to)))
(if (eq? r no-value) (error "graph-edge-label: no value for edge" (cons from to)))
r))
(define (graph-for-each-edge graph fn)
(graph-for-each-node
graph
(lambda (from)
(for-each-f (hash-get (t-successors graph) from)
(lambda (to) (fn from to))))))
(define (graph-fold-edges graph init fn)
(let ((acc init))
(graph-for-each-edge
graph
(lambda (from to) (set! acc (fn from to acc))))
acc))
;;; =====================================================================
;;; Algos
(define (graph-dfs-from-node-with-log graph node dealt-with pre-fn post-fn backward)
(assert (or (not backward) (graph-directed? graph)))
(if (not (hash-mem? dealt-with node))
(begin (hash-put! dealt-with node true)
(pre-fn node)
(for-each-f (if backward
(hash-get (t-predessessors graph) node)
(hash-get (t-successors graph) node))
(lambda (n) (graph-dfs-from-node-with-log graph n dealt-with pre-fn post-fn backward)))
(post-fn node))))
(define graph-dfs-from-node
(case-lambda
[(graph node pre-fn) (graph-dfs-from-node graph node pre-fn (lambda (i) i))]
[(graph node pre-fn post-fn)
(graph-dfs-from-node-with-log graph node (graph-make-hash graph) pre-fn post-fn false)]))
(define graph-dfs-all
(case-lambda
[(graph pre-fn) (graph-dfs-all graph pre-fn (lambda (i) i))]
[(graph pre-fn post-fn)
(let ((dealt-with (graph-make-hash graph)))
(graph-for-each-node graph (lambda (n) (if (not (hash-mem? dealt-with n))
(graph-dfs-from-node-with-log graph n dealt-with pre-fn post-fn false)))))]))
(define (graph-components graph)
(let ((dealt-with (graph-make-hash graph)))
(graph-fold-nodes
graph
empty
(lambda (node acc)
(if (hash-mem? dealt-with node) acc
(let ((cur-component
(let loop ((cur node) (acc empty))
(if (hash-mem? dealt-with cur) acc
(begin (hash-put! dealt-with cur true)
(foldl (lambda (adj acc) (loop adj acc)) (cons cur acc)
(graph-adjs graph cur)))))))
(cons cur-component acc)))))))
(define (graph-strongly-connected-components graph)
(assert (graph-directed? graph))
(let ((finish-times empty)
(dealt-with (graph-make-hash graph)))
(graph-for-each-node
graph
(lambda (n) (graph-dfs-from-node-with-log
graph n dealt-with
(lambda (i) i)
(lambda (i) (set! finish-times (cons i finish-times)))
false)))
(set! dealt-with (graph-make-hash graph))
(let ((component-graph (graph-make-similar graph empty '(safe equal)))
(node2supernode (make-hash)))
(for-each-f
finish-times
(lambda (n)
(if (not (hash-mem? dealt-with n))
(let ((super-node (graph-make-node! component-graph empty)))
(graph-dfs-from-node-with-log
graph n dealt-with
(lambda (i)
(graph-node-set! component-graph super-node (cons i (graph-node-label component-graph super-node)))
(hash-put! node2supernode i super-node))
(lambda (i) i)
true)))))
(graph-for-each-edge graph
(lambda (from to)
(graph-edge-add! component-graph
(hash-get node2supernode from)
(hash-get node2supernode to))))
(cons component-graph node2supernode))))
(define (graph-topological-sort graph)
(assert (graph-directed? graph))
(let ((rtn empty))
(graph-dfs-all graph (lambda (i) i) (lambda (node) (set! rtn (cons node rtn))))
rtn))
;;; =====================================================================
;;; Utils
(define graph-to-list
(case-lambda
[(graph) (graph-to-list graph false)]
[(graph with-labels)
(hash-map (t-nodes graph)
(lambda (node node-val)
(let ((node-rep (if (and with-labels (graph-node-has-label? graph node))
(cons node (graph-node-label graph node))
node)))
(cons node-rep
(hash-fold (hash-get (t-successors graph) node) empty
(lambda (succ edge-val acc)
(if (and with-labels (graph-edge-has-label? graph node succ))
(cons (cons succ (graph-edge-label graph node succ)) acc)
(cons succ acc))))))))]))
(define (graph-to-string-prv graph with-labels to-string)
(let ([the-to-string (or to-string
(lambda (item) (format "~a" item)))])
(string-append (if (graph-directed? graph) "[di-graph: " "[undirected-graph:")
(the-to-string (map (lambda (n)
(cons (first n) (cons '--> (rest n))))
(graph-to-list graph with-labels)))
"]")))
(define (graph-to-string graph . to-string)
(graph-to-string-prv graph false (if (empty? to-string) false (first to-string))))
(define (graph-to-string-with-labels graph . to-string)
(graph-to-string-prv graph true (if (empty? to-string) true (first to-string))))
(define to-string-f (make-to-string `((,t? ,graph-to-string))))
(define debug-f (make-debug to-string-f))
(define for-each-f (make-for-each))
;;; =====================================================================
;;; Tests
(define (graph-test)
(define graph (make-graph 'safe 'directed))
(graph-node-add! graph 'a)
(graph-node-add! graph 'b 2)
(graph-node-add! graph 'c 3)
(graph-node-add! graph 'd)
(graph-edge-add! graph 'a 'c)
(graph-edge-add! graph 'a 'd "asd")
(graph-edge-add! graph 'b 'c "dfg")
(graph-edge-add! graph 'b 'd)
(graph-edge-add! graph 'd 'a)
(display (graph-node-mem? graph 'a))
(display (graph-edge-mem? graph 'a 'c))
(newline)
(display (graph-node-mem? graph 'v))
(display (graph-edge-mem? graph 'c 'a))
(display (graph-edge-mem? graph 'a 'b))
(newline)
(debug-f (graph-to-list graph true))
(graph-for-each-edge graph (lambda (a b) (debug-f "A " a b)))
(graph-dfs-from-node graph 'a (lambda (i) (display i)))
(newline)
(graph-dfs-from-node graph 'b (lambda (i) (display i)))
(newline)
(graph-dfs-from-node graph 'c (lambda (i) (display i)))
(newline)
(graph-dfs-from-node graph 'd (lambda (i) (display i)))
(newline)
(let ((star (make-graph 'directed)))
(graph-edge-add! star 1 'x)
(graph-edge-add! star 'x 1)
(graph-edge-add! star 2 'x)
(graph-edge-add! star 'x 3)
(graph-edge-add! star 'x 4)
(graph-edge-add! star 'x 5)
(graph-node-collapse! star 'x false)
(debug-f "collapsed:" (graph-to-list star)))
(let ((strong-graph (make-graph 'directed)))
(graph-edge-add! strong-graph 'e 'a)
(graph-edge-add! strong-graph 'a 'b)
(graph-edge-add! strong-graph 'b 'e)
(graph-edge-add! strong-graph 'e 'f)
(graph-edge-add! strong-graph 'b 'f)
(graph-edge-add! strong-graph 'b 'c)
(graph-edge-add! strong-graph 'f 'g)
(graph-edge-add! strong-graph 'g 'f)
(graph-edge-add! strong-graph 'c 'g)
(graph-edge-add! strong-graph 'c 'd)
(graph-edge-add! strong-graph 'd 'c)
(graph-edge-add! strong-graph 'g 'h)
(graph-edge-add! strong-graph 'd 'h)
(graph-edge-add! strong-graph 'h 'h)
(graph-edge-add! strong-graph 'xa 'xb)
(graph-edge-add! strong-graph 'xb 'xc)
(graph-edge-add! strong-graph 'xc 'xa)
(debug-f "strong-graph" strong-graph)
(debug-f "component" (graph-components strong-graph))
(let ((components (graph-strongly-connected-components strong-graph)))
(debug-f "strong-components" components)
(debug-f "toposort" (graph-topological-sort (first components)))))
(let ((u-graph (make-graph)))
(graph-edge-add! u-graph 'a 'b)
(graph-edge-add! u-graph 'b 'c)
(graph-edge-add! u-graph 'c 'd)
(graph-edge-add! u-graph 'd 'a)
(graph-edge-add! u-graph 'd 'e)
(graph-edge-add! u-graph 'e 'c)
(graph-edge-add! u-graph 'xa 'xb)
(graph-edge-add! u-graph 'xa 'xc)
(graph-edge-add! u-graph 'xb 'xd)
(newline)
(debug-f "u-graph" u-graph)
(graph-edge-remove! u-graph 'b 'a)
(graph-node-remove! u-graph 'd)
(debug-f "u-graph" u-graph)
(debug-f "component" (graph-components u-graph)))
)
;(graph-test)
)

View File

@ -77,11 +77,15 @@ different uses of MzTake. You should be able to run
them in DrScheme by switching to the MzTake language
and clicking the "Run" button.
demos/highway/highway-test.ss - small MzTake example used above
demos/highway/highway-test.ss - a small MzTake example, used above
demos/sine/sine-test.ss - plots values extracted from the
running program
demos/djikstra/dijkstra-test.ss - debugs a buggy implementation of
Dijkstra's algorithm
demos/montecarlo/montecarlo-test.ss - visualizes Monte Carlo integration
used to derive the value of pi

View File

@ -337,7 +337,7 @@ TESTING/CAPABILITIES------------------------------------------------------------
(thread-wait (thread (lambda () (run))))
; program terminates
(stop process)
(print-info (format "process terminated: ~a" (main-client-name process))))))
(print-info (format "process exited normally: ~a" (main-client-name process))))))
; predicate - is the debugee supposed to be running now?

View File

@ -8,8 +8,11 @@
; Keeps a list of the last n values of a behavior
(define (history-b n stream)
(hold (history-e n stream) empty))
(define (history-e n stream)
(define ((add-to-hist thing) hist) (append (if ((length hist) . < . n) hist (rest hist)) (list thing)))
(accum-b (stream . ==> . add-to-hist) empty))
(accum-e (stream . ==> . add-to-hist) empty))
; Counts number of event pings on an eventstream
(define (count-e evs)