[m-dev.] string streams and formatting

Michael Day mcda at cat.cs.mu.OZ.AU
Fri Jan 14 22:13:16 AEDT 2000


>     1)  I wouldn't call this "write."  I think write should either write
> 	terms (cf Prolog) or raw data (cf C).  Probably the former:
> 	why make a gratuitous change to the current library?  At any
> 	rate, "write" doesn't seem like a good name for the predicate
> 	that does formated output.  How about "format" or "output?"

Given that this is neither Prolog nor C, I felt at liberty to attempt to
make it capable of both, and more. To be precise, write is a type class
method belonging to types that satisfy the writable type class and how
they choose to represent themselves is entirely their own business.

It is not actually a change at all to the current library, it is rather an
addition. io__write and its brethren will continue as previously, possibly
adorned with obsolete pragmas or possibly not. I chose read and write over
input and output because of their simplicity and because readable and
writable don't rip the flesh from my bones in the same way that inputable
and outputable do. Though the append-an-"able" convention for determining
type class names is possibly unsound in the long run, it's quite
convenient sometimes.

>     2)  I think you'll do better if you base this on lists, rather
>         than individual outputs.  For example, putting out 2A on the
>         right of a 80 character field is not as useful as putting, eg,
>         "The result is 2A" in an 80 character field.  For that, you'd
>         want the goal to look something like
> 
> 	     output(right(80, [string("The result is "), hex(42)]))

This is perfectly acceptable as it stands, almost. It just needs a
sensibly defined existentially quantified list type for holding writable
things. I toyed with something like this:

:- type my_list
	--->	[]
	;	some [T] ([T | my_list] => writable(T)).

I've probably got the syntax completely wrong, recalling from memory what
I eventually ended up with. However the problem I encountered was that
although the list did appear to work, I couldn't use literal
representations in my code as they appeared to clash with the standard
list functors and I couldn't work out how to sensibly module quantify
them.

A rather interesting alternative I stumbled on quite accidentally looked
like this:

	write("The result is: " << hex(42) << newline)

which worked by some bizarre interaction between the DCG expansion and an
overloaded functional usage of '<<'. If anyone is interested I can
reproduce the code, I'd be happy if someone could tell me exactly what was
going on. However I'm guessing that C++ style overloading of these
operators for input and output would not be appreciated...?

>     3)  Most importantly:  for several reasons, I think the best way to
>         handle this is using a format type class (I didn't say
>         sequence!), rather than just a format type.  The two most
>         important reasons are: a) it allows users to define their own
>         format types, which will allow them to use the same formatted
>         output predicates for their own types which need special
>         formatting; and b) it allows much more expressive and compact
>         types.  Eg, you can define string as an instance of the format
>         class, and then you can just write
> 
> 		output(right(80, ["The result is ", hex(42)]))
> 
> 	for the previous example.  You'll probably need to use
> 	existential types for this, but I believe they work well
> 	enough now that this could be made to work.  Int, float, etc,
> 	should also be made instance of the format class, so if you
> 	hadn't wanted hex output in the previous example, you could
> 	just write
> 
> 		output(right(80, ["The result is ", 42]))
> 
> 	Oh, and if you make some(T) list(T) an instance of format,
> 	that handles point 2 above without making users write
> 	singleton lists when they've only got one thing to output.  So
> 	all of the following would be valid:
> 
> 	    output(42)
> 	    output(["The result is ", 42])
> 	    output(right(80, hex(42)))
> 	    output(right(80, ["The result is ", hex(42)])

Hmm perhaps I should have extended the preface to the code I posted
earlier, this is more or less what I've done.

write(42) will work, because 42 is an int and int is writable.
write(["blah", 42]) will work with alternative list syntax (see above).
write(right(80, T)) will work if T is writable.

and so on. You can define your own types to be writable, make them wrap
other types and give them formatting semantics, basically what you would
expect.

> Aw, come on!  You're taking all the fun out of it :-).

Every post on input/output will include a disclaimer regarding:

	- constructor classes and collection type classes
	- unique and partial/parametric/polymorphic modes, aliasing, etc
	- default type class methods
	- currying

and any other topic that will lead to a discussion both interesting and
informative but unfortunately completely unrelated to the question at
hand, while still retaining the same deceptive subject line to beguile me
into reading them all.

Features are great, but it's a real pain when your code depends on them
and they aren't implemented, designed or in fact researched yet :)

Michael

--------------------------------------------------------------------------
mercury-developers mailing list
Post messages to:       mercury-developers at cs.mu.oz.au
Administrative Queries: owner-mercury-developers at cs.mu.oz.au
Subscriptions:          mercury-developers-request at cs.mu.oz.au
--------------------------------------------------------------------------



More information about the developers mailing list