Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

a recursive view of Fin n #1923

Merged
merged 43 commits into from
Sep 18, 2023
Merged
Show file tree
Hide file tree
Changes from 36 commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
75fa9d0
a view of `Fin (suc n)`
jamesmckinna Feb 9, 2023
629b415
documentation
jamesmckinna Feb 9, 2023
c6a9994
theory of `opposite` also
jamesmckinna Feb 9, 2023
d6e7b9c
tweak
jamesmckinna Feb 9, 2023
d2173fb
first of Jacques' review changes
jamesmckinna Feb 10, 2023
6e0c4be
refactored according to Jacques' prescriptions; renamed the inverse
jamesmckinna Feb 10, 2023
1021deb
fix whitespace
jamesmckinna Feb 10, 2023
a870d69
tightened imports
jamesmckinna Feb 10, 2023
c766cc7
tightened imports
jamesmckinna Feb 11, 2023
f43a21f
tightened imports
jamesmckinna Feb 11, 2023
66bc0c7
cosmetics
jamesmckinna Feb 11, 2023
8eff5d6
rmeoved redundant
jamesmckinna Feb 11, 2023
6576fe5
made `Instances` not public
jamesmckinna Feb 11, 2023
c18173c
slight refactor
jamesmckinna Feb 11, 2023
d4069e9
symmetry typo
jamesmckinna Feb 11, 2023
6d4cc58
imports
jamesmckinna Feb 11, 2023
0e6db5e
other use of `lower₁` in `Data.Fin.Induction`
jamesmckinna Feb 14, 2023
fa28f4c
previously uncommitted comment on the `View` itself
jamesmckinna Feb 15, 2023
c51dd63
tidied up imports for `Top` view
jamesmckinna Apr 17, 2023
904fdbe
made `--cubical-compatible`
jamesmckinna Apr 17, 2023
f3550ad
better use of `variable`s
jamesmckinna May 12, 2023
9a0d6ad
(vertical) whitespace)
jamesmckinna May 14, 2023
1dd382e
made the view recursive; with simplifications
jamesmckinna Aug 7, 2023
f10cb3f
final tweaks; use of variable `{n}` still needed in places
jamesmckinna Aug 7, 2023
d878b2c
streamlined use of instances
jamesmckinna Aug 7, 2023
c0d5651
revised names, as per discusison
jamesmckinna Aug 8, 2023
2c94427
factored out `Instances`; revised `README` and `CHANGELOG`
jamesmckinna Aug 8, 2023
9bce07e
followed Matthew's suggestion better; added uniqueness proof for the …
jamesmckinna Aug 8, 2023
9012225
typo
jamesmckinna Aug 8, 2023
c7e7c9e
revised `Instances`
jamesmckinna Sep 12, 2023
1f1f9f3
fresh round of `variable` review comments
jamesmckinna Sep 12, 2023
a88d39c
sharpened use of `instance`s in response to review comments
jamesmckinna Sep 12, 2023
c962e14
reordering
jamesmckinna Sep 12, 2023
6ba18be
`fromℕ≢inject₁` now takes implicit argument
jamesmckinna Sep 12, 2023
c7b3acf
`CHANGELOG`!
jamesmckinna Sep 12, 2023
eae3f83
tidy up comments and binders
jamesmckinna Sep 14, 2023
4a4a4e2
Change to use i rather than j in Top
MatthewDaggitt Sep 15, 2023
c8451d7
uniform naming scheme
jamesmckinna Sep 15, 2023
6d8979d
Merge branch 'top-view' of github.com:jamesmckinna/agda-stdlib into t…
jamesmckinna Sep 15, 2023
21500e9
removed `Instances`
jamesmckinna Sep 17, 2023
c5ed38f
removed `inject₁⁻¹`
jamesmckinna Sep 17, 2023
cb3eb95
removed `Top.Instances`
jamesmckinna Sep 17, 2023
7207c6e
drastic `import` simplification
jamesmckinna Sep 17, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -1402,6 +1402,12 @@ New modules
Data.Default
```

* A small library defining a structurally recursive view of `Fin n`:
```
Data.Fin.Relation.Unary.Top
Data.Fin.Relation.Unary.Top.Instances
```

* A small library for a non-empty fresh list:
```
Data.List.Fresh.NonEmpty
Expand Down Expand Up @@ -1913,6 +1919,8 @@ Other minor changes
cast-is-id : cast eq k ≡ k
subst-is-cast : subst Fin eq k ≡ cast eq k
cast-trans : cast eq₂ (cast eq₁ k) ≡ cast (trans eq₁ eq₂) k

