{"id":31942122,"url":"https://github.com/effectfully/ecc","last_synced_at":"2026-02-16T09:32:05.995Z","repository":{"id":25773409,"uuid":"29211712","full_name":"effectfully/ECC","owner":"effectfully","description":"A shallow embedding of Luo's ECC into Agda.","archived":false,"fork":false,"pushed_at":"2015-02-28T18:24:24.000Z","size":288,"stargazers_count":4,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-10-14T09:26:09.627Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Agda","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/effectfully.png","metadata":{"files":{"readme":"readme.agda","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-01-13T21:18:59.000Z","updated_at":"2019-08-08T12:29:29.000Z","dependencies_parsed_at":"2022-08-24T14:14:16.482Z","dependency_job_id":null,"html_url":"https://github.com/effectfully/ECC","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/effectfully/ECC","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/effectfully%2FECC","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/effectfully%2FECC/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/effectfully%2FECC/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/effectfully%2FECC/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/effectfully","download_url":"https://codeload.github.com/effectfully/ECC/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/effectfully%2FECC/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29504746,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-16T09:05:14.864Z","status":"ssl_error","status_checked_at":"2026-02-16T08:55:59.364Z","response_time":115,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-10-14T09:26:08.026Z","updated_at":"2026-02-16T09:32:05.980Z","avatar_url":"https://github.com/effectfully.png","language":"Agda","funding_links":[],"categories":[],"sub_categories":[],"readme":"module readme where\n\nopen import ECC.Main\nopen import Relation.Binary.PropositionalEquality\n\n-- # ECC-in-Agda\n\n-- This is an attempt to formalize [An Extended Calculus of Constructions]\n-- (citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.40.5883) in Agda.\n-- The development contains an impredicative universe, the `unit` type, that lies in it,\n-- natural numbers, infinite universe hierarchy, indexed by natural numbers,\n-- Sigma and Pi types, a bounded dependent quantifier\n-- and explicit liftings in the style of Agda's `Lift`, `lift` and `lower`,\n-- which are used to make the subsumption rule admissible.\n\n-- ## A quick taste\n\n-- Here is the `I` combinator:\n\n-- ```\nI : Term (type 0 Π λ A -\u003e A ⟶ A)\nI = ⇧ λ _ -\u003e ⇧ λ x -\u003e ↑ x\n-- ```\n\n-- Agda's `λ` is used as a binder, so the development doesn't contain De Bruijn indicies.\n\n-- `Π` is an infix operator. `⟶` is a non-dependent version of `Π`.\n\n-- `⇧` is a constructor of the `Term` datatype, that being applied to a function of type\n-- `(x : ᵀ⟦ A ⟧) -\u003e Term (B x)` returns a `Term (A Π B)` modulo wrapping-unwrapping.\n\n-- All semantic brackets like `ᵀ⟦_⟧` are functions from the defined datatypes to\n-- what they denote. For example we could define\n\n-- ```\n-- ᵀ⟦_⟧ : ∀ {α} -\u003e Type α -\u003e Set\n-- ...\n-- ᵀ⟦ unit  ⟧ = ⊤\n-- ᵀ⟦ A Π B ⟧ = (x : ᵀ⟦ A ⟧) -\u003e ᵀ⟦ B x ⟧\n-- ...\n-- ```\n\n-- (but `ᵀ⟦_⟧` is defined isomorphically in terms of more generic `≤⟦_⟧`).\n\n-- The `↑` constructor makes a `Term` from a plain Agda value (like `0` for example),\n-- a bound variable or a type (like `unit` for example), modulo wrapping again.\n\n-- Another common example is the `S` combinator:\n\n-- ```\nS : Term (type 0 Π λ A -\u003e (A ⟶ type 0) Π λ B -\u003e (A Π λ x -\u003e B x ⟶ type 0) Π λ C -\u003e\n      (A Π λ x -\u003e B x Π λ y -\u003e C x y) ⟶ (A Π λ x -\u003e B x) Π λ g -\u003e A Π λ x -\u003e C x (g x))\nS = ⇧ λ _ -\u003e ⇧ λ _ -\u003e ⇧ λ _ -\u003e ⇧ λ f -\u003e ⇧ λ g -\u003e ⇧ λ x -\u003e ↑ f · ↑ x · (↑ g · ↑ x)\n-- ```\n\n-- `_·_` is a dependent function application with the usual semantics.\n\n-- ## Basic types\n\n-- Here is how the `level` datatype is defined:\n\n-- ```\n-- data level : Set where\n--   # : ℕ -\u003e level\n--   ω : level\n-- ```\n\n-- The `#` constructor lifts a `ℕ` into a `level`. `ω` doesn't matter for now.\n\n-- The relevant part of the `Type` definition is\n\n-- ```\n-- data Type : level -\u003e Set\n\n-- Propᵀ : Set\n-- Propᵀ = Type (# 0)\n\n-- Typeᴺ : ℕ -\u003e Set\n-- Typeᴺ = Type ∘ # ∘ suc\n\n-- data Type where\n--   unit : Propᵀ\n--   ᵀℕ : Typeᴺ 0\n--   type : ∀ α -\u003e Typeᴺ α\n--   _Π_ : ∀ {α β} -\u003e (A : Type α) -\u003e (ᵀ⟦ A ⟧ -\u003e Type β) -\u003e Type (α ⊔ᵢ β)\n-- ```\n\n-- The impredicative universe is incorporated into the predicative one:\n\n-- ```\n-- type 0 : Type (# 1)\n-- type 1 : Type (# 2)\n-- ...\n-- type i : Type (# (suc i))\n-- ```\n\n-- and\n\n-- ```\n-- prop : Typeᴺ 0\n-- prop = type 0\n\n-- typeᴺ : ∀ α -\u003e Typeᴺ (suc α)\n-- typeᴺ = type ∘ suc \n-- ```\n\n-- A user doesn't see, that `prop` and `typeᴺ` are represented in terms of\n-- the same `type` constructor, since this constructor is renamed in the `ECC.Main` module\n-- to `universe` and `typeᴺ` is renamed to `type`.\n\n-- With this representation you don't need this three rules for subtyping:\n\n-- ```\n-- prop ≤ prop\n-- ∀ α -\u003e prop ≤ type α\n-- ∀ α' α -\u003e α' ≤ℕ α -\u003e type α' ≤ type α\n-- ```\n\n-- just the last one. It's also crucial for unification to have only one rule.\n\n-- One another option is to extend the `ℕ` datatype with the `-1` constant\n-- and to defined `prop = type -1` in the style of HoTT, but this breaks unification again.\n\n-- `ECC.Main` also renames `Type` to `Universe` and `Typeᴺ to Type`. Let's do some tests:\n\n-- ```\ntest-2 : Propᵀ\ntest-2 = unit\n\ntest-3 : Type 0\ntest-3 = ᵀℕ\n\ntest-4 : Type 1\ntest-4 = type 0\n-- ```\n\n-- The `_Π_` constructor is defined in terms of induction-recursion:\n\n-- ```\n-- _Π_ : ∀ {α β} -\u003e (A : Type α) -\u003e (ᵀ⟦ A ⟧ -\u003e Type β) -\u003e Type (α ⊔ᵢ β)\n-- ```\n\n-- `⟶` is a non-dependent version of `_Π_`:\n\n-- ```\n-- _⟶_  : ∀ {α β} -\u003e Type α -\u003e Type β -\u003e Type (α ⊔ᵢ β)\n-- A  ⟶ B = A  Π λ _ -\u003e B\n-- ```\n\n-- Random tests again:\n\n-- ```\ntest-5 : Propᵀ -- impredicativity here\ntest-5 = type 0 ⟶ unit\n\ntest-6 : Type 2\ntest-6 = (type 1 Π λ A -\u003e A) ⟶ ᵀℕ ⟶ type 0\n-- ```\n\n-- Recall that `ᵀ⟦_⟧` maps a value to its meaning:\n\n-- ```\ntest-7 : ᵀ⟦ ᵀℕ ⟧ ≡ ℕ\ntest-7 = refl\n\ntest-8 : ᵀ⟦ prop ⟧ ≡ Propᵀ\ntest-8 = refl\n\ntest-9 : ∀ α -\u003e ᵀ⟦ type α ⟧ ≡ Type α\ntest-9 _ = refl\n\ntest-10 : ∀ α -\u003e Type (suc α)\ntest-10 α = type α\n-- ```\n\n-- The last two examples show predicativity of the system.\n-- `type α : Type (suc α)` and `type α` evaluates to `Type α`,\n-- hence `Type α` is of type `Type (suc α)`.\n\n-- ## Tagging\n\n-- This datatype:\n\n-- ```\n-- record Tag {α β} {A : Set α} (B : (x : A) -\u003e Set β) (x : A) : Set (α ⊔ β) where\n--   constructor tag\n--   field el : B x\n-- open Tag public\n\n-- tagWith : ∀ {α β} {A : Set α} {B : (x : A) -\u003e Set β} -\u003e (x : A) -\u003e B x -\u003e Tag B x\n-- tagWith _ = tag\n-- ```\n\n-- is used pretty everywhere in the code. An example from the `ECC.Types.Level` module:\n\n-- ```\n-- _≤ℕ_ : ℕ -\u003e ℕ -\u003e Set\n-- 0     ≤ℕ _     = ⊤\n-- suc _ ≤ℕ 0     = ⊥\n-- suc n ≤ℕ suc m = n ≤ℕ m \n\n-- _≤ℕᵂ_ : ℕ -\u003e ℕ -\u003e Set\n-- n ≤ℕᵂ m = Tag (uncurry _≤ℕ_) (n , m)\n\n-- _⊔̂ℕᵢ_ : ∀ {n m p} -\u003e n ≤ℕᵂ p -\u003e m ≤ℕᵂ p -\u003e n ⊔ℕᵢ m ≤ℕᵂ p\n-- _⊔̂ℕᵢ_ {n} {m} (tag n≤p) (tag m≤p) = tag (⊔ℕᵢ-≤ℕ n {m} n≤p m≤p)\n-- ```\n\n-- `_≤ℕ_` is not a datatype ─ it's a function, so Agda can't infer `n` from `n ≤ℕ m`\n-- (she often can infer `m`, if `n` is known, but it's easier to just tag everything).\n-- If we define `_⊔̂ℕᵢ_` like\n\n-- ```\n-- _⊔̂ℕᵢ_ : ∀ {n m p} -\u003e n ≤ℕ p -\u003e m ≤ℕ p -\u003e n ⊔ℕᵢ m ≤ℕ p\n-- ```\n\n-- then we would need to explicitly pass `n` and `m` to every call to `_⊔̂ℕᵢ_`.\n-- A common tactic in this case is to wrap `_≤ℕ_` in an ad hoc record datatype,\n-- but I like this generic approach with tags more.\n\n-- ## Basic terms\n\n-- The relevant part of the `Term` definition is\n\n-- ```\n-- data Term : ∀ {α} -\u003e Type α -\u003e Set where\n--   ↑ : ∀ {α} {A : Type α} -\u003e ᵀ⟦ A ⟧ᵂ -\u003e Term A\n--   ⇧ : ∀ {α β} {A : Type α} {B : ᵀ⟦ A ⟧ -\u003e Type β}\n--     -\u003e ((x : ᵀ⟦ A ⟧ᵂ) -\u003e Term (B (el x)))\n--     -\u003e Term (A Π B)\n--   _·_ : ∀ {α β} {A : Type α} {B : ᵀ⟦ A ⟧ -\u003e Type β}\n--       -\u003e Term (A Π B) -\u003e (x : Term A) -\u003e Term (B ⟦ x ⟧)\n\n-- ⟦_⟧ : ∀ {α} {A : Type α} -\u003e Term A -\u003e ᵀ⟦ A ⟧\n-- ⟦ ↑ x      ⟧ = el x\n-- ⟦  ⇧ f     ⟧ = λ x -\u003e ⟦ f (tag x) ⟧\n-- ⟦ f  · x   ⟧ = ⟦ f ⟧ ⟦ x ⟧\n-- ```\n\n-- `ᵀ⟦_⟧ᵂ` is a tagged version of `ᵀ⟦_⟧`.\n-- There is induction-recursion again ─ in the definition of `_·_`.\n-- This all is a usual dependently typed stuff.\n\n-- Two auxuliary functions (the first is the special case of the second),\n-- that make `Terms` from plain Agda values are:\n\n-- ```\n-- -- That's how we get types at the value level.\n-- ↓ : ∀ {α} -\u003e Type (# α) -\u003e Term (type α)\n-- ↓ = ↑ ∘ tag\n\n-- plain : ∀ {α} {A : Type α} -\u003e ᵀ⟦ A ⟧ -\u003e Term A\n-- plain = ↑ ∘ tag\n-- ```\n\n-- A couple of basic examples:\n\n-- ```\ntest-11 : Term unit\ntest-11 = plain _\n\ntest-12 : Term prop\ntest-12 = ↓ unit\n-- ```\n\n-- The `A` combinator (`_$_` in Agda and Haskell) is\n\n-- ```\nA : Term (type 0\n          Π λ A -\u003e (A ⟶ type 0)\n          Π λ B -\u003e (A Π B)\n          Π λ f -\u003e A\n          Π λ x -\u003e B x)\nA = ⇧ λ _ -\u003e ⇧ λ _ -\u003e ⇧ λ f -\u003e ⇧ λ x -\u003e ↑ f · ↑ x\n-- ```\n\n-- We can encode `id $ 0` as follows:\n\n-- ```\ntest-13 : Term ᵀℕ\ntest-13 = A · ↑ _ · ↑ _ · (I · ↑ _) · plain 0\n-- ```\n\n-- It's also possible to use Agda's implicit arguments to remove these `↑ _`,\n-- but it doesn't matter for now.\n\n-- It is straightforward to define Church-encoded lists:\n\n-- ```\nList : Type 0 -\u003e Type 1\nList A = type 0 Π λ B -\u003e (A ⟶ B ⟶ B) ⟶ B ⟶ B\n\nnil : Term (type 0 Π λ A -\u003e List A)\nnil = ⇧ λ A -\u003e ⇧ λ B -\u003e ⇧ λ f -\u003e ⇧ λ z -\u003e ↑ z\n\nfoldr : Term (type 0 Π λ A -\u003e type 0 Π λ B -\u003e (A ⟶ B ⟶ B) ⟶ B ⟶ List A ⟶ B)\nfoldr = ⇧ λ A -\u003e ⇧ λ B -\u003e ⇧ λ f -\u003e ⇧ λ z -\u003e ⇧ λ xs -\u003e ↑ xs · ↑ B · ↑ f · ↑ z\n\ncons : Term (type 0 Π λ A -\u003e A ⟶ List A ⟶ List A)\ncons = ⇧ λ A -\u003e ⇧ λ x -\u003e ⇧ λ xs -\u003e ⇧ λ B -\u003e ⇧ λ f -\u003e ⇧ λ z -\u003e\n  ↑ f · ↑ x · (foldr · ↑ A · ↑ B · ↑ f · ↑ z · ↑ xs)\n\nsum : Term (List ᵀℕ ⟶ ᵀℕ)\nsum = foldr · ↑ _ · ↑ _ · plain _+_ · plain 0\n\ntest-14 : ⟦ sum · (cons · ↑ _ · plain 1 ·\n                  (cons · ↑ _ · plain 2 · \n                  (cons · ↑ _ · plain 3 ·\n                  (nil · ↑ _)))) ⟧ ≡ 6\ntest-14 = refl\n-- ```\n\n-- ## Universe polymorphism\n\n-- One another constructor of the `Type` datatype is\n\n-- ```\n-- _ℓΠ_ : ∀ {α} (A : Type α) {k : ᵀ⟦ A ⟧ -\u003e level} -\u003e (∀ x -\u003e Type (k x)) -\u003e Typeω\n-- ```\n\n-- Recall, how `_Π_` is defined:\n\n-- ```\n-- _Π_ : ∀ {α β} -\u003e (A : Type α) -\u003e (ᵀ⟦ A ⟧ -\u003e Type β) -\u003e Type (α ⊔ᵢ β)\n-- ```\n\n-- So in `A ℓΠ λ x -\u003e B x` a universe, where `B x` lies, depends on a value of type `A`.\n-- `Typeω` is a synonym for `Type ω`. This is just like in Agda.\n-- For example C-c C-d `∀ α -\u003e Set α` gives this error:\n\n-- ```\n-- 1,3-13\n-- Setω is not a valid type\n-- when checking that the expression ∀ α → Set α has type _690\n-- ```\n\n-- However there is no error in this development\n-- (I don't quite understand, why it appears in Agda):\n\n-- ```\ntest-15 : Typeω\ntest-15 = ᵀℕ ℓΠ λ α -\u003e type α\n-- ```\n\n-- The `Term` datatype contains corresponding constructors for\n-- universe polymorphic lambda abstraction and universe polymorphic function application:\n\n-- ```\n-- ℓ⇧ : ∀ {α} {A : Type α} {k : ᵀ⟦ A ⟧ -\u003e level} {B : (x : ᵀ⟦ A ⟧) -\u003e Type (k x)}\n--    -\u003e ((x : ᵀ⟦ A ⟧ᵂ) -\u003e Term (B (el x)))\n--    -\u003e Term (A ℓΠ B)\n-- _ℓ·_ : ∀ {α} {A : Type α} {k : ᵀ⟦ A ⟧ -\u003e level} {B : (x : ᵀ⟦ A ⟧) -\u003e Type (k x)}\n--      -\u003e Term (A ℓΠ B) -\u003e (x : Term A) -\u003e Term (B ⟦ x ⟧)\n-- ```\n\n-- It is straightforward to make the universe polymorphic `I` and `A` combinators:\n\n-- ```\nuI : Term (ᵀℕ ℓΠ λ α -\u003e type α Π λ A -\u003e A ⟶ A)\nuI = ℓ⇧ λ α -\u003e ⇧ λ A -\u003e ⇧ λ x -\u003e ↑ x\n\nuA : Term (ᵀℕ\n          ℓΠ λ α -\u003e ᵀℕ\n          ℓΠ λ β -\u003e type α\n           Π λ A -\u003e (A ⟶ type β)\n           Π λ B -\u003e (A Π B)\n           Π λ f -\u003e A\n           Π λ x -\u003e B x)\nuA = ℓ⇧ λ α -\u003e ℓ⇧ λ β -\u003e ⇧ λ A -\u003e ⇧ λ B -\u003e ⇧ λ f -\u003e ⇧ λ x -\u003e ↑ f · ↑ x\n-- ```\n\n-- This term corresponds to `id $ 0`\n\n-- ```\ntest-16 : Term ᵀℕ\ntest-16 = uA ℓ· ↑ _ ℓ· ↑ _ · ↑ _ · ↑ _ · (uI ℓ· ↑ _ · ↑ _) · plain 0 \n-- ```\n\n-- This term corresponds to `id $ ℕ`\n\n-- ```\ntest-17 : Term (type 0)\ntest-17 = uA ℓ· ↑ _ ℓ· ↑ _ · ↑ _ · ↑ _ · (uI ℓ· ↑ _ · ↑ _) · ↓ ᵀℕ\n-- ```\n\n-- This term corresponds to `id $ Set`\n\n-- ```\ntest-18 : Term (type 1)\ntest-18 = uA ℓ· ↑ _ ℓ· ↑ _ · ↑ _ · ↑ _ · (uI ℓ· ↑ _ · ↑ _) · ↓ (type 0)\n-- ```\n\n-- For a more complicated example see the `ECC.Tests.UniversePolymorphism` module.\n\n-- ## Subtyping\n\n-- Here is the bounded dependent quantifier:\n\n-- ```\n-- _≥Π_ : ∀ {α}\n--      -\u003e (A : Type α) {k : ∀ {α'} {A' : Type α'} -\u003e A' ≤ A -\u003e level}\n--      -\u003e (∀ {α'} {A' : Type α'} {le : A' ≤ A} -\u003e ≤⟦ le ⟧ᵂ -\u003e Type (k le))\n--      -\u003e Type (α ⊔ᵢ k (≤-refl A))\n-- ```\n\n-- Roughly, in `A ≥Π B` `B` receives a value of type `ᵀ⟦ A' ⟧`\n-- for all `A'`, such that `A' ≤ A`.\n-- However if we define `_≥Π_` in terms of `ᵀ⟦_⟧`, we would need to pattern-match on `A'`,\n-- which is universally quantified and hence unknown. That would make unification stuck.\n-- For example (remember, that `Type` was renamed to `Universe`):\n\n-- ```\npostulate\n  _≥Π'_ : ∀ {α}\n        -\u003e (A : Universe α) {k : ∀ {α'} {A' : Universe α'} -\u003e A' ≤ A -\u003e level}\n        -\u003e (∀ {α'} {A' : Universe α'} {le : A' ≤ A} -\u003e ᵀ⟦ A' ⟧ -\u003e Universe (k le))\n        -\u003e Universe (α ⊔ᵢ k (≤-refl A))\n\n-- test-19 : Type 1\n-- test-19 = type 0 ≥Π' λ A -\u003e {!!}\n-- ```\n\n-- The type of the hole is `Universe (_k_1034 .le)`. `A` in the hole has type `ᵀ⟦ .A' ⟧`.\n-- So we can't fill the hole with `A`. But we know, that `A` is of type `Universe α`\n-- for some `α`, since the only rule, that matches the `A' ≤ type α` pattern\n-- is `type α' ≤ type α`, and `type α'` evaluates to `Universe α'`.\n-- But with the definition, that uses `≤⟦_⟧`, there is no such problem:\n\n-- ```\ntest-19-ok : Type 1\ntest-19-ok = type 0 ≥Π λ A -\u003e el A\n-- ```\n\n-- Subtyping rules for basic cases are\n\n-- ```\n-- data _≤_ : ∀ {α' α} -\u003e Type α' -\u003e Type α -\u003e Set where\n--   ⊤≤⊤ : unit ≤ unit\n--   ℕ≤ℕ : ᵀℕ ≤ ᵀℕ\n--   ᵀ≤ᵀ : ∀ {α' α} {α'≤α : α' ≤ℕ α} -\u003e type α' ≤ type α\n--   Π≤Π : ∀ {α β' β} {A : Type α}\n--           {B' : ᵀ⟦ A ⟧ -\u003e Type β'}\n--           {B  : ᵀ⟦ A ⟧ -\u003e Type β }\n--       -\u003e (∀ x -\u003e B' x ≤ B x)\n--       -\u003e A Π B' ≤ A Π B\n-- ```\n\n-- There is no contravariance in the `Π≤Π` constructor.\n\n-- Here is how `≤⟦_⟧` defined for two trivial cases:\n\n-- ```\n-- ≤⟦_⟧ : ∀ {α' α} {A' : Type α'} {A : Type α} -\u003e A' ≤ A -\u003e Set\n-- ≤⟦_⟧      {A = unit  } _     = ⊤\n-- ≤⟦_⟧      {A = ᵀℕ    } _     = ℕ\n-- ```\n\n-- If `A' ≤ unit`, then `A' ≡ unit`, and `A'` evaluates to `⊤`.\n-- If `A' ≤ ᵀℕ  `, then `A' ≡ ᵀℕ  `, and `A'` evaluates to `ℕ`.\n\n-- More interesting case is\n\n-- ```\n-- ≤⟦_⟧ {α'} {A = type _} _     = Type (# (pred# α'))\n-- ```\n\n-- With `pred#` being\n\n-- ```\n-- pred# : level -\u003e ℕ\n-- pred# (# n) = pred n\n-- pred#  ω    = 0 -- Satisfying the totality checker\n-- ```\n\n-- I.e. if `A' : Type α'` and `A' ≤ type α`, then `A' ≡ type (pred# α')`\n-- due to the predicativity. Here is a proof (with the renamings):\n\n-- ```\nmodule mproof-1 where\n  open import Relation.Binary.HeterogeneousEquality\n  proof-1 : ∀ {α' α} {A' : Universe α'} -\u003e A' ≤ universe α -\u003e A' ≅ universe (pred# α')\n  proof-1 ᵀ≤ᵀ = refl\n-- ```\n\n-- And the `_Π_` case:\n\n-- ```\n-- ≤⟦_⟧      {A = A  Π _} le-Π  = (x : ᵀ⟦ A ⟧)   -\u003e ≤⟦ le-Π   Π· x ⟧\n-- ```\n\n-- `Π·` has complicated type, but its definition is simple:\n\n-- ```\n-- Π≤Π B'≤B Π· x = B'≤B x\n-- ```\n\n-- We cannot just write\n\n-- ```\n-- ≤⟦_⟧      {A = A  Π _} (Π≤Π B'≤B)  = (x : ᵀ⟦ A ⟧)   -\u003e ≤⟦ B'≤B x ⟧\n-- ```\n\n-- since it would force an argument of `≤⟦_⟧` to be in head weak normal form,\n-- making `≤⟦ le ⟧` stuck, when `le` is not in whnf.\n\n-- Bounded lambda abstraction and bounded function application are\n\n-- ```\n-- ≥⇧ : ∀ {α} {A : Type α} {k : ∀ {α'} {A' : Type α'} -\u003e A' ≤ A -\u003e level}\n--        {B : ∀ {α'} {A' : Type α'} {le : A' ≤ A} -\u003e ≤⟦ le ⟧ᵂ -\u003e Type (k le)}\n--    -\u003e (∀ {α'} {A' : Type α'} {le : A' ≤ A} -\u003e (x : ≤⟦ le ⟧ᵂ) -\u003e Term (B x))\n--    -\u003e Term (A ≥Π B)\n-- _≥·_ : ∀ {α' α} {A' : Type α'} {A : Type α} {le : A' ≤ A}\n--          {k : ∀ {α'} {A' : Type α'} -\u003e A' ≤ A -\u003e level}\n--          {B : ∀ {α'} {A' : Type α'} {le : A' ≤ A} -\u003e ≤⟦ le ⟧ᵂ -\u003e Type (k le)}\n--      -\u003e Term (A ≥Π B) -\u003e (x : ≤⟦ le ⟧ᵂ) -\u003e Term (B x)\n-- ```\n\n-- While bounded lambda abstraction follows the common pattern,\n-- bounded function application differs a bit.\n-- The second argument of `_≥·_` is not a `Term` like in other cases ─\n-- it's a tagged plain Agda value, e.g. `tagWith ℕ≤ℕ 0`.\n-- There is the `LeBasic` module, which fixes this,\n-- but it's totally untested and there are no utilities for this module for now.\n\n-- Some tests for subtyping:\n\n-- ```\nsI : Term (type 2 ≥Π λ A -\u003e el A ⟶ el A)\nsI = ≥⇧ λ A -\u003e ⇧ λ x -\u003e ↑ x\n\nsA : Term (type 2\n         ≥Π λ A -\u003e (el A ⟶ type 2)\n         ≥Π λ B -\u003e (el A Π el B)\n          Π λ f -\u003e el A\n          Π λ x -\u003e el B x)\nsA = ≥⇧ λ A -\u003e ≥⇧ λ B -\u003e ⇧ λ f -\u003e ⇧ λ x -\u003e ↑ f · ↑ x\n-- ```\n\n-- This term corresponds to `id $ 0`\n\n-- ```\ntest-20 : Term ᵀℕ\ntest-20 = sA\n       ≥· (tagWith ᵀ≤ᵀ ᵀℕ)\n       ≥· (tagWith (Π≤Π λ _ -\u003e ᵀ≤ᵀ) (λ _ -\u003e ᵀℕ))\n        · (sI ≥· tagWith ᵀ≤ᵀ ᵀℕ)\n        · plain 0\n-- ```\n\n-- This term corresponds to `id $ ℕ`\n\n-- ```\ntest-21 : Term (type 0)\ntest-21 = sA\n       ≥· (tagWith ᵀ≤ᵀ (type 0))\n       ≥· (tagWith (Π≤Π λ _ -\u003e ᵀ≤ᵀ) (λ _ -\u003e type 0))\n        · (sI ≥· tagWith ᵀ≤ᵀ (type 0))\n        · ↓ ᵀℕ\n-- ```\n\n-- This term corresponds to `id $ Set`\n\n-- ```\ntest-22 : Term (type 1)\ntest-22 = sA\n       ≥· (tagWith ᵀ≤ᵀ (type 1))\n       ≥· (tagWith (Π≤Π λ _ -\u003e ᵀ≤ᵀ) (λ _ -\u003e type 1))\n        · (sI ≥· tagWith ᵀ≤ᵀ (type 1))\n        · ↓ (type 0)\n-- ```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Feffectfully%2Fecc","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Feffectfully%2Fecc","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Feffectfully%2Fecc/lists"}