[m-rev.] for review: improvementstopprintinterface

Ralph Becket rafe at cs.mu.OZ.AU
Thu May 9 12:56:01 AEST 2002


Mark Brown, Thursday,  9 May 2002:
> 
> This changes to the code are fine.  However, I have a few suggestions
> for the documentation:
> 	- It would probably be good to change the examples at the top
> 	  of the module to use the new parts of the interface.

Done.

> 	- You might also document the addition of the typeclass in the
> 	  "changes" part of the documentation.

I've added

* We have added the type class `pprint__doc/1' and a new concatenation
  operator, `++/2', which should make it easier to construct doc values.

to the "Changes to the Mercury standard library" section of the NEWS
file.

> 	- Is there an expectation that users would usually add all the
> 	  types they wish to print as instances of the typeclass?  This
> 	  would be good, because they could then write a function that
> 	  converts, say, map(K, V) into doc where K and V are constrained
> 	  by doc, without necessarily resorting to the generic to_doc
> 	  function.  You could then make map/2 an instance of doc.  If
> 	  this is the expectation, then I suggest adding examples of this
> 	  to the documentation.

Unfortunately, until we can check at run-time whether a type is an
instance of a particular type class, to_doc will still have to do
dynamic type casts on the set of special cases (maps, arrays, lists
etc.)

This also means that the special case conversions have to call the
generic to_doc on their arguments.

I've made the code parametric on the doc/1 type class in a few more
places, as well.  Here's the relative diff:


diff -u pprint.m pprint.m
--- pprint.m	6 May 2002 02:17:58 -0000
+++ pprint.m	9 May 2002 02:51:00 -0000
@@ -89,32 +89,35 @@
 % EXAMPLES
 % --------
 %
+% The doc/1 type class has types string, char, int, float and doc as
+% instances.  Hence these types can all be converted to docs by
+% applying doc/1.  This happens automatically to the arguments of ++/2.
+% Users may find it convenient to add other types as instances of the
+% doc/1 type class.
+%
 % Below are some docs followed by the ways they might be
 % displayed by the pretty printer given various line widths.
 %
-% 1. text("Hello ") `<>` line `<>` text("world")
+% 1. "Hello " ++ line ++ "world"
 % 
 %   Hello
 %   world
 %
-% 2. group(text("Hello ") `<>` line `<>` text("world"))
+% 2. group("Hello " ++ line ++ "world")
 %
 %   Hello world
 %
 %   Hello
 %   world
 %
-% 3. group(text("Hello ") `<>` nest(3, line `<>` text("world")))
+% 3. group("Hello " ++ nest(3, line ++ "world"))
 %
 %   Hello world
 %
 %   Hello
 %      world
 %
