[m-rev.] for post-commit review: document trace goals

Zoltan Somogyi zs at csse.unimelb.edu.au
Wed Sep 20 19:32:31 AEST 2006


It is for post-commit "review" because it is easier for reviewers to
actually fix English sentences than to describe how to fix them in an email.

Zoltan.

doc/reference_manual.texi:
	Document trace goals.

NEWS:
	Announce trace goals, now that they are documented.

compiler/prog_io_goal.m:
	Fix a typo in their implementation.

cvs diff: Diffing .
Index: NEWS
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/NEWS,v
retrieving revision 1.422
diff -u -b -r1.422 NEWS
--- NEWS	15 Sep 2006 09:11:22 -0000	1.422
+++ NEWS	20 Sep 2006 09:25:15 -0000
@@ -3,6 +3,8 @@
 
 Changes to the Mercury language:
 
+* We now support trace goals, which can be used to print progress messages or
+  log messages in the middle of arbitrary computations.
 * Mutables can now be marked as constant, which is useful when working with
   constant data structures that cannot be conveniently represented as constant
   terms.
@@ -30,6 +32,38 @@
 
 Changes to the Mercury language:
 
+* A new language construct allows programmers to include debugging and/or
+  logging code in the middle of arbitrary computations. Trace goals
+  may have both compile time and run time conditions placed on their execution.
+  However, if they are enabled, then they can perform I/O (even if the
+  surrounding code can't); they can also access the values of mutables.
+
+  Their capabilities, syntax and intended use are shown by the following
+  example.
+
+	:- mutable(logging_level, int, 0, ground, []).
+
+	:- pred time_consuming_task(data::in, result::out) is det.
+
+	time_consuming_task(In, Out) :-
+		trace [
+			compile_time(flag("do_logging") or grade(debug)),
+			run_time(env("VERBOSE")),
+			io(!IO),
+			state(logging_level, !LoggingLevel)
+		] (
+			io.write_string("Time_consuming_task start\n", !IO),
+			( !.LoggingLevel > 1 ->
+				io.write_string("Input is ", !IO),
+				io.write(In, !IO),
+				io.nl(!IO)
+			;
+				true
+			)
+		),
+		...
+		% perform the actual task
+
 * Unicode characters can now be encoded in string literals using an
   escape sequence.  The escape sequence \uXXXX (or \UXXXXXXXX), where XXXX
   (or XXXXXXXX) is a Unicode character code in hexadecimal, is replaced with
cvs diff: Diffing analysis
cvs diff: Diffing bindist
cvs diff: Diffing boehm_gc
cvs diff: Diffing boehm_gc/Mac_files
cvs diff: Diffing boehm_gc/cord
cvs diff: Diffing boehm_gc/cord/private
cvs diff: Diffing boehm_gc/doc
cvs diff: Diffing boehm_gc/include
cvs diff: Diffing boehm_gc/include/private
cvs diff: Diffing boehm_gc/libatomic_ops-1.2
cvs diff: Diffing boehm_gc/libatomic_ops-1.2/doc
cvs diff: Diffing boehm_gc/libatomic_ops-1.2/src
cvs diff: Diffing boehm_gc/libatomic_ops-1.2/src/atomic_ops
cvs diff: Diffing boehm_gc/libatomic_ops-1.2/src/atomic_ops/sysdeps
cvs diff: Diffing boehm_gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/gcc
cvs diff: Diffing boehm_gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/hpc
cvs diff: Diffing boehm_gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/ibmc
cvs diff: Diffing boehm_gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/icc
cvs diff: Diffing boehm_gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/msftc
cvs diff: Diffing boehm_gc/libatomic_ops-1.2/src/atomic_ops/sysdeps/sunc
cvs diff: Diffing boehm_gc/libatomic_ops-1.2/tests
cvs diff: Diffing boehm_gc/tests
cvs diff: Diffing boehm_gc/windows-untested
cvs diff: Diffing boehm_gc/windows-untested/vc60
cvs diff: Diffing boehm_gc/windows-untested/vc70
cvs diff: Diffing boehm_gc/windows-untested/vc71
cvs diff: Diffing browser
cvs diff: Diffing bytecode
cvs diff: Diffing compiler
Index: compiler/prog_io_goal.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/prog_io_goal.m,v
retrieving revision 1.47
diff -u -b -r1.47 prog_io_goal.m
--- compiler/prog_io_goal.m	5 Sep 2006 06:21:30 -0000	1.47
+++ compiler/prog_io_goal.m	20 Sep 2006 07:56:54 -0000
@@ -871,7 +871,7 @@
                         "takes just one argument",
                     MaybeCompiletime = error1([Msg - Term])
                 )
