[m-rev.] for post-commit review: check for terms containing distinct vars in one place

Peter Wang novalazy at gmail.com
Fri May 10 17:09:33 AEST 2024


On Fri, 10 May 2024 15:19:11 +1000 "Zoltan Somogyi" <zoltan.somogyi at runbox.com> wrote:
> 
> On 2024-05-10 14:45 +10:00 AEST, "Peter Wang" <novalazy at gmail.com> wrote:
> >> @@ -7828,6 +7828,12 @@ However, variables which are in the range of a functional dependency
> >>  need not appear in the signature,
> >>  since it is known that their bindings will be determined
> >>  from the bindings of the variables in the domain.
> >> + at c XXX What about a class with two fundeps: A -> B, and B -> A.
> >> + at c Both A and B are in the range of a fundep.
> >> + at c The above text seems to imply that it is ok for *neither* to appear
> >> + at c in the signature.
> >> + at c Should we replace "since it is known that their bindings will be determined"
> >> + at c with "provided that their bindings are determined"?
> >>  
> > 
> > How about:
> > 
> >     Without any functional dependencies, all variables in constraints
> >     must appear in the signature of the predicate or function being
> >     declared.
> >     However, a variable [that appears] in the range of a functional
> >     dependency does not need appear in the signature *if* the variables
> >     in the domain of that functional dependency do appear in the
> >     signature.
> 
> I don't think that is quite right. Given functional dependencies
> A->B and B->C, it is ok for only A to appear in the signature.
> C does not have to appear there, even though B is not in the signature either,
> because B is nevertheless determined by a type var, A, that *is* in the
> signature.

You're right.

> 
> We need to avoid being both too strict (ruling out the chained application of
> more than one fundep, even though it is allowed, as with the {A->B, B->C} example
> above) and too loose (allowing circular reasoning of the form "assuming
> we know A, we can prove we know A", as with the {A->B, B->A} example
> in the original text). It is difficult to thread the needle between these two issues.
> I can't think of a way to do that using simple and short text, because I think
> that what we need to describe is forward chaining: starting with a given set of type vars
> from the signature, and adding to that set  by applying fundeps *whose domain
> is already in that set*.

I'll give it another go:

    Without any functional dependencies, all variables in constraints
    must appear in the signature of the predicate or function being
    declared.
    However, a variable that appears in the range of a functional
    dependency FD does not need to appear in the signature *if*
    each variable in the domain of FD satisfies one of these conditions:

    - the variable in the domain of FD appears in the signature; or

    - the variable in the domain of FD appears in the range of a
      functional dependency FD2, and the variables in the domain of FD2
      in turn satisfy these conditions.

> 
> I thought we can describe things using dags, along the lines of
> 
> (1) every fundep with N type vars in its domain and M in its range defines N*M directed edges.
> with each one pointing from a var in the domain to one in the range, and (2) every var that
> is not in the signature must be reachable from the vars that are in the signature.
> 
> But I can't come up with a correctness argument for this description, because I have the
> nagging feeling that treating a fundep such as P,Q->R as two *independent* edges,
> P->R and Q->R, loses significant information. In reality, fundeps are not really
> collections of edges, they are *hyperedges*. But if we use that terminology, we lose
> at least 95% of our audience.

You've lost me :)

Peter


More information about the reviews mailing list