Newer Older
1 2 3 4

On named method parameters

5 6 7 8 9 10 11 12
When the arguments of a data constructor are arranged in an inline record, we
would ideally like the data constructor's descending method to receive named
arguments. E.g., it could receive a record as an argument. But that does not
work, because we would need to declare a record type, with the same fields.
Or, it could take labeled arguments. That would work, I think, but we prefer
to avoid labels. Our solution, for now, is to pass unnamed arguments to the
descending method. The arguments appear in the same order as in the data
constructor declaration.
13 14 15

Similarly, the ascending methods for records and for inline records currently
receive anonymous arguments.
16 17 18 19 20 21 22 23


On type variables

Can we deal with parameterized type declarations? Yes, we can, but we should
distinguish two approaches.

POTTIER Francois committed
24 25
The "monomorphic" approach assumes (requires) that a local parameterized type
is always applied to the same actual arguments. So, it is just as if we have a
26 27 28 29 30
type \Lambda at the top level and, under that, we are dealing with ordinary
unparameterized types. This approach naturally leads to generated code where
every method has a monomorphic type, but our class declarations are
parameterized (they have a type \Lambda at the top level). In fact, the
quantification over 'self is probably sufficient to take care of this aspect;
POTTIER Francois committed
31 32
no extra type parameters are required. In this approach, a type variable 'a is
traversed by invoking a virtual method, [visit_'a].

POTTIER Francois committed
The "polymorphic" approach allows a type constructor (which could be local,
35 36
say 'a term, or nonlocal, say 'a list) to be instantiated in multiple sites
with distinct (vectors of) actual arguments. This approach requires
POTTIER Francois committed
37 38
polymorphic methods. In the subclass [iter], for example, the visitor method
[visit_list] could have type:

POTTIER Francois committed
40 41 42 43 44 45 46 47 48 49 50 51
  'env 'a0. ('env -> 'a0 -> unit) -> 'env -> 'a0 list -> unit

In the subclass [map], it could have type:

  'env 'a0 'a1. ('env -> 'a0 -> 'a1) -> 'env -> 'a0 term -> 'a1 term

In this approach, a type variable 'a is traversed by invoking a visitor
function which has been received as an argument.

In the first release of visitors, only the monomorphic approach was supported.
However, the hand-written classes in VisitorsRuntime follow the polymorphic
approach, for greater generality.
POTTIER Francois committed

POTTIER Francois committed
53 54 55
It should be noted that the polymorphic approach is not always preferable to
the monomorphic approach. Indeed, assigning to a method a more general type
makes this method easier to *use*, but more difficult to *override*.
56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75


Base class, or no base class

I initially thought that [iter] and [map] should be subclasses of a base class
[visitor], as they differ only in the ascending computation: to do nothing in
[iter], and to reconstruct a data structure in [map].

However, a difficulty with this approach is that this requires declaring
virtual methods in the base class [visitor], and these virtual methods must
have a monomorphic type, even if they are invoked in several places -- which
is typically the case for nonlocal (parameterized) types, such as tuples,
lists, options, and pre-existing user-defined type constructors. This leads to
an unacceptable lack of generality.

A different approach is to generate [iter] and [map] directly, without a base
class. In the case of nonlocal types, we allow the user to provide (possibly
polymorphic) code. This solves the problem. (Furthermore, we probably gain
some speed by saving a few virtual method calls.)