-% 4. group(
-%   text("Goodbye ") `<>`
-%   nest(3, line `<>` text("cruel ") `<>` line `<>` text("world")
-% )
+% 4. group("Goodbye " ++ nest(3, line ++ "cruel " ++ line ++ "world")
 %
 %   Goodbye cruel world
 %
@@ -122,12 +125,7 @@
 %      cruel
 %      world
 %
-% 5. group(
-%   text("Goodbye ") `<>`
-%   nest(3, line `<>`
-%     group(text("cruel ") `<>` line `<>` text("world"))
-%   )
-% )
+% 5. group("Goodbye " ++ nest(3, line ++ group("cruel " ++ line ++ "world")))
 %
 %   Goodbye cruel world
 %
@@ -138,15 +136,9 @@
 %      cruel
 %      world
 %
-% 6. label("Look! ",
-%   line `<>`
-%   group(
-%     text("Goodbye ") `<>`
-%     nest(3, line `<>`
-%       group(text("cruel ") `<>` line `<>` text("world"))
-%     )
-%   )
-% )
+% 6. label("Look! ", line ++
+%                    group("Goodbye " ++
+%                          nest(3, line ++ group("cruel " ++ line ++ "world"))))
 %
 %   Look! Goodbye cruel world
 %
@@ -172,13 +164,33 @@
 
     % This typeclass can be used to simplify the construction of docs.
     %
-:- typeclass doc(T) where [ func doc(T) = doc ].
+:- typeclass doc(T) where [
+
+        % Convert a T do a doc, placing a limit on how much of the
+        % term will be fully converted as follows:
+        %
+        % doc(_, f         ) = f
+        % doc(N, f(A, B, C)) = f/3 if N =< 0
+        % doc(N, f(A, B, C)) = some representation of the term whereby
+        %   A is converted as doc(N - 1, A),
+        %   B is converted as doc(N - 2, B), and
+        %   C is converted as doc(N - 3, C)
+        %   - if there are more than N arguments, the N+1th and subsequent
+        %     arguments should be replaced with a single ellipsis.
+        %
+    func doc(int, T) = doc
+].
+
 :- instance doc(doc).
 :- instance doc(string).
 :- instance doc(int).
 :- instance doc(float).
 :- instance doc(char).
 
+    % Fully convert an instance of doc/1.
+    %
+:- func doc(T) = doc <= (doc(T)).
+
     % An alternative to the <>/2 concatenation operator that works
     % on members of the doc/1 typeclass.
     %
@@ -190,10 +202,17 @@
 
     % The document consisting of a single string.
     %
+    % NOTE: since string is now an instance of the doc/1
+    % type class, it is simpler to just apply the doc/1
+    % method.
+    %
 :- func text(string)        = doc.
 
     % The composition of two docs with no intervening space.
     %
+    % NOTE: with the addition of the doc/1 type class, it is
+    % simpler to construct compound docs using ++/2.
+    %
 :- func doc `<>` doc        = doc.
 
     % The new-line document.  In a group doc (see below) the
@@ -207,13 +226,13 @@
     % by the pretty printer are followed by the given number
     % of spaces (nested `nest's add up).
     %
-:- func nest(int, doc)      = doc.
+:- func nest(int, T)        = doc <= (doc(T)).
 
     % Identical to a nest doc except that indentation is
     % extended with a string label rather than some number
     % of spaces.
     %
-:- func label(string, doc)  = doc.
+:- func label(string, T)    = doc <= (doc(T)).
 
     % A group doc gives the pretty printer a choice: if
     % the doc can be printed without line wrapping then
@@ -222,20 +241,24 @@
     % the pretty printer treats the group body literally,
     % although nested group docs remain as choice points.
     %
-:- func group(doc)          = doc.
+:- func group(T)            = doc <= (doc(T)).
 
     % This function can be used to convert strings, chars,
     % ints and floats to their text doc equivalents.
     %
+    % NOTE: since these types are now instances of the doc/1
+    % type class, it is simpler to just apply the doc/1
+    % method to these types.
+    %
 :- func poly(string__poly_type) = doc.
 
-    % Shorthand for doc `<>` line `<>` doc.
+    % Shorthand for doc ++ line ++ doc.
     %
 :- func doc `</>` doc       = doc.
 
     % Various bracketing functions.
     %
-    %   bracketed(L, R, Doc) = text(L) `<>` Doc `<>` text(R)
+    %   bracketed(L, R, Doc) = L ++ Doc ++ R
     %       parentheses(Doc) = bracketed("(", ")", Doc)
     %          brackets(Doc) = bracketed("[", "]", Doc)
     %            braces(Doc) = bracketed("{", "}", Doc)
@@ -319,10 +342,9 @@
     % Convert arbitrary terms to docs.  This requires
     % std_util__functor/3 to work on all components of the
     % object being converted.  The second version places a
-    % maximum depth on terms which are otherwise truncated;
-    % when the depth limit is reached, all arguments of a
-    % functor are replaced by `/<arity>' where <arity> is
-    % the number of arguments.
+    % maximum depth on terms which are otherwise truncated
+    % in the manner described in the documentation for the
+    % doc/2 method of the doc/1 type class.
     %
     % This may throw an exception or cause a runtime abort
     % if the term in question has user-defined equality.
@@ -338,10 +360,10 @@
     % Write docs out in pretty printed format.  The int
     % argument specifies a page width in characters.
     %
-:- pred write(int, doc, io__state, io__state).
+:- pred write(int, T, io__state, io__state) <= doc(T).
 :- mode write(in, in, di, uo) is det.
 
-:- pred write(io__output_stream, int, doc, io__state, io__state).
+:- pred write(io__output_stream, int, T, io__state, io__state) <= doc(T).
 :- mode write(in, in, in, di, uo) is det.
 
 %------------------------------------------------------------------------------%
@@ -374,11 +396,15 @@
 
 %------------------------------------------------------------------------------%
 
-:- instance doc(doc)    where [ doc(Doc)    = Doc            ].
-:- instance doc(string) where [ doc(String) = text(String)   ].
-:- instance doc(int)    where [ doc(Int)    = poly(i(Int))   ].
-:- instance doc(float)  where [ doc(Float)  = poly(f(Float)) ].
-:- instance doc(char)   where [ doc(Char)   = poly(c(Char))  ].
+doc(X) = doc(int__max_int, X).
+
+%------------------------------------------------------------------------------%
+
+:- instance doc(doc)       where [ doc(_, Doc)    = Doc            ].
+:- instance doc(string)    where [ doc(_, String) = text(String)   ].
+:- instance doc(int)       where [ doc(_, Int)    = poly(i(Int))   ].
+:- instance doc(float)     where [ doc(_, Float)  = poly(f(Float)) ].
+:- instance doc(char)      where [ doc(_, Char)   = poly(c(Char))  ].
 
 %------------------------------------------------------------------------------%
 
@@ -388,11 +414,11 @@
 
 nil                     = 'NIL'.
 X `<>` Y                = 'SEQ'(X, Y).
-nest(I, X)              = 'NEST'(I, X).
-label(L, X)             = 'LABEL'(L, X).
+nest(I, X)              = 'NEST'(I, doc(X)).
+label(L, X)             = 'LABEL'(L, doc(X)).
 text(S)                 = 'TEXT'(S).
 line                    = 'LINE'.
-group(X)                = 'GROUP'(X).
+group(X)                = 'GROUP'(doc(X)).
 
 poly(s(S))              = text(string__format("%s", [s(S)])).
 poly(c(C))              = text(string__format("%c", [c(C)])).
@@ -405,9 +431,9 @@
     layout_best(pred(H::in, T::in, [H | T]::out) is det, W, X, [], Ss),
     S = string__append_list(list__reverse(Ss)).
 
-write(W, X)             --> layout_best(io__write_string, W, X).
+write(W, X)             --> layout_best(io__write_string, W, doc(X)).
 
-write(Stream, W, X)     --> layout_best(io__write_string(Stream), W, X).
+write(Stream, W, X)     --> layout_best(io__write_string(Stream), W, doc(X)).
 
 %------------------------------------------------------------------------------%
 
@@ -789,10 +815,7 @@
 
 map_to_doc(Depth, X) = Doc :-
     KVs = list__map(mk_map_pair, map__to_assoc_list(X)),
-    Doc =
-        group(
-            "map" ++ parentheses(list_to_doc(Depth - 1, KVs))
-        ).
+    Doc = group("map" ++ parentheses(list_to_doc(Depth - 1, KVs))).
 
 
 :- func mk_map_pair(pair(K, V)) = map_pair(K, V).
@@ -821,12 +844,7 @@
 %------------------------------------------------------------------------------%
 
 word_wrapped(String) =
-    packed(
-        space,
-        list__map(
-            func(Word) = text(Word),
-            string__words(char__is_whitespace, String)
-        )
-    ).
+    packed(space, list__map(func(Word) = text(Word),
+                            string__words(char__is_whitespace, String))).
 
 %------------------------------------------------------------------------------%
--------------------------------------------------------------------------
mercury-reviews mailing list
post:  mercury-reviews at cs.mu.oz.au
administrative address: owner-mercury-reviews at cs.mu.oz.au
unsubscribe: Address: mercury-reviews-request at cs.mu.oz.au Message: unsubscribe
subscribe:   Address: mercury-reviews-request at cs.mu.oz.au Message: subscribe
--------------------------------------------------------------------------



More information about the reviews mailing list