this may be obvious or already discussed somewhere, but is it possible (and could it be useful) to reason about λProlog programs in Coq, before implementing them in Elpi/Coq-Elpi? The algorithm(s) for typeclass resolution presented at the Coq Workshop seemed really tricky to get right.
I have a few answers, which I think are all a bit weird ;-)
The TC solver is an automatic prover and we check the output via Coq. We have (even formal) proofs about the calculus behind, say, E-prover. Would it make sense to prove that the code is OK? We have similar results for SLD or SLG (tabling) main loops. IMO we want to tell the user, statically, that his program will (always) loop in SLD or (always) fail in SLG, for example. Maybe this is what you had in mind, after all. But proving that the "compiler" @Davide F is "correct" is not so clear to me...
Thanks. I meant both giving users static guarantees and proving algorithms for problems like typeclass resolution correct/fast in an abstract setting, divorced from Coq itself (but possibly inside Coq)
In some sense you get the program (and a semantics) only after translation to Elpi.
Given unlimited time, one could still reason about the meta-program — compilation to elpi + elpi execution should be sound relative to a direct semantics — IF you have a simple enough semantics that the extra confidence is worthwhile.
intuitively, any direct semantics should be a bit clearer than one involving a translation, but from outside I'd fear, with low confidence, the ratio between confidence gain and proof effort might be somewhat low?
My problem in verifying the compilation is that one needs the semantics for the source language (Coq's Instance commands and TC solver) and the target one (Elpi's clauses, and the resolution strategy, e.g. depth-first aka SLD).
But I really don't know how to describe the semantics of Coq's TC search. Intuitively it is DFS, but it is really implemented calling apply, which uses the Coq's (legacy) unifier. I don't have a spec for that to begin with, while on the other end unification in Elpi is very very close to pattern-fragment, which one could define formally.
Davide and I are still discovering corner cases of the current TC engine, and sometimes we emulate it, sometimes we say it is wrong and we do differently. So even if we had the two semantics, it would not be the goal to be 100% faithful.
are you writing down somewhere the corner cases?
At the same time having a semantics for the target language, and implement some static checks, is IMO very important. Actually, it was my starting point: I wanted to do static checking of TC "programs", and Dale convinced me I needed a language to express the whole business, and that turned out to be a dialect of lambdaProlog.
Gaëtan Gilbert said:
are you writing down somewhere the corner cases?
I have notes, and they will end up in Davide's master report.
I can mention that the order is which goals are tackled depends on the caller, eg apply and rewrite (setoids) give goals in different order (one of the two does them in a clearly wrong order, as if the objective was maximizing backtracking).
Another thing which I believe Davide explained at the Coq workshop is that input/output modes are used to block the resolution of an ill-moded goal, but not to pick an order of goals which makes the i/o flow correct (or warn the user the order of premises is incompatible with the modes he is using).
The "cost" of an instance is, if I remember correctly, very complex to compute, at the point that we gave up trying to do exactly what Coq does (I thought it was the number of premises, but not quite).
Last updated: Oct 13 2024 at 01:02 UTC