[Agda] [RFC stdlib v2.0] 1. Numeric ops with non-zero proofs

Matthew Daggitt matthewdaggitt at gmail.com
Tue Jul 6 06:43:28 CEST 2021


Dear all,
To kick things off, the first RFC (request for comment) for v2.0 of the
Agda standard library is about proposed changes to how numeric operations
that require non-zero proofs (e.g. division) work.

The current situation

Currently operations such as division are defined as follows
<https://github.com/agda/agda-stdlib/blob/516c545f28aca931d695a86fbdf7941154b0a64f/src/Data/Nat/DivMod.agda#L43>
:

_/_ : (dividend divisor : ℕ) {≢0 : False (divisor ≟ 0)} → ℕ

taking an implicit proof that the result of the decision procedure of
testing whether it is zero reduces to false. This is preferable to passing
a direct proof of the form divisor ≢ 0 as it means that when divisor normalises
to something of the form suc n then the type of the proof reduces to
unit ⊤ which
Agda automatically fills in. Consequently you can write 7 / 3 or m /
sucn without
having to explicitly construct the proof.

The current problems

   1. When the denominator is not in the form suc _, Agda can't infer the
   proof and therefore it must always be passed explicitly even when the proof
   is in scope. This leads to having to write the ugly code like the following:

∀ m n {gcd≢0 : NonZero (gcd m n)} → Coprime ((m / gcd m n) {gcd≢0})
((n / gcd m n) {gcd≢0})


   1.

   When proving equalities over _/_ you can't use cong₂ from
   Relation.Binary.PropositionalEquality directly as Agda requires that you
   explicitly prove the proofs of non-zeroness do not affect the result. This
   makes it very finicky to use equational reasoning.
   2.

   The use of the decision procedure _≟_ means that the definition must
   depend on Data.Nat.Properties where _≟_ lives. This means that a)
   type-checking anything involving _/_ requires type-checking a much
   larger proportion of the library that one would expect and b) _/_ can't
   live in Data.Nat.Base.
   3.

   Constructing a proof of the type False (divisor ≟ 0) is much trickier
   than a proof of divisor ≢ 0and requires extra imports from
   Relation.Nullary.

Proposed solution

We propose to take a leaf out of Ulf Norell's Prelude library and instead
pass the proofs as *irrelevant*, *instance* arguments that use the new
NonZero predicates introduced in v1.5:

_/_ : (dividend divisor : ℕ) {{.(NonZero divisor)}} → ℕ

which preserves the ability to not provide the proofs for divisors of the
form suc _ and fixes the problems listed above as follows:

   1. Agda automatically fills in instance arguments if they are in scope,
   therefore removing the need to supply them to every place in the expression
   where they can't be inferred. For example we would then be able to write
   the much nicer:

∀ m n {{NonZero (gcd m n)}} → Coprime (m / gcd m n) (n / gcd m n)


   1.

   Agda doesn't consider irrelevant arguments when proving propositional
   equality. Therefore to prove m / n and x / y are propositionally equal
   will only require that we prove m equals x and n equals y and will not
   require us to explicitly prove that the result doesn't depend on the proofs
   of non-zeroness.
   2.

   The NonZero predicate is much more lightweight than the decidability
   proof and lives in Data.Nat.Base rather than Data.Nat.Properties.
   3.

   The NonZero predicate comes with nice constructors nonZero-< and
   nonZero-≢ that makes constructing such proofs much easier.

This has an additional advantage in that for certain operations that always
result in a non-zero result, e.g. factorial, it will be possible to declare
a proof of the non-zeroness as an instance and you will never have to
explicitly pass a proof.

Backwards incompatibilities

In cases where the proof is already automatically inferred nothing will
need to change. In places where the proof has to be passed explicitly, then
the type of the proof will need to change and will need to be passed using
instance brackets {{_}} rather than implict brackets {_}. As mentioned
above, NonZero comes with constructors so constructing the new proofs
should be much easier.

Feedback

Any feedback would be greatly appreciated! Please feel free to reply in one
of the following issues:
https://github.com/agda/agda-stdlib/issues/921
https://github.com/agda/agda-stdlib/issues/1170
https://github.com/agda/agda-stdlib/issues/1408
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.chalmers.se/pipermail/agda/attachments/20210706/1bffc86a/attachment.html>


More information about the Agda mailing list