[m-dev.] Automatic generation of map, foldr, foldl

Fergus Henderson fjh at cs.mu.OZ.AU
Mon Sep 21 14:25:28 AEST 1998


On 09-Sep-1998, Peter Schachte <pets at cs.mu.OZ.AU> wrote:
> > :- type tree(T) ---> leaf(T); t(tree(T),tree(T)).
> > you can generate some Horn clauses:
> 
>  [ generalization of apply_closure_to_all_elements and member ]
> 
> > And with another declaration like
> > :- skeleton tree_any/1 generates foldl, foldr, map(1), map(2).
> > generate
> 
>  [ generalization of foldl, foldr, etc. ]
> 
> 
> I like the idea of generating higher-order code, or indeed anything
> that makes it easier to use higher levels of abstraction.  But I do
> have the feeling that this isn't necessarily the right set of
> abstractions.  For example, your first generated predicate is
> something like "for all x in <data structure> f(x)", and your second
> is "x in y."  Why isn't the second "there exists x in <data structure>
> such that f(x)?"  And on binary trees, foldl and foldr do preorder and
> postorder traversal; what about inorder?  And how about mapping and
> folding operators that stop before traversing the whole data
> structure?  There are so many variants of these travarsal predicates.
> 
> This would be much nicer if you could abstract what is common among
> all of these and provide that.  A tall order.

I agree with Peter here.

> Or maybe when you say
> that one can write one's own predicates you're indicating that you've
> made that abstraction.

That *seemed* to be what Lee was saying, but I couldn't see how it
would work, and Lee hasn't given us any examples (hint, hint ;-).

> One thought, though.  One way of abstracting part of what all of these
> predicates do is with the concept of an "iterator" (I know, I know,
> this word brings to mind horrible images of C++, but it's a pretty
> good description).  I guess it's best to think of iterator as a family
> of type classes iterator_n(T,CT,IT) where T is a type (or a tuple of
> types somehow?), CT is a collection of T, and IT is an iterator for
> that collection.  Instances of iterator1 provide these predicates and
> functions:
> 
> 	:- func iterator(CT::in) = IT::out is det.
> 	:- pred next(IT::in, IT::out, T::out) is semidet.
...
> Anyway, given just this, you can write a lot of the sorts of
> higher-order predicates you're talking about generating once, and put
> them in the library.  Eg, member is
> 
> 	:- pred member(T::out, CT::in) is nondet <= iterator1(T,CT,IT).

That won't work; you're not allowed to put constraints on type
variables such as `IT' which don't occur in the predicate's arguments.
The compiler can't figure out what type `IT' should be.  Note there
might be more than one possible iterator type for a given collection
type and element type.  For example, you might have iterators that
iterate forwards, iterators that iterate backwards, iterators that
iterate only over the even-numbered elements, etc.

-- 
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 developers mailing list