[mercury-users] polymorphism
Fergus Henderson
fjh at cs.mu.oz.au
Fri Sep 26 14:04:04 AEST 1997
Tomas By, you wrote:
>
> I'm writing an XML library. The interface consists of a
> document type and procedures to read/write/validate etc.
> The problem with XML documents is that apps might want to
> treat them either as a stream of elements or as a tree
> structure, and that you sometimes want to preserve
> whitespace and sometimes not.
>
> So you need four different types:
>
> stream with whitespace [ stream(byte) ]
> stream without whitespace [ stream(word) ]
> tree with whitespace [ tree(byte) ]
> tree without whitespace [ tree(word) ]
...
> "Fergus Henderson" <fjh at cs.mu.oz.au> wrote:
> > Why don't you want p/1 to handle things of other types?
>
> I want a procedure 'dump' for example that can handle all the
> four types above. The reason I don't want it to handle other
> things is I don't want to write the code. :-)
Well, one way to handle this is to have `dump' take a couple of
of predicates `DumpToken' and `DumpV' as additional arguments.
:- pred dump(item(V, T)::in,
pred(V, io__state, io__state)::(pred(in, di, uo) is det)
pred(T, io__state, io__state)::(pred(in, di, uo) is det)
io__state::di, io__state::uo) is det.
dump(v(V), DumpV, _DumpToken) --> DumpV(V).
dump(token(Token), _DumpV, DumpToken) --> DumpToken(Token).
dump(spec(Spec), _DumpV, _DumpToken) --> ...
Then if you want to dump a variable of type stream(byte), you call
`dump(ByteStream, dump_stream, dump_byte)':
dump_byte_stream(ByteStream) -->
dump(ByteStream, dump_stream, dump_byte).
This is basically the type-class approach, except that since we don't
yet support type classes, you simulate them using higher-order preds.
The other alternative is that you could just define `item' as a type
that can be either a tree or a stream, of either bytes or words:
:- type item
---> token(token)
; spec(spec)
; start_tag(string,list(attribute))
; end_tag(string)
; element(string,list(attribute),item).
:- type token
---> byte(byte)
; word(word).
You could then use insts as subtypes:
:- inst stream(I) == list_skel(stream(I)).
:- inst stream_item(I)
---> token(I)
; spec(ground)
; start_tag(ground,ground)
; end_tag(ground).
:- inst tree(I) == list_skel(tree(I)).
:- inst tree_item(I)
---> token(I)
; spec(ground)
; element(ground,ground,tree_item(I)).
:- inst word_token
---> byte(ground).
:- inst byte_token
---> byte(ground).
Another approach is to use the item/0 type defined above,
but not bother with using insts as subtypes -- subtype errors
would then be detected at runtime (via calls to error/1) rather
than at compile time.
I'm really not sure which approach would be better;
I think any of these three approaches could work well.
Probably I'd be inclined to go with the simulate-type-classes approach.
--
Fergus Henderson <fjh at cs.mu.oz.au> | "I have always known that the pursuit
WWW: <http://www.cs.mu.oz.au/~fjh> | of excellence is a lethal habit"
PGP: finger fjh at 128.250.37.3 | -- the last words of T. S. Garp.
More information about the users
mailing list