{"id":31942116,"url":"https://github.com/effectfully/generic","last_synced_at":"2026-02-16T20:35:55.640Z","repository":{"id":54811165,"uuid":"61040073","full_name":"effectfully/Generic","owner":"effectfully","description":"A library for doing generic programming in Agda","archived":false,"fork":false,"pushed_at":"2021-01-27T21:41:04.000Z","size":165,"stargazers_count":34,"open_issues_count":2,"forks_count":4,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-10-14T09:26:05.220Z","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":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/effectfully.png","metadata":{"files":{"readme":"readme.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2016-06-13T13:49:26.000Z","updated_at":"2025-08-26T06:29:06.000Z","dependencies_parsed_at":"2022-08-14T03:31:27.247Z","dependency_job_id":null,"html_url":"https://github.com/effectfully/Generic","commit_stats":null,"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/effectfully/Generic","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/effectfully%2FGeneric","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/effectfully%2FGeneric/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/effectfully%2FGeneric/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/effectfully%2FGeneric/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/effectfully","download_url":"https://codeload.github.com/effectfully/Generic/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/effectfully%2FGeneric/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29517617,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-16T18:37:19.720Z","status":"ssl_error","status_checked_at":"2026-02-16T18:36:46.920Z","response_time":115,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: 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:03.547Z","updated_at":"2026-02-16T20:35:55.612Z","avatar_url":"https://github.com/effectfully.png","language":"Agda","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Generic\n\nIt's a library for doing generic programming in Agda.\n\nThe library is tested with Agda-2.6.1 and Agda-2.6.1.2 and likely does not work with other versions of Agda.\n\n# A quick taste\n\nDeriving decidable equality for vectors:\n\n```\nopen import Data.Vec using (Vec) renaming ([] to []ᵥ; _∷_ to _∷ᵥ_)\n\ninstance VecEq : ∀ {n α} {A : Set α} {{aEq : Eq A}} -\u003e Eq (Vec A n)\nunquoteDef VecEq = deriveEqTo VecEq (quote Vec)\n\nxs : Vec ℕ 3\nxs = 2 ∷ᵥ 4 ∷ᵥ 1 ∷ᵥ []ᵥ\n\ntest₁ : xs ≟ xs ≡ yes refl\ntest₁ = refl\n\ntest₂ : xs ≟ (2 ∷ᵥ 4 ∷ᵥ 2 ∷ᵥ []ᵥ) ≡ no _\ntest₂ = refl\n```\n\nSame for `Data.Star`:\n\n```\nopen import Data.Star\n\ninstance StarEq : ∀ {i t} {I : Set i} {T : Rel I t} {i j}\n                    {{iEq : Eq I}} {{tEq : ∀ {i j} -\u003e Eq (T i j)}} -\u003e Eq (Star T i j)\nunquoteDef StarEq = deriveEqTo StarEq (quote Star)\n```\n\n# Internally\n\nDescriptions of constructors are defined as follows:\n\n```\nmutual\n  Binder : ∀ {ι} α β γ -\u003e Arg-info -\u003e ι ⊔ lsuc (α ⊔ β) ≡ γ -\u003e Set ι -\u003e Set γ\n  Binder α β γ i q I = Coerce q (∃ λ (A : Set α) -\u003e \u003c relevance i \u003e A -\u003e Desc I β)\n\n  data Desc {ι} (I : Set ι) β : Set (ι ⊔ lsuc β) where\n    var : I -\u003e Desc I β\n    π   : ∀ {α} i\n        -\u003e (q : α ≤ℓ β)\n        -\u003e Binder α β _ i (cong (λ αβ -\u003e ι ⊔ lsuc αβ) q) I\n        -\u003e Desc I β\n    _⊛_ : Desc I β -\u003e Desc I β -\u003e Desc I β\n```\n\nConstructors are interpreted in the way described in [Descriptions](http://effectfully.blogspot.com/2016/04/descriptions.html) (in the `CompProp` module). That `Coerce` stuff is elaborated in [Emulating cumulativity in Agda](http://effectfully.blogspot.com/2016/07/cumu.html).\n\nA description of a data type is a list of named constructors\n\n```\nrecord Data {α} (A : Set α) : Set α where\n  no-eta-equality\n  constructor packData\n  field\n    dataName  : Name\n    parsTele  : Type\n    indsTele  : Type\n    consTypes : List A\n    consNames : All (const Name) consTypes\n```\n\nFor regular data types `A` is instantiated to `Type`, for described data types `A` is instantiated to `Desc I β` for some `I` and `β`. Descriptions also store the name of an original data type and telescopes of types of parameters and indices. `Name` and `Type` come from the `Reflection` module.\n\nThere is a reflection machinery that allows to parse regular Agda data types into their described counterparts. An example from the [`Examples/ReadData.agda`](Examples/ReadData.agda) module:\n\n```\ndata D {α β} (A : Set α) (B : ℕ -\u003e Set β) : ∀ {n} -\u003e B n -\u003e List ℕ -\u003e Set (α ⊔ β) where\n  c₁ : ∀ {n} (y : B n) xs -\u003e A -\u003e D A B y xs\n  c₂ : ∀ {y : B 0} -\u003e (∀ {n} (y : B n) {{xs}} -\u003e D A B y xs) -\u003e List A -\u003e D A B y []\n\nD′ : ∀ {α β} (A : Set α) (B : ℕ -\u003e Set β) {n} -\u003e B n -\u003e List ℕ -\u003e Set (α ⊔ β)\nD′ = readData D\n\npattern c₁′ {n} y xs x = #₀  (relv n , relv y , relv xs , relv x , lrefl)\npattern c₂′ {y} r ys   = !#₁ (relv y , r , irrv ys , lrefl)\n\ninj : ∀ {α β} {A : Set α} {B : ℕ -\u003e Set β} {n xs} {y : B n} -\u003e D A B y xs -\u003e D′ A B y xs\ninj (c₁ y xs x) = c₁′ y xs x\ninj (c₂ r ys)   = c₂′ (λ y -\u003e inj (r y)) ys\n\noutj : ∀ {α β} {A : Set α} {B : ℕ -\u003e Set β} {n xs} {y : B n} -\u003e D′ A B y xs -\u003e D A B y xs\noutj (c₁′ y xs x) = c₁ y xs x\noutj (c₂′ r ys)   = c₂ (λ y -\u003e outj (r y)) ys\n```\n\nSo universe polymorphism is fully supported, as well as implicit and instance arguments, multiple (including single or none) parameters and indices, irrelevance (partly), higher-order inductive occurrences and you can define functions over described data types just like over the actual ones (though, [pattern synonyms are not equal in power to proper constructors](https://github.com/agda/agda/issues/2069)).\n\nThere is a generic procedure that allows to coerce elements of described data type to elements of the corresponding regular data types, e.g. `outj` can be defined as\n\n```\noutj : ∀ {α β} {A : Set α} {B : ℕ -\u003e Set β} {n xs} {y : B n} -\u003e D′ A B y xs -\u003e D A B y xs\noutj d = guncoerce d\n```\n\nInternally it's a bit of reflection sugar on top of a generic fold defined on described data types (the [`Function/FoldMono.agda`](Function/FoldMono.agda) module).\n\nIt's possible to coerce the other way around:\n\n```\nunquoteDecl foldD = deriveFoldTo foldD (quote D)\n\ninj : ∀ {α β} {A : Set α} {B : ℕ -\u003e Set β} {n xs} {y : B n} -\u003e D A B y xs -\u003e D′ A B y xs\ninj = gcoerce foldD\n```\n\n`foldD` is a derived (via reflection) indexed fold (like `foldr` on `Vec`) on `D`. The procedure that derives indexed folds for regular data types is in the [`Lib/Reflection/Fold.agda`](Lib/Reflection/Fold.agda) module.\n\n`D′` computes to the following term:\n\n```\nλ {.α} {.β} A B {n} z z₁ →\n  μ\n  (packData\n -- dataName\n   (quote D)\n -- parsTele\n   (implRelPi (pureDef (quote Level)) \"α\"\n    (implRelPi (pureDef (quote Level)) \"β\"\n     (explRelPi (sort (set (pureVar 1))) \"A\"\n      (explRelPi (pureDef (quote ℕ) ‵→ sort (set (pureVar 2))) \"B\"\n       unknown))))\n -- indsTele\n   (implRelPi (pureDef (quote ℕ)) \"n\"\n    (appVar 1 (explRelArg (pureVar 0) ∷ []) ‵→\n     appDef (quote List)\n     (implRelArg (pureDef (quote lzero)) ∷\n      explRelArg (pureDef (quote ℕ)) ∷ [])\n     ‵→\n     sort\n     (set\n      (appDef (quote _⊔_)\n       (explRelArg (pureVar 5) ∷ explRelArg (pureVar 6) ∷ [])))))\n -- consTypes\n   (implRelDPi ℕ\n    (λ rx →\n       explRelDPi (B (unrelv rx))\n       (λ rx₁ →\n          explRelDPi (List ℕ)\n          (λ rx₂ →\n             explRelDPi A (λ rx₃ → var (unrelv rx , unrelv rx₁ , unrelv rx₂)))))\n    ∷\n    implRelDPi (B 0)\n    (λ rx →\n       implRelDPi ℕ\n       (λ rx₁ →\n          explRelDPi (B (unrelv rx₁))\n          (λ rx₂ →\n             instRelDPi (List ℕ)\n             (λ rx₃ → var (unrelv rx₁ , unrelv rx₂ , unrelv rx₃))))\n       ⊛ explIrrDPi (List A) (λ rx₁ → var (0 , unrelv rx , [])))\n    ∷ [])\n -- consNames\n   (quote c₁ , quote c₂ , tt))\n  (n , z , z₁)\n```\n\nActual generic programming happens in the [`Property`](Property) subfolder. There is generic decidable equality defined over described data types. It can be used like this:\n\n```\nxs : Vec (List (Fin 4)) 3\nxs = (fsuc fzero ∷ fzero ∷ [])\n   ∷ᵥ (fsuc (fsuc fzero) ∷ [])\n   ∷ᵥ (fzero ∷ fsuc (fsuc (fsuc fzero)) ∷ [])\n   ∷ᵥ []ᵥ\n\ntest : xs ≟ xs ≡ yes refl\ntest = refl\n```\n\nEquality for desribed `Vec`s, `List`s and `Fin`s is derived automatically.\n\nThe [`Property/Reify.agda`](Property/Reify.agda) module implements coercion from described data types to `Term`s. Since stored names of described constructors are taken from actual constructors, reified elements of described data types are actually quoted elements of regular data types and hence the former can be converted to the latter (like with `guncoerce`, but deeply and accepts only canonical forms):\n\n```\nrecord Reify {α} (A : Set α) : Set α where\n  field reify : A -\u003e Term\n\n  macro\n    reflect : A -\u003e Term -\u003e TC _\n    reflect = unify ∘ reify\nopen Reify {{...}} public\n\ninstance\n  DescReify : ∀ {i β} {I : Set i} {D : Desc I β} {j}\n                {{reD : All (ExtendReify ∘ proj₂) D}} -\u003e Reify (μ D j)\n  DescReify = ...\n\nopen import Generic.Examples.Data.Fin\nopen import Generic.Examples.Data.Vec\n\nopen import Data.Fin renaming (Fin to StdFin)\nopen import Data.Vec renaming (Vec to StdVec)\n\nxs : Vec (Fin 4) 3\nxs = fsuc (fsuc (fsuc fzero)) ∷ᵥ fzero ∷ᵥ fsuc fzero ∷ᵥ []ᵥ\n\nxs′ : StdVec (StdFin 4) 3\nxs′ = suc (suc (suc zero)) ∷ zero ∷ (suc zero) ∷ []\n\ntest : reflect xs ≡ xs′\ntest = refl\n```\n\nHaving decidable equality on `B` we can derive decidable equality on `A` if there is an injection `A ↦ B`. To construct an injection we need two functions `to : A -\u003e B`, `from : B -\u003e A` and a proof `from-to : from ∘ to ≗ id`. `to` and `from` are `gcoerce` and `guncoerce` from the above and `from-to` is another generic function (defined via reflection again, placed in [`Reflection/DeriveEq.agda`](Reflection/DeriveEq.agda): `fromToClausesOf` generates clauses for it) which uses universe polymorphic n-ary [`cong`](https://github.com/effectfully/Generic/blob/master/Lib/Equality/Congn.agda) under the hood.\n\nThere are also generic `elim` in [`Function/Elim.agda`](Function/Elim.agda) (the idea is described in [Deriving eliminators of described data types](http://effectfully.blogspot.com/2016/06/deriving-eliminators-of-described-data.html) and `lookup` in [`Function/Lookup.agda`](Function/Lookup.agda) (broken currently).\n\n# Limitations\n\n- No support for mutually recursive data types. They can be supported, I just haven't implemented that.\n\n- No support for inductive-inductive or inductive-recursive data types. The latter [can be done](https://github.com/effectfully/random-stuff/blob/master/Desc/IRDesc.agda) at the cost of complicating the encoding.\n\n- No coinduction.\n\n- You can't describe a non-strictly positive data type. Yes, I think it's a limitation. I have [an idea](http://effectfully.blogspot.ru/2016/10/insane-descriptions.html) about how non-strictly positive and inductive-inductive data types can be described (it doesn't give you a way to define safe things safely, but this probably can be added).\n\n- Records can be described (see [`Examples/Data/Product.agda`](Examples/Data/Product.agda`)), but η-laws don't hold for them, because constructors contain `lift refl : tt ≡ tt` and `(p q : tt ≡ tt) -\u003e p ≡ q` doesn't hold definitionally. `μ` is also a `data` rather than `record` (records confuse the termination checker, though, there are `{-# TERMINATING #-}` pragmas anyway), so this breaks η-expansion too.\n\n- Ornaments may or may not appear later (in the way described in [Unbiased ornaments](http://effectfully.blogspot.com/2016/07/unbiased-ornaments.html)). I don't find them very vital currently.\n\n- No forcing of indices. [`Lift`](Examples/Data/Lift.agda) can be described, though.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Feffectfully%2Fgeneric","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Feffectfully%2Fgeneric","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Feffectfully%2Fgeneric/lists"}