A similar question may rise about functions in the large, this is just that
I am wondering about it, in the context of proofs.
I wonder how I can check or proof that if I can derive a proof of B from a
proof of A, then for a given proof of A (that is, its exact expression with
indexes), I can derive only one proof of B (the same, I mean its exact
expression with indexes).
Say proofs are like functions, then this is about how to check or prove, a
proof function is deterministic and there are no possible arbitrary
choices, which may make the result vary.
Some samples may tell better. I expose four cases (then a fifth case about
something else related). For all of these four cases, I purposely use the
same prval
expressions to check and show some things. All four cases uses
two dataprop
named R and E (which stands for Representation and Entity).
- The first two cases are examples of what I want to avoid.
- The next two cases are examples of what is OK. I don’t know how to prove
these latter two cases are OK.
// 1) A case where from any R one can derive any E
// ===============================================
sortdef r = int
sortdef e = int
dataprop R(i:r) =
| R1(i)
dataprop E(i:e) =
| E1(i) of [j:r] R(j)
prval pf:E(0) = E1(R1:R(0))
prval pf:E(0) = E1(R1:R(1))
prval pf:E(0) = E1(R1:R(2))
prval pf:E(1) = E1(R1:R(0))
prval pf:E(1) = E1(R1:R(1))
// And so on, whatever one wants …
// 2) A case where from one R one can derive multiple E
// ====================================================
sortdef r = int
sortdef e = int
dataprop R(i:r) =
| R1(i)
dataprop E(i:e) =
| E1(i) of R(i / 2)
prval pf:E(0) = E1(R1:R(0))
// Constraint error: prval pf:E(0) = E1(R1:R(1))
// Constraint error: prval pf:E(0) = E1(R1:R(2))
prval pf:E(1) = E1(R1:R(0))
// Constraint error: prval pf:E(1) = E1(R1:R(1))
// 3) A case where from one R one can derive only one E
// ====================================================
sortdef r = int
sortdef e = int
dataprop R(i:r) =
| R1(i)
dataprop E(i:e) =
| E1(i) of R(i)
prval pf:E(0) = E1(R1:R(0))
// Constraint error: prval pf:E(0) = E1(R1:R(1))
// Constraint error: prval pf:E(0) = E1(R1:R(2))
// Constraint error: prval pf:E(1) = E1(R1:R(0))
prval pf:E(1) = E1(R1:R(1))
// 4) Another case where from one R one can derive only one E
// ==========================================================
//
// However, one E may be derived from multiple R.
sortdef r = int
sortdef e = int
dataprop R(i:r) =
| R1(i)
dataprop E(i:e) =
| E1(i / 2) of R(i)
prval pf:E(0) = E1(R1:R(0))
prval pf:E(0) = E1(R1:R(1))
// Constraint error: prval pf:E(0) = E1(R1:R(2))
// Constraint error: prval pf:E(1) = E1(R1:R(0))
// Constraint error: prval pf:E(1) = E1(R1:R(1))
I naively though about something like this:
extern prfn f():
[r1, r2: r; e1, e2: e; ~(r1 == r2) || (e1 == e2)]
(R(r1) -> E(e1), R(r2) -> E(e2))
which would be supposed to mean: for any two functions deriving an R from
an E, then r1 == r2 implies e1 == e2.
Unfortunately, even the first case allows to prove it, which shows this
cannot ensure the deterministic functional relation I would like to be able
to prove or check. I’m repeating the first case, to remind, with the proof
added at the end:
// 1) A case where from any R one can derive any E
// ===============================================
sortdef r = int
sortdef e = int
dataprop R(i:r) =
| R1(i)
dataprop E(i:e) =
| E1(i) of [j:r] R(j)
prval pf:E(0) = E1(R1:R(0))
prval pf:E(0) = E1(R1:R(1))
prval pf:E(0) = E1(R1:R(2))
prval pf:E(1) = E1(R1:R(0))
prval pf:E(1) = E1(R1:R(1))
// And so on, whatever one wants …
prfn f():
[r1, r2: r; e1, e2: e; ~(r1 == r2) || (e1 == e2)]
(R(r1) -> E(e1), R(r2) -> E(e2)) =
let
prfn {i:int} g(r:R(i)): E(i) = E1(R1:R(i))
stacst i:int
in (g:R(i) -> E(i), g:R(i) -> E(i)) end
… look at f
, which is unfortunately provable.
I feel to guess I need quantification over functions. Or is there another
way to express it in ATS?
Something different now, while related, as it’s about what a result depends
on (this one, is obviously applicable to any function too, not just proof
functions):
// 5.2) from an axiom from the context
// -----------------------------------
dataprop A =
| A1
dataprop C =
| C1 of C // Bigger than our universe
extern praxi c(): C // Let us be silly
dataprop B =
| B1 of C
prfn b_from_a(pf:A): B = B1(c())
// Not really B from A, rather B from c()!
// How to tell about this proof’s dependencies?
This is very important to keep in mind that this:
prfn b_from_a(pf:A): B = B1
… does not necessarily means “B is derivable from A”, as it’s too easy to
believe (it’s particularly important to not miss‑read what one read, when
xe read a proof signature).
This case (the fifth case) probably requires manual inspection (may be with
the help of a dedicated tool), and this would be OK. However, for the four
first cases, I really would like to be able to express it directly.