demos are updated based on feedback.

a few "useful-code" functions were added and documented.

svn: r149
This commit is contained in:
Jono Spiro 2004-08-06 11:25:19 +00:00
parent 04e9cefc17
commit ffd45198fa
12 changed files with 311 additions and 201 deletions

View File

@ -1,6 +1,6 @@
;; The program being debugged (a module in "highway.ss") generates fake speed readings over and over.
#| The program being debugged (a module in "highway.ss") generates fake speed readings over and over. |#
(require (lib "animation.ss" "frtime")) ;; needed for display-shapes
(require (lib "animation.ss" "frtime")) #| needed for display-shapes |#
(define-mztake-process radar-program ("highway.ss" [values-of-speed 3 4 bind 'speed]))
@ -10,44 +10,46 @@
this is right before the program sleeps for 1 second.
* At this tracepoint, define "values-of-speed" to a FrTime eventstream that
recieves events containing a single numerical value:
- The (lexically-scoped) current value of the variables `speed' are send
every time the code at line 3, column 4, is reached.
|#
recieves events containing the current value of the variable `speed',
which are sent every time the code at line 3, column 4, is reached. |#
(printf-b "current speed: ~a" (hold values-of-speed))
;; Prints the current speed being recorded
#| Prints the current speed being recorded |#
(printf-b "last ten speeds: ~a" (history-b 10 values-of-speed))
;; prints a FIFO list of the last 10 speeds seen
#| prints a FIFO list of the last 10 speeds seen |#
(map-e (lambda (a-speed) (when (>= a-speed 55) (pause radar-program)))
values-of-speed)
;; pauses the program for inspection when a speed is too fast
#| pauses the program for inspection when a speed is too fast |#
;; produces a list of shapes to draw/animate, taking in a number for speed
#| produces a list of shapes to draw/animate, taking in a number for speed |#
(define (make-speed-gauge speed)
(let ([center (make-posn 200 200)])
(list (make-circle center 170 "black")
(make-circle center 160 "white")
(make-rect (make-posn 0 202) 1000 1000 "white")
(make-line (make-posn 30 201) (make-posn 370 201) "black")
;; draws the the half-circle guage
#| draws the the half-circle guage |#
;; draws the red line for the current speed
#| draws the red line for the current speed |#
(make-line center
(posn+ center (make-posn (- (* 150 (cos (/ speed 30))))
(- (* 150 (sin (/ speed 30))))))
"red"))))
(display-shapes (make-speed-gauge (hold values-of-speed)))
#| display-shapes takes a list of objects to draw.
(hold values-of-speed) keeps track of the current value of speed,
as seen on the eventstream, and that is passed to make-speed-guage,
which gets called every time values-of-speed gets a new speed.
|#
which gets called every time values-of-speed gets a new speed. |#
(start/resume radar-program)
;; Start the process for highway.ss
(start/resume radar-program) #| Start the process for highway.ss |#

View File

@ -3,15 +3,14 @@
anonymous locations.
We don't even need to bind any variables or add any breaks, we just
run the program and catch the exception it throws.
|#
run the program and catch the exception it throws. |#
(define-mztake-process p ("exception.ss"))
(printf-b "exception.ss exited? ~a" (process:exited? p))
;; Prints out a behavior that tells you whether the debug-process is still running...
#| Prints out a behavior that tells you whether the debug-process is still running... |#
(printf-b "last exception seen: ~a" (hold (process:exceptions p)))
;; Prints out the last exception that the program threw
#| Prints out the last exception that the program threw |#
(start/resume p)

View File

@ -6,8 +6,7 @@
and recieve different values, watching how an algorithm unfolds.
Be sure you look at first-class.ss to see where the bindings are taken from, to get
and idea of why they recieve different values from the same "x".
|#
and idea of why they recieve different values from the same "x". |#
(define-mztake-process p ("first-class.ss" [x-before-let 3 29 bind 'x]
[x-in-let 4 25 bind 'x]
@ -19,12 +18,11 @@
x-after-let)))
#| merge-e takes multiple event streams and turns them into one event stream.
count-e then counts how many pings are recieved on all three streams,
in other words, how many times "x" updates in all the traces.
|#
in other words, how many times "x" updates in all the traces. |#
(printf-b "x before let, should be (2 4 6 7): ~a" (history-b 4 x-before-let))
(printf-b "x in let, should be (6 10 14 16): ~a" (history-b 4 x-in-let))
(printf-b "x after let, should be (5 9 13 15): ~a" (history-b 4 x-after-let))
;; Prints out a FIFO list containing the last 4 values seen by each trace.
#| Prints out a FIFO list containing the last 4 values seen by each trace. |#
(start/resume p)

View File

@ -1,14 +1,22 @@
#| The program being debugged (a module in the file "montecarlo.ss") runs an infinite loop,
binding "x" and "y" to a random number between [-199,199] each iteration, and "pi"
to the value of pi as calculated using this algorithm.
#| The program being debugged (a module in the file "montecarlo.ss") runs
an infinite loop, binding "x" and "y" to a random number between
[-199,199], each iteration.
This MzTake script draws only the points that are deemed *not* within
a radius of 200 pixels from the center of the window.
|#
This is supposed to represent throwing darts at a circular dartboard.
You keep a count of how many darts you have thrown, and a side count
for each time the dart is thrown within the circle. The ratio of
hits to total tries, multiplied by 4, approaches "pi" with some error,
usually closing in around 3.13. The target program does this computation
and binds it to the variable "pi".
This MzTake script visualizes the process, drawing points (darts)
that "hit" the circle, a radius of 200 pixels from the center of
the window. |#
(require (lib "graphics.ss" "graphics"))
;; Needed for open-graphics, open-viewport, and draw-solid-ellipse
#| Needed for open-graphics, open-viewport, and draw-solid-ellipse |#
(open-graphics)
(define window (open-viewport "Debugger" 400 400))
@ -17,49 +25,47 @@
and the dots are stationary -- so we just keep drawing the circles at
the random coordinates that we get from the target program.
See the doc for more information on this kind of drawing.
|#
See the doc for more information on this kind of drawing. |#
(define-mztake-process p ("montecarlo.ss" [x/y/pi-trace 13 18 bind '(x y pi)]))
(define-mztake-process p ("montecarlo.ss" [x/y/pi-trace 13 13 bind '(x y pi)]))
#| * Create a process to debug montecarlo.ss
* Add a tracepoint at line 13, column 18; in the program,
this is right after the cond determined that the point is not in
the radius of the circle. [else ->(loop ...)]
* Add a tracepoint at line 13, column 13; in the program,
this is right after the cond determined that the point *is* within
the radius of the circle, before starting the next iteration of the loop.
* At this tracepoint, define "x/y/pi-trace" to a FrTime eventstream that
recieves events containing a list of the latest values of "x" "y" and "pi"
in a list, every time the code at line 13, column 18, is reached.
|#
in a list, every time the code at line 13, column 18, is reached. |#
(define x/y/pi (hold x/y/pi-trace))
#| The local, time-varying variable "x/y/pi" is now is a FrTime behavior that always
holds the current (latest) list of values from x/y/pi-trace.
|#
holds the current (latest) list of values from x/y/pi-trace. |#
(define x (+ 200 (first x/y/pi)))
(define y (+ 200 (second x/y/pi)))
(define current-pi (third x/y/pi))
#| The local, time-varying variables "x" "y" and "current-pi" are bound to
their respective values in the list from x/y/pi.
|#
their respective values in the list from x/y/pi. |#
(printf-b "total points chosen: ~a" (count-b x))
(printf-b "total points chosen: ~a" (count-b (changes x)))
(printf-b "current computed value of pi: ~a" current-pi)
(printf-b "log error: ~a" (log (abs (- current-pi 3.141592653)))) ;; the more negative, the better...
; more negative the better ...down to -14
(printf-b "log error: ~a" (log (abs (- current-pi 3.1415926))))
((draw-viewport window) "wheat")
((draw-solid-ellipse window) (make-posn -4 -4) 408 408 "black")
((draw-solid-ellipse window) (make-posn 0 0) 400 400 "sienna")
#| Draw the dartboard |#
(map-e (lambda (x/y) ((draw-solid-ellipse window) (make-posn (first x/y) (second x/y))
3 3 "blue"))
3 3 "black"))
(changes (list x y)))
#| Every time the list (x y) changes (x and y get a new value), take this latest list value ("==>")
and pass it to a function which draws a circle at the x,y coordinates in the list.
|#
and pass it to a function which draws a circle at the x,y coordinates in the list. |#
(start/resume p)
;; Start the process for montecarlo.ss
(start/resume p) #| Start the process for montecarlo.ss |#

View File

@ -5,10 +5,11 @@
(define (run)
(let loop ([hits 1]
[total 1])
(let* ([x (- (random 400) 200)]
[y (- (random 400) 200)]
(let* ([x (- (random 401) 200)]
[y (- (random 401) 200)]
[length (sqrt (+ (* x x) (* y y)))]
[pi (* 4. (/ hits total))])
(cond [(length . <= . 200) (loop (add1 hits) (add1 total))]
(cond [(length . < . 200)
(loop (add1 hits) (add1 total))]
[else (loop hits (add1 total))]))))
(run))

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

View File

@ -1,13 +1,38 @@
#| The program being debugged (a module in the file "random-xs.ss") runs an infinite loop,
binding "x" to a random number between [0,199] each iteration.
binding "x" to a random number between [0,100) each iteration.
This MzTake script draws a histogram of the values of x seen over time,
in sync with the execution of "random-xs.ss".
|#
in sync with the execution of "random-xs.ss". This will run until one
bar reaches the top of the screen.
This histogram provides three pieces of information:
* Each bar represents a bin, the height represents how many times
that "random" number was generated.
* The brighter the blue, the faster that bin is growing compared
to the others. The darker, the slower.
* You can see a history of speeds over time based on how the colors
change in each bin.
Try looking for small groupings of bins where all are light, or all
are dark -- these represent trends in the numbers.
Look for tortoises that stay low and black, and hares which are very
active and bright.
Notice how the bottom tends to be rather patchy with lots of color
variation (the "start-up" phase of the random number generator),
and then towards the middle of the screen, most of the blues have
settled down and evened out.
The bars drag a bit when moving upwards (the height goes up by 2, but
the redrawing of the latest color goes down 10 pixels) so that you can
spot vertical and horizontal trends more easily. |#
(require (lib "graphics.ss" "graphics")
;; Needed for open-graphics, open-viewport, and draw-solid-ellipse
#| Needed for open-graphics, open-viewport, and draw-solid-ellipse |#
(lifted mzscheme
make-hash-table
@ -15,19 +40,21 @@
hash-table-get))
#| "Lifted" is explained in FrTime's own documentation (plt/collects/frtime/doc.txt)
Quickly put, lifting extends the functions listed above so they can take FrTime time-varying
values (such as MzTake traces) as arguments.
|#
values (such as MzTake traces) as arguments. |#
(open-graphics)
(define window (open-viewport "Debugger" 600 500))
((draw-viewport window) (make-rgb 0.95 0.95 0.95))
#| This file doesn't animate a list of objects since the number of
objects quickly reaches the thousands (slowing drawing time severly),
and they are stationary -- so we just keep drawing the circles at
their new heights based on the value in the hashtable.
See the doc for more information on this kind of drawing.
|#
See the doc for more information on this kind of drawing. |#
(define-mztake-process p ("random-Xs.ss" [x-trace 4 6 bind 'x]))
#| * Create a process to debug random-xs.ss
@ -38,43 +65,48 @@
* At this tracepoint, define "x-trace" to a FrTime eventstream that
recieves events containing the latest value of "x" seen,
every time the code at line 4, column 6, is reached.
|#
(define x (hold x-trace))
#| The local, time-varying variable "x" is now is a FrTime behavior that always
holds the current (latest) value of x-trace.
|#
every time the code at line 4, column 6, is reached. |#
(define largest-bin 0)
(define valcount (make-hash-table))
;; this will hold the counts for the histogram
#| this will hold the counts for the histogram
x is the key, and the number of times x shows up is the value |#
(hold (x-trace . -=> .(printf-b "largest count: ~a" largest-bin)))
#| Prints out the largest count every time we get a new x-trace event |#
(map-e (lambda (x)
(hash-table-put! valcount x (add1 (hash-table-get valcount x (lambda () 0))))
(let* ([new-cnt (add1 (hash-table-get valcount x (lambda () 0)))]
[color (/ new-cnt (add1 largest-bin))])
(when (= largest-bin 250)
(kill p))
; when one of the bars reaches the top of the screen, kill the program.
(when (> new-cnt largest-bin) (set! largest-bin new-cnt))
; keep track of the largest count
(hash-table-put! valcount x new-cnt)
;; increment the value in the hashtable, starting from 0 if none exists.
((draw-solid-ellipse window) (make-posn (* x 3)
(- 500 (* 3 (hash-table-get valcount x (lambda () 1)))))
4 4 "blue"))
(changes x))
#| Every time the local variable x changes (x-trace gets a new value), take this latest value ("==>")
and pass it to a function which increments the count in the hashtable, and draws a circle in the window
at (* x 3) pixels from the left, and the height is (3 * the latest count in the hashtable for that x).
((draw-solid-rectangle window) (make-posn (* x 6) (- 500 (* 2 new-cnt)))
6 10 ;; width height
(make-rgb 0 (* 0.75 color) color))))
x-trace)
#| Every time x-trace gets a new value, take this latest value and pass it to a function
which increments the count in the hashtable, and draws a circle in the window at
(* x 6) pixels from the left, and the height is (2 * the latest count in the hashtable for that x),
making a color (MAKE-RGB) that is lighter based on how fast it is growing.
|#
(printf-b "x: ~a" x)
(printf-b "count: ~a" (count-e (changes x)))
#| prints the current value of x and a count of how many times x has changed,
in other words, how many values are in the histogram
(printf-b "count: ~a" (count-b x-trace))
#| prints the count of how many events x-trace got,
aka how many values are in the histogram and on the screen.
|#
(let ([cnt (count-e (changes x))])
(when (= 2000 cnt) (pause p)))
#| This binds the same type of count seen above to cnt,
when the histogram is showing 2000 values, pause the program
the next time the breakpoint is reached before doing anything else.
Then try restarting it with (start/resume p)
|#
(start/resume p)
;; Start the process for random-xs.ss

View File

@ -1,5 +1,5 @@
(module |random-Xs| mzscheme
(define (run)
(let loop ([x (random 200)])
(loop (random 200))))
(let loop ([x (random 100)])
(loop (random 100))))
(run))

View File

@ -1,62 +1,63 @@
#| The program being debugged (a module in "sine.ss") runs an infinite loop,
binding "x" to a moment in time [-200,200], and "sin-x" to the sin(x) each iteration.
binding "x" to a moment in time [-200,200], and "sin-x" to the sin(x/20) each iteration.
This MzTake script plots the value of x over time, in sync with the execution of "sine.ss".
|#
This MzTake script plots the value of x over time, in sync with the execution of "sine.ss". |#
(require (lib "animation.ss" "frtime")) ;; needed for display-shapes
(define-mztake-process p ("sine.ss" [sin/x-trace 5 8 bind '(sin-x x)]))
(define-mztake-process p ("sine.ss" [x/sinx-trace 5 8 bind '(x sin-x)]))
#| * Create a process to debug sine.ss
* Add a tracepoint at line 5, column 8; in the program,
this is right after the let values are bound, ->(if (x ...)
* At this tracepoint, define "sin/x-trace" to a FrTime eventstream that
recieves events containing a list of two elements:
- The (lexically-scoped) current values of the variables `sin-x' and `x' are
sent as a list every time the code at line 5, column 8, is reached.
|#
(printf-b "runtime elapsed: ~a" (process:runtime/seconds p))
;; Prints how long the program has been running, in seconds
* At this tracepoint, define "x/sinx-trace" to be a FrTime eventstream that
recieves events containing a list of two elements -- the current values
of the variables `x' and `sin-x', respectively. |#
(printf-b "sine.ss exited? ~a" (process:exited? p))
;; Prints out a behavior that tells you whether the mztake-process is still running...
(define x/sinx (hold x/sinx-trace))
#| the local variable "sin/x" now is a FrTime behavior that holds the current value of the list (sin-x x) |#
(define sin/x (hold sin/x-trace))
;; the local variable "sin/x" now is a FrTime behavior that holds the current value of the list (sin-x x)
(define sin-x (+ 200 (first sin/x)))
(define x (+ 200 (second sin/x)))
;; "x" and "sin-x" are the current values of (x + 200) and (sin(x) + 200)
(define x (first x/sinx))
(define sin-x (second x/sinx))
#| the local variables x, sin-x hold their current values |#
(printf-b "x: ~a" x)
(printf-b "sin(x): ~a" sin-x)
;; Print the current values of x and sin-x
(printf-b "sin(x/20): ~a" sin-x)
#| Print the current values of x and sin-x |#
(printf-b "largest x: ~a sin(x/20): ~a"
(largest-val-b (changes (first x/sinx)))
(largest-val-b (changes (second x/sinx))))
(printf-b "smallest x:~a sin(x/20):~a"
(smallest-val-b (changes (first x/sinx)))
(smallest-val-b (changes (second x/sinx))))
(display-shapes
(list* (make-line (make-posn 0 200) (make-posn 400 200) "gray")
(make-line (make-posn 200 0) (make-posn 200 400) "gray")
;; draw horizontal and vertical gray lines
#| draw horizontal and vertical gray lines |#
(let ([x (+ 200 x)]
[sin-x (+ 200 (* 100 sin-x))])
(history-b 50 (changes (make-circle
(make-posn x sin-x)
5 ; diameter
5
(if (< 200 sin-x)
(if (< 200 x) "blue" "darkblue") ; Quadrants 3 and 4
(if (< 200 x) "red" "darkred"))))))) ; 1 and 2
#| * Make a circle at position (x, sin-x) with diameter 5 pixels, and a color based on the coords.
* Everytime this value (the circle) changes (when the values of x and sin-x change)
* Keep a history (as a FIFO list) of (up to) the last 50 circles that were created.
* Pass this list to the display-shapes function, which will redraw everytime this list changes.
|#
(if (< 200 x) "blue" "darkblue") #| Quadrants 3 and 4 |#
(if (< 200 x) "red" "darkred")))))))) #| 1 and 2 |#
(start/resume p)
;; Start the process for sine.ss
#| Make a circle at position x:(x + 200) and y:(100*sin(x/20) + 200) (scaled so we can draw it on screen)
with diameter of 5 pixels, and a color based on which quadrant the coordinate is in.
Every time this value (the circle) changes (when the values of x and sin-x change):
* Keep a history (as a FIFO list) of (up to) the last 50 circles that were created.
* Pass this list to the display-shapes function, which will redraw every time this list changes. |#
(start/resume p) #| Start the process for sine.ss |#

View File

@ -1,8 +1,8 @@
(module sine mzscheme
(define (run)
(let loop ([x -200])
(let ([sin-x (* 100 (sin (/ x 20.0)))])
(if (x . <= . 200)
(let ([sin-x (sin (/ x 20.0))])
(if (x . < . 200)
(loop (add1 x))
(loop -200)))))
(run))

View File

@ -6,9 +6,10 @@
_MzTake_ is a _scripted debugger_ for PLT Scheme. It helps
programmers monitor the execution of a target program as it
unfolds (and optionally pause or resume its execution!).
In the future, MzTake will support other kinds of interactions,
such as inspecting the call stack.
unfolds (and optionally pause or resume its execution!). MzTake
gives you the power to easily write real programs that debug real
programs. You are no longer limited to a tool chest of buttons
like "add breakpoint", "step-next", "step-into", and "step-over".
MzTake scripts are written in the FrTime programming
language, which is bundled with DrScheme. FrTime supports the
@ -23,8 +24,7 @@ using callbacks). Consider a MzTake script to monitor the
behavior of the program "highway.ss", in the demos directory
of the MzTake collection:
(define-mztake-process
radar-program
(define-mztake-process radar-program
("highway.ss" [values-of-speed 3 4 bind 'speed]))
(printf-b "current speed: ~a" (hold values-of-speed))
(start/resume radar-program)
@ -136,6 +136,12 @@ You should be able to run them in DrScheme by switching to the
of DrScheme's language dialog, and then selecting "Run"
(or "Execute") from the DrScheme tool bar.
The demos are listed in order of complexity. When you open them
in DrScheme, don't let the amount of text overwhelm you -- the
scripts themselves are only a few lines of code. However, the
commenting is *exhaustive* so that a FrTime novice can still use
MzTake without ever having written a FrTime script before!
./highway/highway-test.ss - a small MzTake example, shown above
./sine/sine-test.ss - plots values extracted from the
@ -178,73 +184,96 @@ with them.
_Debugging with MzTake_
The model of the debugger is as follows:
Conceptually, MzTake is an extension of FrTime, providing
functions that execute a target program (or many!), and
"connect" to points in its code. MzTake then provides the
running FrTime script with interesting information (such as
a variable's current value) which it derives from these
"connections". FrTime then handles the rest.
FrTime takes that information and lets the script author
compute with it, verify it, print it, make visualizations
with it, anything you would like to do.
Currently, other than the powerful monitoring facilities that
MzTake provides (see BIND and ENTRY in the next section), user
interaction is limited to pausing/resuming the running program,
and operating on a few properties and predicates over general
program state (see PROCESS:EXITED?, PROCESS:RUNTIME/SECONDS,
and PROCESS:EXCEPTIONS). In the future, MzTake will offer other
types of interaction and information, such as inspecting
(and stepping through!) the call stack.
In more depth, the debugger works on a model roughly as follows:
* A single debugging script file contains all the MzTake
processes, traces, bindings, animations, and other FrTime
code fragments that do the debugging and program monitoring.
* This script file is run in the MzTake language in DrScheme.
Interaction and textual print-outs are provided in the
interaction pane.
* This script file is loaded into the Definitions window in
DrScheme, and run using the MzTake language. User interaction
with the debugger is provided through the Interactions window.
* A MzTake *process* is like an operating system that runs a group of
programs, installs hooks into them to monitor their execution,
and provides FrTime with these hooks to do computations.
* Each MzTake process is independent of the other MzTake processes.
One will not affect the other, only their traces can interact in
the script.
* Also like an operating system, each MzTake process runs
independently of all other MzTake processes; one will not affect
another. They can "interact" in the script by adding traces and
computing with those traces.
* A MzTake process accepts a number of target-files as "clients" to
debug and monitor. Each client should contain a module program,
of the form:
(module mod-nam mzscheme
(... module body ...))
(module mod-name mzscheme
... program-body ... )
MzTake does not support debugging anything other than modules.
* The first client defined for each process is *always* the main module.
That is, START/RESUME runs the *first* client module (in the same way
that you run it in DrScheme in the "module..." language), assuming there
will be side-effects that start the debugging.
* The first client defined for each MzTake process is *always* the
main ("top level") module. That is, START/RESUME runs the main
client module, in much the same way that you would run it in
DrScheme (in the "module..." language). It is assumed the module
has "side-effects" which start the target program.
The rest of the files traced in a MZTAKE-PROCESS are typically
modules used *by* the main-module, allowing you to see
what is going on deeper than the main module. For example:
The rest of the files traced in a MZTAKE-PROCESS are modules
used *by* the main module, allowing you to see what is going
on deeper than in the main-module. For example:
(define-mztake-process p1
("my-stack-tests.ss")
((lib "my-stack.ss" "my-stack") [s-push-p1 3 29 bind 'insert-value]
[s-pop-p1 10 16 bind 'return-value]))
"my-stack-tests.ss" uses functions from "my-stack.ss". You want to
make sure "my-stack.ss" is working properly in the context of
running the module in "my-stack-tests.ss" for side-effects.
"my-stack-tests.ss" is the main module. Suppose it is a test-suite
for "my-stack.ss"; the test suite asserts that the stacks are not
working as expected. You may want to use these traces to test how
"my-stack.ss" is operating "inside" during the test-suite.
Watch the pushes and pops and see how they correlate to what you expect.
* The same file can be traced differently in different processes, even with
different main clients using them:
* The same module can be traced differently for each MzTake processe.
Lets say that in the same script you want to see why the stack is using
a lot more memory than expected. You can set traces to count how many times
spaces is allocated and cleared and see if they are equal.
(define-mztake-process p2
("more-my-stack-tests.ss")
((lib "my-stack.ss" "my-stack") [s-clear-p2 22 8 ENTRY]))
("my-stack-tests.ss")
((lib "my-stack.ss" "my-stack") [s-allocates-p2 22 2 entry]
[s-clears-p2 28 2 entry]))
This installs an ENTRY trace at the function entry point for (clear).
Every time (clear) gets called, s-clear-p2 will get a ping of "#t".
This installs an ENTRY trace at the function entry point for
ALLOCATE-STACK and CLEAR-STACK in "my-stack.ss". Every time
those functions get called, these traces will send a "#t" event,
and could be counted using COUNT-E.
* Once all the processes are defined, (start/resume ...) is called on
each starting their execution.
* Once a MzTake processe is defined, and all the script code operating
on traces is defined, START/RESUME can be called on the process
to begin its execution.
* All the variables bound (MZTAKE-PROCESSes, BINDs, ENTRYs),
from all the different MZTAKE-PROCESSes, are collected together by
MzTake so they can be all be computed with using FrTime functions
and idioms.
* Processes have certain properties and predicates which you can get,
such as runtime (in seconds or milliseconds), exceptions that are thrown,
and whether the process exited yet. See "process:runtime/(milli)seconds",
"process:exceptions", and "process:exited?".
* All of the variables defined by traces (BINDs and ENTRYs on the active
MzTake processes) are available simulatenously in the script.
* Lastly, proceses can be started, paused, resumed, and terminated.
See START/RESUME, PAUSE, KILL, KILL-ALL.
@ -405,10 +434,21 @@ and can be used in the Interactions window.
_Useful Functions for Time-Varying Values_
MzTake defines a few functions on time-varying values
that are particularly useful when debugging.
Note: FrTime uss naming convention where functions which
return behaviors have names that end in "-b", and
functions that return event streams end in "-e".
MzTake defines a few functions on time-varying values
that are particularly useful when debugging:
> (history-b stream)
Keeps a complete history of all the values seen
on an event stream as a list, oldest events last.
Use with BINDs: (history-b x-trace)
> (history-b n stream)
Keeps a list of the last n values of a behavior
@ -416,21 +456,29 @@ that are particularly useful when debugging.
elements are the n last values seem on the stream,
in order, oldest first.
> (count-e stream)
> (count-b stream)
Counts number of event pings on an eventstream,
regardless of whether the value changes or not
(often used with ENTRY traces).
Counts number of events seen on an eventstream.
> (count-b b)
Often used directly on ENTRY traces, counting how many
times ENTRY occured: (count-e entry-trace)
Counts number of times a behavior's value
updates/changes (often used with BIND traces).
Also useful to count how many times a BIND changed
by calling: (count-b (changes bind-trace))
> (largest-val-b stream)
> (smallest-val-b stream)
Keeps track of the largest/smallest values seen on a stream.
Use with BINDs: (largest-val-b (changes bind-trace)).
> (sequence-match? seq evs)
Matches a sequence of items in a list to the history
of event pings, on the event stream evs.
of event pings, on the event stream evs. Returns #t
when it matches, and #f otherwise. Use when you expect
a certain pattern to show up, and want to know when:
(sequence-match? '(0 1 2 1 0) (changes bind-trace))
> (printf-b format-string arg ...)

View File

@ -6,25 +6,48 @@
(provide (all-defined))
; Everything is contracted to 'any' for speed benefits, though there is already a big performance hit
; Keeps a list of the last n values of a behavior
(define (history-b n stream)
(hold (history-e n stream) empty))
(define/contract history-b (case-> (event? . -> . any)
(number? event? . -> . any))
(case-lambda [(stream)
(define ((add-to-complete-hist x) hist) (append hist (list x)))
(accum-b (stream . ==> . add-to-complete-hist) empty)]
(define (history-e n stream)
(define ((add-to-hist thing) hist) (append (if ((length hist) . < . n) hist (rest hist)) (list thing)))
(accum-e (stream . ==> . add-to-hist) empty))
[(n stream)
(define ((add-to-short-hist x) hist) (append (if (< (length hist) n) hist (rest hist)) (list x)))
(accum-b (stream . ==> . add-to-short-hist) empty)]))
; Counts number of event pings on an eventstream
(define (count-e evs)
(accum-b (evs . -=> . add1) 0))
; Counts number of events on an event stream
(define/contract count-b (event? . -> . any)
(lambda (stream)
(accum-b (stream . -=> . add1) 0)))
; Counts number of times a behavior updates/changes
(define (count-b b)
(accum-b ((changes b) . -=> . add1) 0))
; Keeps track of the largest value seen on a stream
(define/contract largest-val-b (event? . -> . any)
(lambda (stream)
(hold (accum-e (stream
. ==> .
(lambda (last)
(lambda (x)
(if (> x last) x last))))
-inf.0))))
; Keeps track of the smallest value seen on a stream
(define/contract smallest-val-b (event? . -> . any)
(lambda (stream)
(hold (accum-e (stream
. ==> .
(lambda (last)
(lambda (x)
(if (< x last) x last))))
+inf.0))))
; Matches a sequence of items in a list to event pings
(define (sequence-match? seq evs)
(equal? seq (history-b (length seq) evs)))
(define/contract sequence-match? ((listof any?) . -> . any)
(lambda (seq evs)
(equal? seq (history-b (length seq) evs))))
; Cheap printf for behaviors
(define printf-b format)