-            ; Atom = "travelevel" ->
+            ; Atom = "tracelevel" ->
                 ( SubTerms = [SubTerm] ->
                     (
                         SubTerm = term.functor(term.atom(LevelName), [], _),
cvs diff: Diffing compiler/notes
cvs diff: Diffing debian
cvs diff: Diffing debian/patches
cvs diff: Diffing deep_profiler
cvs diff: Diffing deep_profiler/notes
cvs diff: Diffing doc
Index: doc/reference_manual.texi
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/doc/reference_manual.texi,v
retrieving revision 1.366
diff -u -b -r1.366 reference_manual.texi
--- doc/reference_manual.texi	14 Aug 2006 09:09:20 -0000	1.366
+++ doc/reference_manual.texi	20 Sep 2006 09:12:39 -0000
@@ -103,6 +103,8 @@
 * C interface::       The C interface allows C code to be called
                       from Mercury code, and vice versa.
 * Impurity::          Users can write impure Mercury code.
+* Trace goals::       Trace goals allow programmers to add debugging and
+                      logging code to their programs.
 * Pragmas::           Various compiler directives, used for example to
                       control optimization.
 * Implementation-dependent extensions::       
@@ -839,6 +841,23 @@
 are not allowed to occur outside
 @code{promise_equivalent_solution_sets @var{Vars} @var{Goal}} goals.
 
+ at item @code{trace @var{Params} @var{Goal}}
+A trace goal, typically used for debugging or logging.
+ at var{Goal} must be a valid goal;
+ at var{Params} must be a valid list of trace parameters.
+Some trace parameters specify compile time or run time conditions;
+if any of these conditions are false, @var{Goal} will not be executed.
+Since in some program invocations
+ at var{Goal} may be replaced by @samp{true} in this way,
+ at var{Goal} may not bind or change the instantiation state
+of any variables it shares with the surrounding context.
+The things it may do are thus restricted to side effects;
+good programming style requires these side effects
+to not have any affect on the execution of the program itself,
+but to be confined to the provision of extra information
+for the user of the program.
+See @pxref{Trace goals} for the details.
+
 @item @code{@var{Call}}
 Any goal which does not match any of the above forms
 must be a predicate call.
@@ -9099,6 +9118,190 @@
 		impure Ys = map(ImpureFunc, Ys).
 @end example
 
+ at node Trace goals
+ at chapter Trace goals
+
+Sometimes, programmers find themselves
+needing to perform some side-effects in the middle of declarative code.
+One example is an operation that takes so long that
+users may think the program has gone into an infinite loop:
+periodically printing a progress message can give them reassurance.
+Another example is a program that is
+too long-running for its behavior to be analyzed via debuggers
+and too complex for analysis via profilers;
+a programmable logging facility generating data
+for analysis by a specially-written program may be the best option.
+However, inserting arbitrary side effects into declarative code
+is against the spirit of Mercury.
+Trace goals exist to provide a mechanism
+to code these side effects in a disciplined fashion.
+
+The format of trace goals is @code{trace @var{Params} @var{Goal}}.
+ at var{Goal} must be a valid goal;
+ at var{Params} must be a valid list of one or more trace parameters.
+The following example shows all four of the available kinds of parameters:
+ at samp{compile_time}, @samp{run_time}, @samp{io} and @samp{state}.
+(It practice, it is far more typical to have just one parameter, @samp{io}.)
+
+ at example
+:- mutable(logging_level, int, 0, ground, []).
+
+:- pred time_consuming_task(data::in, result::out) is det.
+
+time_consuming_task(In, Out) :-
+        trace [
+                compile_time(flag("do_logging") or grade(debug)),
+                run_time(env("VERBOSE")),
+                io(!IO),
+                state(logging_level, !LoggingLevel)
+        ] (
+                io.write_string("Time_consuming_task start\n", !IO),
+                ( !.LoggingLevel > 1 ->
+                        io.write_string("Input is ", !IO),
+                        io.write(In, !IO),
+                        io.nl(!IO)
+                ;
+                        true
+                )
+        ),
+        ...
+        % perform the actual task
+ at end example
+
+The @samp{compile_time} parameter says under what circumstances
+the trace goal should be included in the executable program.
+In the example, at least one of two conditions has to be true:
+either this module has to be compiled
+with the option @samp{--trace-flag=do_logging},
+or it has to be compiled in a debugging grade.
+
+In general, the single argument of the @samp{compile_time} function symbol
+is a boolean expression that may use the @samp{and} and @samp{or} operators
+to connect one or more primitive compile-time conditions.
+There are three kinds of conditions.
+The first has the form @samp{flag(@var{FlagName})},
+where @var{FlagName} is an arbitrary name picked by the programmer;
+this condition is true
+if the module is compiled with the option @samp{--trace-flag=@var{FlagName}}.
+The second has the form @samp{grade(debug)};
+this condition is true
+if the module is compiled with in a debugging grade.
+(We may support the specification of other kinds of grades in the future.)
+The third has the form @samp{tracelevel(shallow)}, or @samp{tracelevel(deep)};
+this condition is true (irrespective of grade)
+if the module is compiled with at least the specified trace level.
+
+The @samp{run_time} parameter says under what circumstances the trace goal,
+if included in the executable program, should actually be executed.
+In this case, the environment variable @samp{VERBOSE} has be to set
+when the program starts execution.
+(It doesn't matter what value it is set to.)
+
+In general, the single argument of the @samp{run_time} function symbol
+is a boolean expression that may use the @samp{and} and @samp{or} operators
+to connect one or more primitive compile-time conditions.
+There is just one condition.
+It has the form @samp{env(@var{EnvVarName})},
+this condition is true
+if the environment variable @var{EnvVarName}
+exists when the program starts execution.
+
+The @samp{compile_time} and @samp{run_time} parameters
+may not appear in the parameter list more than once;
+programmers who want more than one condition
+have to specify how (with what boolean operators)
+their values should be combined.
+However, it is ok for them not to appear in the parameter list at all.
+If there is no @samp{compile_time} parameter,
+the trace goal is always compiled into the executable;
+if there is no @samp{run_time} parameter,
+the trace goal is always executed (if it is compiled into the executable).
+
+Since the trace goal may end up
+either not compiled into the executable or just not executed,
+it cannot bind any variables that occur in the surrounding code.
+(If it were allowed to bind such variables,
+then those variables would stay unbound
+if either the compile time or the run time condition were false.)
+This greatly restricts what trace goals can do.
+
+The usual reason for including a trace goal
+in a procedure body is to perform some I/O,
+which requires access to the I/O state.
+The @samp{io} parameter supplies this access.
+Its argument must be the name of a state variable prefixed by @samp{!};
+by convention, it is usually @samp{!IO}.
+The language implementation supplies
+the initial unique value of the I/O state
+as the value of @samp{!.IO} at the start of the trace goal;
+it requires the trace goal to give back
+the final unique value of the I/O state
+as the value of @samp{!.IO} current at the end of the trace goal.
+
+Note that trace goals that wish to do I/O
+must include this parameter in their parameter list
+ at emph{even if} the surrounding code already has access to an I/O state.
+This is because otherwise,
+doing any I/O inside the trace goal
+would destroy the value of the current I/O state,
+changing the instantiation state of the variable holding it,
+and trace goals are not allowed to do that.
+
+The @samp{io} parameter may appear in the parameter list at most once,
+since it doesn't make sense to have
+two copies of the I/O state available to the trace goal.
+
+Besides doing I/O, trace goals may read and possibly write
+the values of mutable variables.
+Each mutable the trace goal wants access to should be listed
+in its own @samp{state} parameter
+(which may therefore appear in the parameter list more than once).
+Each @samp{state} parameter has two arguments:
+the first gives the name of the mutable,
+while the second must be the name of a state variable prefixed by @samp{!},
+e.g. @samp{!LoggingLevel}.
+The language implementation supplies
+the initial value of the mutable
+as the value of (in this case) @samp{!.LoggingLevel}
+at the start of the trace goal;
+at the end of the trace goal,
+it puts the value of @samp{!.LoggingLevel} current then
+back into the mutable.
+
+The intention here is that trace goals
+should be able to access mutables that give them information
+about the parameters within which they should operate.
+The ability of trace goals to actually @emph{update} the values of mutables
+is intended to allow the implementation of trace goals
+whose actions depend on the actions executed by previous trace goals.
+For example, a trace goal could test
+whether the current input value is the same as the previous input value,
+and if it is, then it can say so instead of printing the value out again.
+Another possibility is a progress message
+which is printed not for every item processed, but for every 1000th item,
+reassuring users without overwhelming them with a deluge of output.
+
+This kind of code is the @emph{only} intended use of this ability.
+Any program in which the value of a mutable set by a trace goal
+is inspected by code that is not itself within a trace goal
+is explicitly violating the intended uses of trace goals.
+Only the difficulty of implementing the required global program analysis
+prevents the language design from outlawing such programs in the first place.
+
+The compiler will not delete trace goals
+from the bodies of the procedures containing them.
+However, trace goals inside a procedure don't prevent
+calls to that procedure from being optimized away,
+if such optimization is otherwise possible.
+(There is no point in debugging or logging
+operations that don't actually occur.)
+In their effect on program optimizations,
+trace goals function as a kind of impure code,
+but one with an implicit promise_pure around the clause in which they occur.
+ at c zs: I think saying the following is more likely to confuse than enlighten:
+ at c The trace goal scope itself acts
+ at c as a promise_pure scope for any impure code inside it.
+
 @node Pragmas
 @chapter Pragmas
 
cvs diff: Diffing extras
cvs diff: Diffing extras/cgi
cvs diff: Diffing extras/complex_numbers
cvs diff: Diffing extras/complex_numbers/samples
cvs diff: Diffing extras/complex_numbers/tests
cvs diff: Diffing extras/concurrency
cvs diff: Diffing extras/curs
cvs diff: Diffing extras/curs/samples
cvs diff: Diffing extras/curses
cvs diff: Diffing extras/curses/sample
cvs diff: Diffing extras/dynamic_linking
cvs diff: Diffing extras/error
cvs diff: Diffing extras/gator
cvs diff: Diffing extras/gator/generations
cvs diff: Diffing extras/gator/generations/1
cvs diff: Diffing extras/graphics
cvs diff: Diffing extras/graphics/easyx
cvs diff: Diffing extras/graphics/easyx/samples
cvs diff: Diffing extras/graphics/mercury_glut
cvs diff: Diffing extras/graphics/mercury_opengl
cvs diff: Diffing extras/graphics/mercury_tcltk
cvs diff: Diffing extras/graphics/samples
cvs diff: Diffing extras/graphics/samples/calc
cvs diff: Diffing extras/graphics/samples/gears
cvs diff: Diffing extras/graphics/samples/maze
cvs diff: Diffing extras/graphics/samples/pent
cvs diff: Diffing extras/lazy_evaluation
cvs diff: Diffing extras/lex
cvs diff: Diffing extras/lex/samples
cvs diff: Diffing extras/lex/tests
cvs diff: Diffing extras/logged_output
cvs diff: Diffing extras/moose
cvs diff: Diffing extras/moose/samples
cvs diff: Diffing extras/moose/tests
cvs diff: Diffing extras/morphine
cvs diff: Diffing extras/morphine/non-regression-tests
cvs diff: Diffing extras/morphine/scripts
cvs diff: Diffing extras/morphine/source
cvs diff: Diffing extras/odbc
cvs diff: Diffing extras/posix
cvs diff: Diffing extras/quickcheck
cvs diff: Diffing extras/quickcheck/tutes
cvs diff: Diffing extras/references
cvs diff: Diffing extras/references/samples
cvs diff: Diffing extras/references/tests
cvs diff: Diffing extras/solver_types
cvs diff: Diffing extras/solver_types/library
cvs diff: Diffing extras/stream
cvs diff: Diffing extras/trailed_update
cvs diff: Diffing extras/trailed_update/samples
cvs diff: Diffing extras/trailed_update/tests
cvs diff: Diffing extras/windows_installer_generator
cvs diff: Diffing extras/windows_installer_generator/sample
cvs diff: Diffing extras/windows_installer_generator/sample/images
cvs diff: Diffing extras/xml
cvs diff: Diffing extras/xml/samples
cvs diff: Diffing extras/xml_stylesheets
cvs diff: Diffing java
cvs diff: Diffing java/runtime
cvs diff: Diffing library
cvs diff: Diffing mdbcomp
cvs diff: Diffing profiler
cvs diff: Diffing robdd
cvs diff: Diffing runtime
cvs diff: Diffing runtime/GETOPT
cvs diff: Diffing runtime/machdeps
cvs diff: Diffing samples
cvs diff: Diffing samples/c_interface
cvs diff: Diffing samples/c_interface/c_calls_mercury
cvs diff: Diffing samples/c_interface/cplusplus_calls_mercury
cvs diff: Diffing samples/c_interface/mercury_calls_c
cvs diff: Diffing samples/c_interface/mercury_calls_cplusplus
cvs diff: Diffing samples/c_interface/mercury_calls_fortran
cvs diff: Diffing samples/c_interface/simpler_c_calls_mercury
cvs diff: Diffing samples/c_interface/simpler_cplusplus_calls_mercury
cvs diff: Diffing samples/diff
cvs diff: Diffing samples/muz
cvs diff: Diffing samples/rot13
cvs diff: Diffing samples/solutions
cvs diff: Diffing samples/tests
cvs diff: Diffing samples/tests/c_interface
cvs diff: Diffing samples/tests/c_interface/c_calls_mercury
cvs diff: Diffing samples/tests/c_interface/cplusplus_calls_mercury
cvs diff: Diffing samples/tests/c_interface/mercury_calls_c
cvs diff: Diffing samples/tests/c_interface/mercury_calls_cplusplus
cvs diff: Diffing samples/tests/c_interface/mercury_calls_fortran
cvs diff: Diffing samples/tests/c_interface/simpler_c_calls_mercury
cvs diff: Diffing samples/tests/c_interface/simpler_cplusplus_calls_mercury
cvs diff: Diffing samples/tests/diff
cvs diff: Diffing samples/tests/muz
cvs diff: Diffing samples/tests/rot13
cvs diff: Diffing samples/tests/solutions
cvs diff: Diffing samples/tests/toplevel
cvs diff: Diffing scripts
cvs diff: Diffing slice
cvs diff: Diffing tests
cvs diff: Diffing tests/benchmarks
cvs diff: Diffing tests/debugger
cvs diff: Diffing tests/debugger/declarative
cvs diff: Diffing tests/dppd
cvs diff: Diffing tests/general
cvs diff: Diffing tests/general/accumulator
cvs diff: Diffing tests/general/string_format
cvs diff: Diffing tests/general/structure_reuse
cvs diff: Diffing tests/grade_subdirs
cvs diff: Diffing tests/hard_coded
cvs diff: Diffing tests/hard_coded/exceptions
cvs diff: Diffing tests/hard_coded/purity
cvs diff: Diffing tests/hard_coded/sub-modules
cvs diff: Diffing tests/hard_coded/typeclasses
cvs diff: Diffing tests/invalid
cvs diff: Diffing tests/invalid/purity
cvs diff: Diffing tests/misc_tests
cvs diff: Diffing tests/mmc_make
cvs diff: Diffing tests/mmc_make/lib
cvs diff: Diffing tests/par_conj
cvs diff: Diffing tests/recompilation
cvs diff: Diffing tests/tabling
cvs diff: Diffing tests/term
cvs diff: Diffing tests/trailing
cvs diff: Diffing tests/valid
cvs diff: Diffing tests/warnings
cvs diff: Diffing tools
cvs diff: Diffing trace
cvs diff: Diffing util
cvs diff: Diffing vim
cvs diff: Diffing vim/after
cvs diff: Diffing vim/ftplugin
cvs diff: Diffing vim/syntax
--------------------------------------------------------------------------
mercury-reviews mailing list
Post messages to:       mercury-reviews at csse.unimelb.edu.au
Administrative Queries: owner-mercury-reviews at csse.unimelb.edu.au
Subscriptions:          mercury-reviews-request at csse.unimelb.edu.au
--------------------------------------------------------------------------



More information about the reviews mailing list