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

Ian MacLarty maclarty at csse.unimelb.edu.au
Thu Sep 21 11:14:29 AEST 2006


On Wed, Sep 20, 2006 at 07:32:31PM +1000, Zoltan Somogyi wrote:
> 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)};

I think a lot of this discussion belongs in the user guide (or at least
we should include a reference to the user guide here), since
grades and trace levels are not explained in the reference manual, but
in the user guide.

I think the reference manual should also state what trace conditions
should be supported by all implementations.  How should an
implementation deal with conditions it doesn't support?  For example
suppose someone else implements another Mercury compiler that has no
concept of grades.  Is it okay for that implementation to ignore the
grade option?  What if that implementation adds its own conditions?
Perhaps we shouldn't make unrecognised options an error, but just emit a
warning if we find unrecognised options.

It's a bit of a moot point, since there are no other Mercury compilers,
but I still think the reference manual should make clear what is part of
the Mercury language and what are specific to the Melbourne Mercury
compiler.

Ian.
--------------------------------------------------------------------------
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