fromℕ≢inject₁ : {j : Fin n} → fromℕ n ≢ inject₁ j
```

* Added new functions in `Data.Integer.Base`:
Expand Down
152 changes: 152 additions & 0 deletions README/Data/Fin/Relation/Unary/Top.agda
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
------------------------------------------------------------------------
-- The Agda standard library
--
-- Example use of the 'top' view of Fin
--
-- This is an example of a view of (elements of) a datatype,
-- here i : Fin (suc n), which exhibits every such i as
-- * either, i = fromℕ n
-- * or, i = inject₁ j for a unique j : Fin n
--
-- Using this view, we can redefine certain operations in `Data.Fin.Base`,
-- together with their corresponding properties in `Data.Fin.Properties`:
------------------------------------------------------------------------

{-# OPTIONS --cubical-compatible --safe #-}

module README.Data.Fin.Relation.Unary.Top where

open import Data.Nat.Base using (ℕ; zero; suc; _∸_; _≤_)
open import Data.Nat.Properties using (n∸n≡0; +-∸-assoc; ≤-reflexive)
open import Data.Fin.Base using (Fin; zero; suc; toℕ; fromℕ; inject₁; _>_)
open import Data.Fin.Properties using (toℕ-fromℕ; toℕ<n; toℕ-inject₁)
open import Data.Fin.Induction hiding (>-weakInduction)
open import Data.Fin.Relation.Unary.Top
open import Data.Fin.Relation.Unary.Top.Instances
open import Induction.WellFounded as WF
open import Level using (Level)
open import Relation.Binary.PropositionalEquality
open import Relation.Unary using (Pred)

private
variable
ℓ : Level
n : ℕ
i : Fin (suc n)
j : Fin n

------------------------------------------------------------------------
-- Inverting inject₁

-- The principal purpose of this View of Fin (suc n) is that it provides
-- a *partial inverse* to the function inject₁, as follows:
--
-- * pattern matching of the form `... inj j ← view {n} i` ensures that
-- `i ≟ inject₁ j`, and hence that `j` is, *definitionally*, an image
-- under a hypothetical inverse to `inject₁`;
--
-- * such patterns are irrefutable *precisely* when `i` is in the codomain
-- of `inject₁`, which by property `fromℕ≢inject₁`, is equivalent to the
-- condition `i ≢ fromℕ n`, or again equivalently, `toℕ i ≢ n`, each
-- equivalent to `IsInject₁ {n} (view i)`, hence amenable to instance resolution
--
-- Definition
--
-- Rather than redefine `lower₁` of `Data.Fin.Base`, we instead define

inject₁⁻¹ : (i : Fin (suc n)) → .{{IsInject₁ (view i)}} → Fin n
inject₁⁻¹ i with ‵inject₁ j ← view i = j

-- Properties, by analogy with those for `lower₁` in `Data.Fin.Properties`

inject₁-inject₁⁻¹ : (i : Fin (suc n)) .{{_ : IsInject₁ (view i)}} →
inject₁ (inject₁⁻¹ i) ≡ i
inject₁-inject₁⁻¹ i with ‵inj₁ _ ← view i = refl

inject₁⁻¹-inject₁ : (j : Fin n) → inject₁⁻¹ (inject₁ j) ≡ j
inject₁⁻¹-inject₁ j rewrite view-inject₁ j = refl

inject₁≡⇒inject₁⁻¹≡ : (eq : inject₁ {n} j ≡ i) →
let instance _ = inject₁≡⁺ eq in inject₁⁻¹ i ≡ j
inject₁≡⇒inject₁⁻¹≡ refl = inject₁⁻¹-inject₁ _

inject₁⁻¹-injective : (i₁ i₂ : Fin (suc n))
.{{_ : IsInject₁ (view i₁)}}
.{{_ : IsInject₁ (view i₂)}} →
inject₁⁻¹ i₁ ≡ inject₁⁻¹ i₂ → i₁ ≡ i₂
inject₁⁻¹-injective i₁ i₂ with ‵inj₁ _ ← view i₁ | ‵inj₁ _ ← view i₂ = cong inject₁

inject₁⁻¹-irrelevant : (i : Fin (suc n)) .{{ii₁ ii₂ : IsInject₁ (view i)}} →
inject₁⁻¹ i {{ii₁}} ≡ inject₁⁻¹ i {{ii₂}}
inject₁⁻¹-irrelevant i with ‵inj₁ _ ← view i = refl

toℕ-inject₁⁻¹ : (i : Fin (suc n)) .{{_ : IsInject₁ (view i)}} →
toℕ (inject₁⁻¹ i) ≡ toℕ i
toℕ-inject₁⁻¹ i with ‵inject₁ j ← view i = sym (toℕ-inject₁ j)

------------------------------------------------------------------------
-- Reimplementation of `Data.Fin.Base.opposite`, and its properties

-- Definition

opposite : Fin n → Fin n
opposite {suc n} i with view i
... | ‵fromℕ = zero
... | ‵inject₁ j = suc (opposite {n} j)

-- Properties

opposite-zero≡fromℕ : ∀ n → opposite {suc n} zero ≡ fromℕ n
opposite-zero≡fromℕ zero = refl
opposite-zero≡fromℕ (suc n) = cong suc (opposite-zero≡fromℕ n)

opposite-fromℕ≡zero : ∀ n → opposite {suc n} (fromℕ n) ≡ zero
opposite-fromℕ≡zero n rewrite view-fromℕ n = refl

opposite-suc≡inject₁-opposite : (j : Fin n) →
opposite (suc j) ≡ inject₁ (opposite j)
opposite-suc≡inject₁-opposite {suc n} i with view i
... | ‵fromℕ = refl
... | ‵inject₁ j = cong suc (opposite-suc≡inject₁-opposite {n} j)

opposite-involutive : (j : Fin n) → opposite (opposite j) ≡ j
opposite-involutive {suc n} zero
rewrite opposite-zero≡fromℕ n
| view-fromℕ n = refl
opposite-involutive {suc n} (suc i)
rewrite opposite-suc≡inject₁-opposite i
| view-inject₁(opposite i) = cong suc (opposite-involutive i)

opposite-suc : (j : Fin n) → toℕ (opposite (suc j)) ≡ toℕ (opposite j)
opposite-suc j = begin
toℕ (opposite (suc j)) ≡⟨ cong toℕ (opposite-suc≡inject₁-opposite j) ⟩
toℕ (inject₁ (opposite j)) ≡⟨ toℕ-inject₁ (opposite j) ⟩
toℕ (opposite j) ∎ where open ≡-Reasoning

opposite-prop : (j : Fin n) → toℕ (opposite j) ≡ n ∸ suc (toℕ j)
opposite-prop {suc n} i with view i
... | ‵fromℕ rewrite toℕ-fromℕ n | n∸n≡0 n = refl
... | ‵inject₁ j = begin
suc (toℕ (opposite j)) ≡⟨ cong suc (opposite-prop j) ⟩
suc (n ∸ suc (toℕ j)) ≡˘⟨ +-∸-assoc 1 {n} {suc (toℕ j)} (toℕ<n j) ⟩
n ∸ toℕ j ≡˘⟨ cong (n ∸_) (toℕ-inject₁ j) ⟩
n ∸ toℕ (inject₁ j) ∎ where open ≡-Reasoning

------------------------------------------------------------------------
-- Reimplementation of `Data.Fin.Induction.>-weakInduction`

open WF using (Acc; acc)

>-weakInduction : (P : Pred (Fin (suc n)) ℓ) →
P (fromℕ n) →
(∀ i → P (suc i) → P (inject₁ i)) →
∀ i → P i
>-weakInduction {n = n} P Pₙ Pᵢ₊₁⇒Pᵢ i = induct (>-wellFounded i)
where
induct : ∀ {i} → Acc _>_ i → P i
induct {i} (acc rec) with view i
... | ‵fromℕ = Pₙ
... | ‵inject₁ j = Pᵢ₊₁⇒Pᵢ j (induct (rec _ inject₁[j]+1≤[j+1]))
where
inject₁[j]+1≤[j+1] : suc (toℕ (inject₁ j)) ≤ toℕ (suc j)
inject₁[j]+1≤[j+1] = ≤-reflexive (toℕ-inject₁ (suc j))
3 changes: 3 additions & 0 deletions src/Data/Fin/Properties.agda
Original file line number Diff line number Diff line change
Expand Up @@ -443,6 +443,9 @@ toℕ-inject {i = suc i} (suc j) = cong suc (toℕ-inject j)
-- inject₁
------------------------------------------------------------------------

fromℕ≢inject₁ : fromℕ n ≢ inject₁ j
fromℕ≢inject₁ {j = suc j} eq = fromℕ≢inject₁ {j = j} (suc-injective eq)

inject₁-injective : inject₁ i ≡ inject₁ j → i ≡ j
inject₁-injective {i = zero} {zero} i≡j = refl
inject₁-injective {i = suc i} {suc j} i≡j =
Expand Down
84 changes: 84 additions & 0 deletions src/Data/Fin/Relation/Unary/Top.agda
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
------------------------------------------------------------------------
-- The Agda standard library
--
-- The 'top' view of Fin
--
-- This is an example of a view of (elements of) a datatype,
-- here i : Fin (suc n), which exhibits every such i as
-- * either, i = fromℕ n
-- * or, i = inject₁ j for a unique j : Fin n
------------------------------------------------------------------------

{-# OPTIONS --cubical-compatible --safe #-}

module Data.Fin.Relation.Unary.Top where

open import Data.Nat.Base using (ℕ; zero; suc; _<_)
open import Data.Fin.Base using (Fin; zero; suc; toℕ; fromℕ; inject₁)
open import Data.Fin.Properties using (toℕ-fromℕ; toℕ-inject₁; inject₁ℕ<)
open import Relation.Binary.PropositionalEquality.Core
open import Relation.Nullary.Negation using (contradiction)

private
variable
n : ℕ
i : Fin (suc n)
j : Fin n

------------------------------------------------------------------------
-- The View, considered as a unary relation on Fin n

-- NB `Data.Fin.Properties.fromℕ≢inject₁` establishes that the following
-- inductively defined family on `Fin n` has constructors which target
-- *disjoint* instances of the family (moreover at indices `n = suc _`);
-- hence the interpretations of the View constructors will also be disjoint.

data View : (j : Fin n) → Set where
‵fromℕ : View (fromℕ n)
‵inj₁ : View j → View (inject₁ j)

pattern ‵inject₁ j = ‵inj₁ {j = j} _

-- The view covering function, witnessing soundness of the view

view-zero : ∀ n → View {suc n} zero
view-zero zero = ‵fromℕ
view-zero (suc n) = ‵inj₁ (view-zero n)

view : (j : Fin n) → View j
view zero = view-zero _
view (suc i) with view i
... | ‵fromℕ = ‵fromℕ
... | ‵inject₁ j = ‵inj₁ (view (suc j))

-- Interpretation of the view constructors

⟦_⟧ : {j : Fin n} → View j → Fin n
⟦ ‵fromℕ ⟧ = fromℕ _
⟦ ‵inject₁ j ⟧ = inject₁ j

-- Completeness of the view

view-complete : (v : View j) → ⟦ v ⟧ ≡ j
view-complete ‵fromℕ = refl
view-complete (‵inj₁ _) = refl

-- 'Computational' behaviour of the covering function

view-fromℕ : ∀ n → view (fromℕ n) ≡ ‵fromℕ
view-fromℕ zero = refl
view-fromℕ (suc n) rewrite view-fromℕ n = refl

view-inject₁ : (j : Fin n) → view (inject₁ j) ≡ ‵inj₁ (view j)
view-inject₁ zero = refl
view-inject₁ (suc j) rewrite view-inject₁ j = refl

-- Uniqueness of the view

view-unique : (v : View j) → view j ≡ v
view-unique ‵fromℕ = view-fromℕ _
view-unique (‵inj₁ {j = j} v) = begin
view (inject₁ j) ≡⟨ view-inject₁ j ⟩
‵inj₁ (view j) ≡⟨ cong ‵inj₁ (view-unique v) ⟩
‵inj₁ v ∎ where open ≡-Reasoning

89 changes: 89 additions & 0 deletions src/Data/Fin/Relation/Unary/Top/Instances.agda
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
------------------------------------------------------------------------
-- The Agda standard library
--
-- The 'top' view of Fin
--
-- This is an example of a view of (elements of) a datatype,
-- here i : Fin (suc n), which exhibits every such i as
-- * either, i = fromℕ n
-- * or, i = inject₁ j for a unique j : Fin n
------------------------------------------------------------------------

{-# OPTIONS --cubical-compatible --safe #-}

module Data.Fin.Relation.Unary.Top.Instances where
Copy link
Contributor

@MatthewDaggitt MatthewDaggitt Sep 12, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, my overall comment is that I'm not sure this is really a good match for instance search. Can you explain what the advantages of using instance search here are over simply applying the proofs manually? And why they're worth the decrease in the ability of the reader to comprehend the proofs?

Copy link
Contributor Author

@jamesmckinna jamesmckinna Sep 12, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See above: not sure that I can! UPDATED: but now see below?

The original rationale (sic) for the use of instances was again, to try to workaround (based on what I observed from the error messages ;-) the limitations of the typechecker arising from working --without-K, viz. the inability to unify type indices involving non-constructor-but-nevertheless-injective defined symbols (an important bug/feature of the otherwise ostensible use of 'green slime' in View types), and before I had even first heard of injectivity hints in lossy-unification (which I still don't quite understand how to use/exploit in such situations).

The View type constructors here mention 'green slime' in their indices, but nevertheless (as view witnesses!), define a provably-disjoint-and-total covering of the telescope of indices in the type... my deployment of instances was an idiomatic/idiosyncratic attempt to negotiate turning that 'provably-disjoint-and-total covering' into something the typechecker knows and can exploit.

Copy link
Contributor Author

@jamesmckinna jamesmckinna Sep 12, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Against that, I think that the example inject₁⁻¹ of inverting inject₁ in README.DATA.Fin.Relation.Unary.Top does mostly shine... only the example

inject₁≡⇒inject₁⁻¹≡ : (eq : inject₁ {n} j ≡ i) 
                       inject₁⁻¹ i {{inject₁≡⁺ {eq = eq}}} ≡ j

really fails in that regard?

To be more explicit: when we have a function with a partial inverse, long experience tells me it's actually a pain to have to explicitly supply a witness to its domain condition... you could say that I partly started on this development (besides wanting/needing the view for the Binomial Theorem) out of sheer frustration at the amount of wasted proof energy on checking the domain condition for lower₁, and the additional not-needed patterns involved in its definition, when the alternative, shown here, shows how the judicious use of views streamlines such definition/reasoning.

Mind you, it seems as though I perhaps have not been as successful in advocating for, or winning, this point, as I had first thought.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See most recent commits: I think I can now get more value out of (automatic) instance inference... but maybe that shows I still have much to learn about that! Specifically,

inject₁⁻¹-inject₁ : (j : Fin n)  inject₁⁻¹ (inject₁ j) ≡ j
inject₁⁻¹-inject₁ j rewrite view-inject₁ j = refl

inject₁≡⇒inject₁⁻¹≡ : (eq : inject₁ {n} j ≡ i)  let instance _ = inject₁≡⁺ eq in inject₁⁻¹ i ≡ j
inject₁≡⇒inject₁⁻¹≡ refl = inject₁⁻¹-inject₁ _

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re: your original question
I think it is now the case that the proofs of the properties of the inverse function now show off the use of instance inference as (originally) intended. I suppose your question might remain as to whether, in practice, a hypothetical user of these example programs might have trouble producing witnesses when they want to appeal to the inverse function. But actually, I don't think that would be the case, precisely because the ambient proof context should contain enough witnessing information (eg in the scope of a with based on a call to the view, or else through other explicit mention of inject₁ in the types of things) to know that it is safe to appeal to the inverse function without further ado?

Copy link
Contributor

@MatthewDaggitt MatthewDaggitt Sep 15, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the explanation. I follow your reasoning about why the view pattern is useful and strongly agree with it! However, I've downloaded the code and had a play with it. Unfortunately fundamentally I don't think the remaining instances are doing very much. All the places in README. .... .Top where you actually end up instantiating the instances, the required form holds definitionally.

You can actually see this in the way the instances are constructed, e.g. the only way to Agda can use instances search to find a proof of type IsInject₁ i is to have i actually be definitionally equal to inject₁ v for some v in the first place.

Furthermore, comparing the code in the README file for the properties inject₁⁻¹ vs the properties of lower₁ in Data.Fin.Properties, the latter are far more readable in my opinion.

Conclusion

I really like the view pattern, its neat and really useful, as witnessed by the nice proofs of opposite in the README file. However, I'm still of the opinion that the contents of Top.Instance is over-complicating things for minimal gain.

In the interests of getting the view merged in, I therefore propose that in this PR we remove Top.Instance and the inverting inject code in the README file, and then merge as is.

If you're still keen to push for the instance-based code, we can then have a in-depth follow up discussion (in a less asynchronous setting) about a second follow-up PR?


open import Data.Nat.Base using (ℕ; zero; suc; _<_)
open import Data.Fin.Base using (Fin; zero; suc; toℕ; fromℕ; inject₁)
open import Data.Fin.Properties using (toℕ-fromℕ; toℕ-inject₁; inject₁ℕ<)
open import Data.Fin.Relation.Unary.Top
open import Relation.Binary.PropositionalEquality.Core
open import Relation.Nullary.Negation using (contradiction)

private
variable
n : ℕ
i : Fin (suc n)
j : Fin n

------------------------------------------------------------------------
-- Experimental
--
-- Because we work --without-K, Agda's unifier will complain about
-- attempts to match `refl` against hypotheses of the form
-- `view {n} i ≡ v`
-- or gets stuck trying to solve unification problems of the form
-- (inferred index ≟ expected index)
-- even when these problems are *provably* solvable.
--
-- So the two predicates on values of the view defined below
-- are extensionally equivalent to the assertions
-- `view {n} i ≡ ‵fromℕ` and `view {n} i ≡ ‵inject₁ j`
--
-- But such assertions can only ever have a unique (irrelevant) proof
-- so we introduce instances to witness them, themselves given in
-- terms of the functions `view-fromℕ` and `view-inject₁` defined in
-- `Data.Fin.Relation.Unary.Top`

data IsFromℕ : View i → Set where
‵fromℕ : IsFromℕ (‵fromℕ {n})

instance

fromℕ⁺ : IsFromℕ (view (fromℕ n))
fromℕ⁺ {n = n} rewrite view-fromℕ n = ‵fromℕ

data IsInject₁ : View i → Set where
‵inj₁ : (v : View j) → IsInject₁ (‵inj₁ v)

instance

inject₁⁺ : IsInject₁ (view (inject₁ j))
inject₁⁺ {j = j} rewrite view-inject₁ j = ‵inj₁ _

inject₁≡⁺ : (eq : inject₁ j ≡ i) → IsInject₁ (view i)
inject₁≡⁺ refl = inject₁⁺

inject₁≢n⁺ : (n≢i : n ≢ toℕ (inject₁ i)) → IsInject₁ (view {suc n} i)
inject₁≢n⁺ {n} {i} n≢i with view i
... | ‵fromℕ = contradiction (sym i≡n) n≢i
where
open ≡-Reasoning
i≡n : toℕ (inject₁ (fromℕ n)) ≡ n
i≡n = begin
toℕ (inject₁ (fromℕ n)) ≡⟨ toℕ-inject₁ (fromℕ n) ⟩
toℕ (fromℕ n) ≡⟨ toℕ-fromℕ n ⟩
n ∎
... | ‵inj₁ v = ‵inj₁ v


------------------------------------------------------------------------
-- As corollaries, we obtain two useful properties, which are
-- witnessed by, but can also serve as proxy replacements for,
-- the corresponding properties in `Data.Fin.Properties`

view-fromℕ-toℕ : ∀ i → .{{IsFromℕ (view i)}} → toℕ i ≡ n
view-fromℕ-toℕ i with ‵fromℕ ← view i = toℕ-fromℕ _

view-inject₁-toℕ< : ∀ i → .{{IsInject₁ (view i)}} → toℕ i < n
view-inject₁-toℕ< i with ‵inject₁ j ← view i = inject₁ℕ< j