{"id":16313646,"url":"https://github.com/alhassy/gentle-intro-to-reflection","last_synced_at":"2026-01-24T10:03:17.405Z","repository":{"id":39845824,"uuid":"186654215","full_name":"alhassy/gentle-intro-to-reflection","owner":"alhassy","description":"A slow-paced introduction to reflection in Agda. ---Tactics!","archived":false,"fork":false,"pushed_at":"2022-05-25T01:25:28.000Z","size":59,"stargazers_count":101,"open_issues_count":0,"forks_count":9,"subscribers_count":5,"default_branch":"master","last_synced_at":"2025-04-24T04:38:23.099Z","etag":null,"topics":["agda","exercise","macro","proof-pattern","tactics","tutorial"],"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/alhassy.png","metadata":{"files":{"readme":"README.md","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":"2019-05-14T15:50:56.000Z","updated_at":"2025-03-27T03:12:01.000Z","dependencies_parsed_at":"2022-08-20T15:50:11.926Z","dependency_job_id":null,"html_url":"https://github.com/alhassy/gentle-intro-to-reflection","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/alhassy/gentle-intro-to-reflection","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alhassy%2Fgentle-intro-to-reflection","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alhassy%2Fgentle-intro-to-reflection/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alhassy%2Fgentle-intro-to-reflection/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alhassy%2Fgentle-intro-to-reflection/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/alhassy","download_url":"https://codeload.github.com/alhassy/gentle-intro-to-reflection/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alhassy%2Fgentle-intro-to-reflection/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28724374,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-24T08:27:05.734Z","status":"ssl_error","status_checked_at":"2026-01-24T08:27:01.197Z","response_time":89,"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":["agda","exercise","macro","proof-pattern","tactics","tutorial"],"created_at":"2024-10-10T21:51:55.052Z","updated_at":"2026-01-24T10:03:17.391Z","avatar_url":"https://github.com/alhassy.png","language":"Agda","funding_links":[],"categories":[],"sub_categories":[],"readme":"A slow-paced introduction to reflection in Agda. \u0026#x2014;Tactics!\n\n\u003cdiv class=\"org-center\"\u003e\n**Abstract**\n\u003c/div\u003e\n\n*One proof for two different theorems!*\n\nLet's learn how we can do that in Agda.\n\nThis tutorial is the result of mostly experimenting with the\n[documentation](https://agda.readthedocs.io/en/v2.5.2/language/reflection.html) on Agda's reflection mechanism, which essentially\nonly exposes the reflection interface and provides a few tiny examples.\nThe goal of this tutorial is to contain a diverse variety of examples,\nalong with occasional exercises for the reader.\n\nExamples include:\n\n-   String manipulation of built-in identifier names. 🍓\n-   Handy dandy combinators for AST formation: `𝓋𝓇𝒶, λ𝓋_↦_, …`. 🛠\n-   Numerous examples of quotation of terms and types. 🎯\n-   Wholesale derivation of singleton types for an example datatype,\n    along with derivable proofs 💛 🎵\n-   Automating proofs that are only `refl` *with* pattern matching 🏄\n-   Discussion of C-style macros in Agda 🌵\n-   Abstracting proofs patterns without syntactic overhead using macros 💪 🎼\n-   Remarks on what I could not do, possibly since it cannot be done :sob:\n\nEverything here works with Agda version 2.6.0.\nThis document is a literate Agda file written using\nthe (poorly coded) [org-agda](https://alhassy.github.io/literate/) framework.\n\nA pure `.agda` file can be found [here](tangled.agda).\n\n\n# Table of Contents\n\n1.  [Imports](#org0aa53a5)\n2.  [Introduction](#org93d5c28)\n3.  [`NAME` ─Type of known identifiers](#org8c7be7f)\n4.  [`Arg` ─Type of arguments](#org479222b)\n5.  [`Term` ─Type of terms](#orgc533d22)\n    1.  [Example: Simple Types](#org9e1b7a8)\n    2.  [Example: Simple Terms](#org5f8d00c)\n    3.  [A relationship between `quote` and `quoteTerm`](#org24877d0)\n    4.  [Example: Lambda Terms](#orgb235933)\n6.  [Metaprogramming with The Typechecking Monad `TC`](#org24401fa)\n7.  [Unquoting ─Making new functions \u0026 types](#org2291c5c)\n8.  [Sidequest: Avoid tedious `refl` proofs](#org9553964)\n9.  [Macros ─Abstracting Proof Patterns](#org17511af)\n    1.  [C-style macros](#orgce93e44)\n    2.  [Tedious Repetitive Proofs No More!](#org3df21e0)\n10. [Our First Real Proof Tactic](#orgf24bc9c)\n11. [Heuristic for Writing a Macro](#orge7318a1)\n12. [What about somewhere deep within a subexpression?](#org00976e8)\n\n\n# Imports\n\nFirst, some necessary imports:\n\n    module gentle-intro-to-reflection where\n\n    import Level as Level\n    open import Reflection hiding (name; Type)\n    open import Relation.Binary.PropositionalEquality hiding ([_])\n    open import Relation.Unary using (Decidable)\n    open import Relation.Nullary\n\n    open import Data.Unit\n    open import Data.Nat as Nat hiding (_⊓_)\n    open import Data.Bool\n    open import Data.Product\n    open import Data.List as List\n    open import Data.Char as Char\n    open import Data.String as String\n\n\n# Introduction\n\n*Reflection* is the ability to convert program code into an abstract syntax,\na data structure that can be manipulated like any other.\n\nConsider, for example, the tedium of writing a decidable equality for an enumerated type.\nBesides being tedious and error-prone, the inexpressibility of\nwhat should be a mechanically-derivable concept\nobscures the corresponding general principle underlying it, thus foregoing\nany machine assistance in ensuring any correctness or safety-ness guarantees.\nReflection allows a more economical and disciplined approach.\n\nIt is the aim of this tutorial to show how to get started with reflection in Agda.\nTo the best of my knowledge there is no up to date tutorial on this matter.\n\nThere are three main types in Agda's reflection mechanism:\n`Name, Arg, Term`. We will learn about them with the aid of\nthis following simple enumerated typed, as well as other standard types.\n\n    data RGB : Set where\n      Red Green Blue : RGB\n\n\n# `NAME` ─Type of known identifiers\n\n`Name` is the type of quoting identifiers, Agda names.\nElements of this type can be formed and pattern matched using\nthe `quote` keyword.\n\n    a-name : Name\n    a-name = quote ℕ\n\n    isNat : Name → Bool\n    isNat (quote ℕ) = true\n    isNat _         = false\n\n    -- bad : Set → Name\n    -- bad s = quote s  {- s is not known -}\n\n-   `NAME` comes equipped with equality, ordering, and a show function.\n-   Quote will not work on function arguments; the identifier must be known.\n\nLet's show names:\n\n    _ : showName (quote _≡_) ≡ \"Agda.Builtin.Equality._≡_\"\n    _ = refl\n\n    _ : showName (quote Red) ≡ \"gentle-intro-to-reflection.RGB.Red\"\n    _ = refl\n\nIt would be nice to have `Red` be shown as just `“RGB.Red”`.\n\nFirst, let's introduce some ‘programming’ helpers to treat Agda strings as if they\nwhere Haskell strings, and likewise to treat predicates as decidables.\n\n    {- Like “$” but for strings. -}\n    _⟨𝒮⟩_ : (List Char → List Char) → String → String\n    f ⟨𝒮⟩ s = fromList (f (toList s))\n\n    {- This should be in the standard library; I could not locate it. -}\n    toDec : ∀ {ℓ} {A : Set ℓ} → (p : A → Bool) → Decidable {ℓ} {A} (λ a → p a ≡ true)\n    toDec p x with p x\n    toDec p x | false = no λ ()\n    toDec p x | true = yes refl\n\nWe can now easily obtain the module's name, then drop it from the data constructor's name.\n\n    module-name : String\n    module-name = takeWhile (toDec (λ c → not (c Char.== '.'))) ⟨𝒮⟩ showName (quote Red)\n\n    _ : module-name ≡ \"gentle-intro-to-reflection\"\n    _ = refl\n\n    strName : Name → String\n    strName n = drop (1 + String.length module-name) ⟨𝒮⟩ showName n\n    {- The “1 +” is for the “.” seperator in qualified names. -}\n\n    _ : strName (quote Red) ≡ \"RGB.Red\"\n    _ = refl\n\n`NAME` essentially provides us with the internal representation of a known name,\nfor which we can query to obtain its definition or type.\nLater we will show how to get the type constructors of `ℕ` from its name.\n\n\n# `Arg` ─Type of arguments\n\nArguments in Agda may be hidden or computationally irrelevant.\nThis information is captured by the `Arg` type.\n\n    {- Arguments can be (visible), {hidden}, or ⦃instance⦄ -}\n    data Visibility : Set where\n      visible hidden instance′ : Visibility\n\n    {-Arguments can be relevant or irrelevant: -}\n    data Relevance : Set where\n      relevant irrelevant : Relevance\n\n    {- Visibility and relevance characterise the behaviour of an argument: -}\n    data ArgInfo : Set where\n      arg-info : (v : Visibility) (r : Relevance) → ArgInfo\n\n    data Arg (A : Set) : Set where\n      arg : (i : ArgInfo) (x : A) → Arg A\n\nFor example, let's create some helpers that make arguments of any given type `A`:\n\n    {- 𝓋isible 𝓇elevant 𝒶rgument -}\n    𝓋𝓇𝒶 : {A : Set} → A → Arg A\n    𝓋𝓇𝒶 = arg (arg-info visible relevant)\n\n    {- 𝒽idden 𝓇elevant 𝒶rgument -}\n    𝒽𝓇𝒶 : {A : Set} → A → Arg A\n    𝒽𝓇𝒶 = arg (arg-info hidden relevant)\n\nBelow are the variable counterparts, for the `Term` datatype,\nwhich will be discussed shortly.\n\n-   Variables are De Bruijn indexed and may be applied to a list of arguments.\n-   The index *n* refers to the argument that is *n* locations away from ‘here’.\n\n    {- 𝓋isible 𝓇elevant 𝓋ariable -}\n    𝓋𝓇𝓋 : (debruijn : ℕ) (args : List (Arg Term)) → Arg Term\n    𝓋𝓇𝓋 n args = arg (arg-info visible relevant) (var n args)\n\n    {- 𝒽idden 𝓇elevant 𝓋ariable -}\n    𝒽𝓇𝓋 : (debruijn : ℕ) (args : List (Arg Term)) → Arg Term\n    𝒽𝓇𝓋 n args = arg (arg-info hidden relevant) (var n args)\n\n\n# `Term` ─Type of terms\n\nWe use the `quoteTerm` keyword to turn a well-typed fragment of code\n\u0026#x2014;concrete syntax\u0026#x2014; into a value of the `Term` datatype \u0026#x2014;the abstract syntax.\nHere's the definition of `Term`:\n\n    data Term where\n\n      {- A variable has a De Bruijn index and may be applied to arguments. -}\n      var       : (x : ℕ)  (args : List (Arg Term)) → Term\n\n      {- Constructors and definitions may be applied to a list of arguments. -}\n      con       : (c : Name) (args : List (Arg Term)) → Term\n      def       : (f : Name) (args : List (Arg Term)) → Term\n\n      {- λ-abstractions bind one varaible; “t” is the string name of the variable\n\talong with the body of the lambda.\n      -}\n      lam       : (v : Visibility) (t : Abs Term) → Term  {- Abs A  ≅  String × A -}\n      pat-lam   : (cs : List Clause) (args : List (Arg Term)) → Term\n\n      {- Telescopes, or function types; λ-abstraction for types. -}\n      pi        : (a : Arg Type) (b : Abs Type) → Term\n\n      {- “Set n” or some term that denotes a type -}\n      agda-sort : (s : Sort) → Term\n\n      {- Metavariables; introduced via quoteTerm -}\n      meta      : (x : Meta) → List (Arg Term) → Term\n\n      {- Literal  ≅  ℕ | Word64 | Float | Char | String | Name | Meta -}\n      lit       : (l : Literal) → Term\n\n      {- Items not representable by this AST; e.g., a hole. -}\n      unknown   : Term {- Treated as '_' when unquoting. -}\n\n    data Sort where\n      set     : (t : Term) → Sort {- A Set of a given (possibly neutral) level. -}\n      lit     : (n : Nat) → Sort  {- A Set of a given concrete level. -}\n      unknown : Sort\n\n    data Clause where\n      clause        : (ps : List (Arg Pattern)) (t : Term) → Clause\n      absurd-clause : (ps : List (Arg Pattern)) → Clause\n\n\n## Example: Simple Types\n\nHere are three examples of “def”ined names, the first two do not take an argument.\nThe last takes a visible and relevant argument, 𝓋𝓇𝒶, that is a literal natural.\n\n    import Data.Vec as V\n    import Data.Fin as F\n\n    _ : quoteTerm ℕ ≡ def (quote ℕ) []\n    _ = refl\n\n    _ : quoteTerm V.Vec ≡ def (quote V.Vec) []\n    _ = refl\n\n    _ : quoteTerm (F.Fin 3) ≡ def (quote F.Fin) (𝓋𝓇𝒶 (lit (nat 3)) ∷ [])\n    _ = refl\n\n\n## Example: Simple Terms\n\nElementary numeric quotations:\n\n    _ : quoteTerm 1 ≡ lit (nat 1)\n    _ = refl\n\n    _ :    quoteTerm (suc zero)\n\t ≡ con (quote suc) (arg (arg-info visible relevant) (quoteTerm zero) ∷ [])\n    _ = refl\n\n    {- Using our helper 𝓋𝓇𝒶 -}\n    _ : quoteTerm (suc zero) ≡ con (quote suc) (𝓋𝓇𝒶 (quoteTerm zero) ∷ [])\n    _ = refl\n\nThe first example below demonstrates that `true` is a type “con”structor\nthat takes no arguments, whence the `[]`. The second example shows that\n`_≡_` is a defined name, not currently applied to any arguments.\nThe final example has propositional equality applied to two arguments.\n\n    _ : quoteTerm true ≡ con (quote true) []\n    _ = refl\n\n    _ : quoteTerm _≡_ ≡ def (quote _≡_) []\n    _ = refl\n\n    _ :   quoteTerm (\"b\" ≡ \"a\")\n\t≡ def (quote _≡_)\n\t  ( 𝒽𝓇𝒶 (def (quote Level.zero) [])\n\t  ∷ 𝒽𝓇𝒶 (def (quote String) [])\n\t  ∷ 𝓋𝓇𝒶 (lit (string \"b\"))\n\t  ∷ 𝓋𝓇𝒶 (lit (string \"a\")) ∷ [])\n    _ = refl\n\nNotice that a propositional equality actually has four arguments ─a level, a type, and two arguments─\nwhere the former two happen\nto be inferrable from the latter.\nHere is a more polymorphic example:\n\n    _ : ∀ {level : Level.Level}{Type : Set level} (x y : Type)\n\t→   quoteTerm (x ≡ y)\n\t   ≡ def (quote _≡_)\n\t       (𝒽𝓇𝓋 3 [] ∷ 𝒽𝓇𝓋 2 [] ∷ 𝓋𝓇𝓋 1 [] ∷ 𝓋𝓇𝓋 0 [] ∷ [])\n\n    _ = λ x y → refl\n\nRemember that a De Bruijn index `n` refers to the lambda variable\nthat is `n+1` lambdas away from its use site.\nFor example, `𝓋𝓇𝓋 1` means starting at the `⋯ ≡ ⋯`, go `1+1`\nlambdas away to get the variable `x`.\n\nWe will demonstrate an example of a section, say\n`≡_ \"b\"`, below when discussing lambda abstractions.\n\n\n## A relationship between `quote` and `quoteTerm`\n\nKnown names `𝒻` in a quoted term are denoted by a `quote 𝒻` in the AST representation.\n\nFor example ─I will use this 𝒻ℴ𝓃𝓉 for my postulated items─\n\n    postulate 𝒜 ℬ : Set\n    postulate 𝒻 : 𝒜 → ℬ\n    _ : quoteTerm 𝒻 ≡ def (quote 𝒻) []\n    _ = refl\n\nIn contrast, names that *vary* are denoted by a `var` constructor in the AST representation.\n\n    module _ {A B : Set} {f : A → B} where\n      _ : quoteTerm f ≡ var 0 []\n      _ = refl\n\n\n## Example: Lambda Terms\n\nFirst we show how reduction with lambdas works then we show how lambda functions\nare represented as `Term` values.\n\n`quoteTerm` typechecks and normalises its argument before yielding a `Term` value.\n\n    _ : quoteTerm ((λ x → x) \"nice\") ≡ lit (string \"nice\")\n    _ = refl\n\nEta-reduction happens, `f ≈ λ x → f x`.\n\n    id : {A : Set} → A → A\n    id x = x\n\n    _ :   quoteTerm (λ (x : ℕ) → id x)\n\t≡ def (quote id) (𝒽𝓇𝒶 (def (quote ℕ) []) ∷ [])\n    _ = refl\n\nNo delta-reduction happens; function definitions are not elaborated.\n\n    _ :   quoteTerm (id \"a\")\n\t≡ def (quote id)\n\t    (𝒽𝓇𝒶 (def (quote String) []) ∷  𝓋𝓇𝒶 (lit (string \"a\")) ∷ [])\n    _ = refl\n\nHere is a simple identity function on the Booleans.\nA “lam”bda with a “visible” “abs”tract argument named `\"x\"` is introduced\nhaving as body merely being the 0 nearest-bound variable, applied to an empty\nlist of arguments.\n\n    _ : quoteTerm (λ (x : Bool) → x) ≡ lam visible (abs \"x\" (var 0 []))\n    _ = refl\n\nHere is a more complicated lambda abstraction: Note that `f a` is represented as\nthe variable 0 lambdas away from the body applied to the variable 1 lambda away\nfrom the body.\n\n    _ : quoteTerm (λ (a : ℕ) (f : ℕ → ℕ) → f a)\n\t≡  lam visible (abs \"a\"\n\t     (lam visible (abs \"f\"\n\t       (var 0 (arg (arg-info visible relevant) (var 1 []) ∷ [])))))\n    _ = refl\n\nThis is rather messy, let's introduce some syntactic sugar to make it more readable.\n\n    infixr 5 λ𝓋_↦_  λ𝒽_↦_\n\n    λ𝓋_↦_  λ𝒽_↦_ : String → Term → Term\n    λ𝓋 x ↦ body  = lam visible (abs x body)\n    λ𝒽 x ↦ body  = lam hidden (abs x body)\n\nNow the previous example is a bit easier on the eyes:\n\n    _ :   quoteTerm (λ (a : ℕ) (f : ℕ → ℕ) → f a)\n\t≡ λ𝓋 \"a\" ↦ λ𝓋 \"f\" ↦ var 0 [ 𝓋𝓇𝒶 (var 1 []) ]\n    _ = refl\n\nUsing that delicious sugar, let's look at the constant function a number of ways.\n\n    _ : {A B : Set} →   quoteTerm (λ (a : A) (b : B) → a)\n\t\t      ≡ λ𝓋 \"a\" ↦ (λ𝓋 \"b\" ↦ var 1 [])\n    _ = refl\n\n    _ :  quoteTerm (λ {A B : Set} (a : A) (_ : B) → a)\n\t≡ (λ𝒽 \"A\" ↦ (λ𝒽 \"B\" ↦ (λ𝓋 \"a\" ↦ (λ𝓋 \"_\" ↦ var 1 []))))\n    _ = refl\n\n    const : {A B : Set} → A → B → A\n    const a _ = a\n\n    _ : quoteTerm const ≡ def (quote const) []\n    _ = refl\n\nFinally, here's an example of a section.\n\n    _ :   quoteTerm (_≡ \"b\")\n\t≡ λ𝓋 \"section\" ↦\n\t   (def (quote _≡_)\n\t    (𝒽𝓇𝒶 (def (quote Level.zero) []) ∷\n\t     𝒽𝓇𝒶 (def (quote String) []) ∷\n\t     𝓋𝓇𝒶 (var 0 []) ∷\n\t     𝓋𝓇𝒶 (lit (string \"b\")) ∷ []))\n    _ = refl\n\n\n# Metaprogramming with The Typechecking Monad `TC`\n\nThe `TC` monad provides an interface to Agda's type checker.\n\n    postulate\n      TC       : ∀ {a} → Set a → Set a\n      returnTC : ∀ {a} {A : Set a} → A → TC A\n      bindTC   : ∀ {a b} {A : Set a} {B : Set b} → TC A → (A → TC B) → TC B\n\nIn order to use `do`-notation we need to have the following definitions in scope.\n\n    _\u003e\u003e=_        : ∀ {a b} {A : Set a} {B : Set b} → TC A → (A → TC B) → TC B\n    _\u003e\u003e=_ = bindTC\n\n    _\u003e\u003e_        : ∀ {a b} {A : Set a} {B : Set b} → TC A → TC B → TC B\n    _\u003e\u003e_  = λ p q → p \u003e\u003e= (λ _ → q)\n\nThe primitives of `TC` can be seen on the [documentation](https://agda.readthedocs.io/en/v2.6.0/language/reflection.html#type-checking-computations) page; below are a few notable\nones that we may use. Other primitives include support for the current context,\ntype errors, and metavariables.\n\n    postulate\n      {- Take what you have and try to make it fit into the current goal. -}\n      unify : (have : Term) (goal : Term) → TC ⊤\n\n      {- Try first computation, if it crashes with a type error, try the second. -}\n      catchTC : ∀ {a} {A : Set a} → TC A → TC A → TC A\n\n      {- Infer the type of a given term. -}\n      inferType : Term → TC Type\n\n      {- Check a term against a given type. This may resolve implicit arguments\n\t in the term, so a new refined term is returned. Can be used to create\n\t new metavariables: newMeta t = checkType unknown t -}\n      checkType : Term → Type → TC Term\n\n      {- Compute the normal form of a term. -}\n      normalise : Term → TC Term\n\n      {- Quote a value, returning the corresponding Term. -}\n      quoteTC : ∀ {a} {A : Set a} → A → TC Term\n\n      {- Unquote a Term, returning the corresponding value. -}\n      unquoteTC : ∀ {a} {A : Set a} → Term → TC A\n\n      {- Create a fresh name. -}\n      freshName : String → TC Name\n\n      {- Declare a new function of the given type. The function must be defined\n\t later using 'defineFun'. Takes an Arg Name to allow declaring instances\n\t and irrelevant functions. The Visibility of the Arg must not be hidden. -}\n      declareDef : Arg Name → Type → TC ⊤\n\n      {- Define a declared function. The function may have been declared using\n\t 'declareDef' or with an explicit type signature in the program. -}\n      defineFun : Name → List Clause → TC ⊤\n\n      {- Get the type of a defined name. Replaces 'primNameType'. -}\n      getType : Name → TC Type\n\n      {- Get the definition of a defined name. Replaces 'primNameDefinition'. -}\n      getDefinition : Name → TC Definition\n\n      {-  Change the behaviour of inferType, checkType, quoteTC, getContext\n\t  to normalise (or not) their results. The default behaviour is no\n\t  normalisation. -}\n      withNormalisation : ∀ {a} {A : Set a} → Bool → TC A → TC A\n\n`TC` computations, or “metaprograms”, can be run by declaring them as macros or by\nunquoting. Let's begin with the former.\n\n\n# Unquoting ─Making new functions \u0026 types\n\nRecall our `RGB` example type was a simple enumeration consisting of `Red, Green, Blue`.\nConsider the singleton type:\n\n    data IsRed : RGB → Set where\n      yes : IsRed Red\n\nThe name `Red` completely determines this datatype; so let's try to generate it\nmechanically. Unfortunately, as far as I could tell, there is currently no way\nto unquote `data` declarations. As such, we'll settle for the following\nisomorphic functional formulation:\n\n    IsRed : RGB → Set\n    IsRed x = x ≡ Red\n\nFirst, let's quote the relevant parts, for readability.\n\n    “ℓ₀” : Arg Term\n    “ℓ₀” = 𝒽𝓇𝒶 (def (quote Level.zero) [])\n\n    “RGB” : Arg Term\n    “RGB” = 𝒽𝓇𝒶 (def (quote RGB) [])\n\n    “Red” : Arg Term\n    “Red” = 𝓋𝓇𝒶 (con (quote Red) [])\n\nThe first two have a nearly identical definition and it would be nice to\nmechanically derive them\u0026#x2026;\n\nAnyhow,\nwe use the `unquoteDecl` keyword, which allows us to obtain a `NAME` value, `IsRed`.\nWe then quote the desired type, declare a function of that type, then define it\nusing the provided `NAME`.\n\n    unquoteDecl IsRed =\n      do ty ← quoteTC (RGB → Set)\n\t declareDef (𝓋𝓇𝒶 IsRed) ty\n\t defineFun IsRed   [ clause [ 𝓋𝓇𝒶 (var \"x\") ] (def (quote _≡_) (“ℓ₀” ∷ “RGB” ∷ “Red” ∷ 𝓋𝓇𝓋 0 [] ∷ [])) ]\n\nLet's try out our newly declared type.\n\n    red-is-a-solution : IsRed Red\n    red-is-a-solution = refl\n\n    green-is-not-a-solution : ¬ (IsRed Green)\n    green-is-not-a-solution = λ ()\n\n    red-is-the-only-solution : ∀ {c} → IsRed c → c ≡ Red\n    red-is-the-only-solution refl = refl\n\nThere is a major problem with using `unquoteDef` outright like this:\nWe cannot step-wise refine our program using holes `?`, since that would\nresult in unsolved meta-variables. Instead, we split this process into two stages:\nA programming stage, then an unquotation stage.\n\n    {- Definition stage, we can use ‘?’ as we form this program. -}\n    define-Is : Name → Name → TC ⊤\n    define-Is is-name qcolour = defineFun is-name\n      [ clause [ 𝓋𝓇𝒶 (var \"x\") ] (def (quote _≡_) (“ℓ₀” ∷ “RGB” ∷ 𝓋𝓇𝒶 (con qcolour []) ∷ 𝓋𝓇𝓋 0 [] ∷ [])) ]\n\n    declare-Is : Name → Name → TC ⊤\n    declare-Is is-name qcolour =\n      do let η = is-name\n\t τ ← quoteTC (RGB → Set)\n\t declareDef (𝓋𝓇𝒶 η) τ\n\t defineFun is-name\n\t   [ clause [ 𝓋𝓇𝒶 (var \"x\") ]\n\t     (def (quote _≡_) (“ℓ₀” ∷ “RGB” ∷ 𝓋𝓇𝒶 (con qcolour []) ∷ 𝓋𝓇𝓋 0 [] ∷ [])) ]\n\n    {- Unquotation stage -}\n    IsRed′ : RGB → Set\n    unquoteDef IsRed′ = define-Is IsRed′ (quote Red)\n\n    {- Trying it out -}\n    _ : IsRed′ Red\n    _ = refl\n\nNotice that if we use “unquoteDef”, we must provide a type signature.\nWe only do so for illustration; the next code block avoids such a redundancy by\nusing “unquoteDecl”.\n\nThe above general approach lends itself nicely to the other data constructors as well:\n\n    unquoteDecl IsBlue  = declare-Is IsBlue  (quote Blue)\n    unquoteDecl IsGreen = declare-Is IsGreen (quote Green)\n\n    {- Example use -}\n    disjoint-rgb  : ∀{c} → ¬ (IsBlue c × IsGreen c)\n    disjoint-rgb (refl , ())\n\nThe next natural step is to avoid manually invoking `declare-Is` for each constructor.\nUnfortunately, it seems fresh names are not accessible, for some reason. 😢\n\nFor example, you would think the following would produce a function\nnamed `gentle-intro-to-reflection.identity`. Yet, it is not in scope.\nI even tried extracting the definition to its own file and no luck.\n\n    unquoteDecl {- identity -}\n      = do {- let η = identity -}\n\t   η ← freshName \"identity\"\n\t   τ ← quoteTC (∀ {A : Set} → A → A)\n\t   declareDef (𝓋𝓇𝒶 η) τ\n\t   defineFun η [ clause [ 𝓋𝓇𝒶 (var \"x\") ] (var 0 []) ]\n\n    {- “identity” is not in scope!?\n    _ : ∀ {x : ℕ}  →  identity x  ≡  x\n    _ = refl\n    -}\n\n**Exercises**:\n\n1.  Comment out the `freshName` line above and uncomment the surrounding artifacts to so that the above\n    unit test goes through.\n2.  Using that as a template, unquote a function `everywhere-0 : ℕ → ℕ` that is constantly 0.\n3.  Unquote the constant combinator `K : {A B : Set} → A → B → A`.\n\n    unquoteDecl everywhere-0\n      = do ⋯\n\n    _ : everywhere-0 3 ≡ 0\n    _ = refl\n\n    unquoteDecl K\n      = do ⋯\n\n    _ : K 3 \"cat\" ≡ 3\n    _ = refl\n\n**Bonus:** Proofs of a singleton type such as `IsRed` are essentially the same for all singleton types\nover `RGB`. Write, in two stages, a metaprogram that demonstrates each singleton type has a single member\n─c.f., `red-is-the-only-solution` from above. Hint: This question is as easy as the ones before it.\n\n    {- Programming stage }\n    declare-unique : Name → (RGB → Set) → RGB → TC ⊤\n    declare-unique it S colour =\n      = do ⋯\n\n    {- Unquotation stage -}\n    unquoteDecl red-unique = declare-unique red-unique IsRed Red\n    unquoteDecl green-unique = declare-unique green-unique IsGreen Green\n    unquoteDecl blue-unique = declare-unique blue-unique IsBlue Blue\n\n    {- Test -}\n    _ : ∀ {c} → IsGreen c → c ≡ Green\n    _ = green-unique\n\n\n# Sidequest: Avoid tedious `refl` proofs\n\nTime for a breather (•̀ᴗ•́)و\n\nLook around your code base for a function that makes explicit pattern matching, such as:\n\n    just-Red : RGB → RGB\n    just-Red Red   = Red\n    just-Red Green = Red\n    just-Red Blue  = Red\n\n    only-Blue : RGB → RGB\n    only-Blue Blue = Blue\n    only-Blue _   = Blue\n\nSuch functions have properties which cannot be proven unless we pattern match\non the arguments they pattern match. For example, that the above function is\nconstantly `Red` requires pattern matching then a `refl` for each clause.\n\n    just-Red-is-constant : ∀{c} → just-Red c ≡ Red\n    just-Red-is-constant {Red}   = refl\n    just-Red-is-constant {Green} = refl\n    just-Red-is-constant {Blue}  = refl\n\n    {- Yuck, another tedious proof -}\n    only-Blue-is-constant : ∀{c} → only-Blue c ≡ Blue\n    only-Blue-is-constant {Blue}  = refl\n    only-Blue-is-constant {Red}   = refl\n    only-Blue-is-constant {Green} = refl\n\nIn such cases, we can encode the general design decisions ---*pattern match and yield refl*\u0026#x2014;\nthen apply the schema to each use case.\n\nHere's the schema:\n\n    constructors : Definition → List Name\n    constructors (data-type pars cs) = cs\n    constructors _ = []\n\n    by-refls : Name → Term → TC ⊤\n    by-refls nom thm-you-hope-is-provable-by-refls\n     = let mk-cls : Name → Clause\n\t   mk-cls qcolour = clause [ 𝒽𝓇𝒶 (con qcolour []) ] (con (quote refl) [])\n       in\n       do let η = nom\n\t  δ ← getDefinition (quote RGB)\n\t  let clauses = List.map mk-cls (constructors δ)\n\t  declareDef (𝓋𝓇𝒶 η) thm-you-hope-is-provable-by-refls\n\t  defineFun η clauses\n\nHere's a use case.\n\n    _ : ∀{c} → just-Red c ≡ Red\n    _ = nice\n      where unquoteDecl nice = by-refls nice (quoteTerm (∀{c} → just-Red c ≡ Red))\n\nNote:\n\n1.  The first `nice` refers to the function\n    created by the RHS of the unquote.\n\n2.  The RHS `nice` refers to the Name value provided\n    by the LHS.\n\n3.  The LHS `nice` is a declaration of a Name value.\n\nThis is rather clunky since the theorem to be proven was repeated twice\n─repetition is a signal that something's wrong! In the next section we\nuse macros to avoid such repetiton, as well as the `quoteTerm` keyword.\n\nNote that we use a `where` clause since unquotation cannot occur in a `let`,\nfor some reason.\n\nHere's another use case of the proof pattern (•̀ᴗ•́)و\n\n    _ : ∀{c} → only-Blue c ≡ Blue\n    _ = nice\n      where unquoteDecl nice = by-refls nice (quoteTerm ∀{c} → only-Blue c ≡ Blue)\n\nOne proof pattern, multiple invocations!\nSuper neat stuff :grin:\n\n\n# Macros ─Abstracting Proof Patterns\n\nMacros are functions of type `τ₀ → τ₁ → ⋯ → Term → TC ⊤` that are defined in a\n`macro` block. The last argument is supplied by the type checker and denotes\nthe “goal” of where the macro is placed: One generally unifies what they have\nwith the goal, what is desired in the use site.\n\nWhy the `macro` block?\n\n-   Metaprograms can be run in a term position.\n-   Without the macro block, we run computations using the `unquote` keyword.\n-   Quotations are performed automatically; e.g.,\n    if `f : Term → Name → Bool → Term → TC ⊤`\n    then an application `f u v w` desugars into\n    `unquote (f (quoteTerm u) (quote v) w)`.\n\n    No syntactic overhead: Macros are applied like normal functions.\n\nMacros cannot be recursive; instead one defines a recursive function outside the\nmacro block then has the macro call the recursive function.\n\n\n## C-style macros\n\nIn the C language one defines a macro, say, by `#define luckyNum 1972` then later uses\nit simply by the name `luckyNum`. Without macros, we have syntactic overhead using\nthe `unquote` keyword:\n\n    luckyNum₀ : Term → TC ⊤\n    luckyNum₀ h = unify h (quoteTerm 55)\n\n    num₀ : ℕ\n    num₀ = unquote luckyNum₀\n\nInstead, we can achieve C-style behaviour by placing our metaprogramming code within a `macro` block.\n\n    macro\n      luckyNum : Term → TC ⊤\n      luckyNum h = unify h (quoteTerm 55)\n\n    num : ℕ\n    num = luckyNum\n\nUnlike C, all code fragments must be well-defined.\n\n**Exercise:** Write a macro to always yield the first argument in a function.\nThe second example shows how it can be used to access implicit arguments\nwithout mentioning them :b\n\n    macro\n      first : Term → TC ⊤\n      first goal = ⋯\n\n    myconst : {A B : Set} → A → B → A\n    myconst = λ x → λ y → first\n\n    mysum : ({x} y : ℕ) → ℕ\n    mysum y = y + first\n\nC-style macros ─unifying against a concretely quoted term─ are helpful\nwhen learning reflection. For example, define a macro `use` that yields\ndifferent strings according to the shape of their input ─this exercise\nincreases familiarity with the `Term` type. Hint: Pattern match on the\nfirst argument ;-)\n\n    macro\n      use : Term → Term → TC ⊤\n      use = ⋯\n\n    {- Fully defined, no arguments. -}\n\n    2+2≈4 : 2 + 2 ≡ 4\n    2+2≈4 = refl\n\n    _ : use 2+2≈4 ≡ \"Nice\"\n    _ = refl\n\n    {- ‘p’ has arguments. -}\n\n    _ : {x y : ℕ} {p : x ≡ y} → use p ≡ \"WoahThere\"\n    _ = refl\n\n\n## Tedious Repetitive Proofs No More!\n\nSuppose we wish to prove that addition, multiplication, and exponentiation\nhave right units 0, 1, and 1 respectively. We obtain the following nearly identical\nproofs!\n\n    +-rid : ∀{n} → n + 0 ≡ n\n    +-rid {zero}  = refl\n    +-rid {suc n} = cong suc +-rid\n\n    *-rid : ∀{n} → n * 1 ≡ n\n    *-rid {zero}  = refl\n    *-rid {suc n} = cong suc *-rid\n\n    ^-rid : ∀{n} → n ^ 1 ≡ n\n    ^-rid {zero}  = refl\n    ^-rid {suc n} = cong suc ^-rid\n\nThere is clearly a pattern here screaming to be abstracted, let's comply ♥‿♥\n\nThe natural course of action in a functional language is to try a higher-order combinator:\n\n    {- “for loops” or “Induction for ℕ” -}\n    foldn : (P : ℕ → Set) (base : P zero) (ind : ∀ n → P n → P (suc n))\n\t  → ∀(n : ℕ) → P n\n    foldn P base ind zero    = base\n    foldn P base ind (suc n) = ind n (foldn P base ind n)\n\nNow the proofs are shorter:\n\n    _ : ∀ (x : ℕ) → x + 0 ≡ x\n    _ = foldn _ refl (λ _ → cong suc)    {- This and next two are the same -}\n\n    _ : ∀ (x : ℕ) → x * 1 ≡ x\n    _ = foldn _ refl (λ _ → cong suc)    {- Yup, same proof as previous -}\n\n    _ : ∀ (x : ℕ) → x ^ 1 ≡ x\n    _ = foldn _ refl (λ _ → cong suc)    {- No change, same proof as previous -}\n\nUnfortunately, we are manually copy-pasting the same proof *pattern*.\n\n\u003e When you see repetition, copy-pasting, know that there is room for improvement! (•̀ᴗ•́)و\n\u003e\n\u003e Don't repeat yourself!\n\nRepetition can be mitigated a number of ways, including typeclasses or metaprogramming, for example.\nThe latter requires possibly less thought and it's the topic of this article, so let's do that :smile:\n\n**Exercise**: Following the template of the previous exercises, fill in the missing parts below.\nHint: It's nearly the same level of difficulty as the previous exercises.\n\n    make-rid : (let A = ℕ) (_⊕_ : A → A → A) (e : A) → Name → TC ⊤\n    make-rid _⊕_ e nom\n     = do ⋯\n\n    _ : ∀{x : ℕ} → x + 0 ≡ x\n    _ = nice where unquoteDecl nice = make-rid _+_ 0 nice\n\nThere's too much syntactic overhead here, let's use macros instead.\n\n    macro\n      _trivially-has-rid_ : (let A = ℕ) (_⊕_ : A → A → A) (e : A) → Term → TC ⊤\n      _trivially-has-rid_ _⊕_ e goal\n       = do τ ← quoteTC (λ(x : ℕ) → x ⊕ e ≡ x)\n\t    unify goal (def (quote foldn)            {- Using foldn    -}\n\t      ( 𝓋𝓇𝒶 τ                                {- Type P         -}\n\t      ∷ 𝓋𝓇𝒶 (con (quote refl) [])            {- Base case      -}\n\t      ∷ 𝓋𝓇𝒶 (λ𝓋 \"_\" ↦ quoteTerm (cong suc))  {- Inductive step -}\n\t      ∷ []))\n\nNow the proofs have minimal repetition *and* the proof pattern is written only *once*:\n\n    _ : ∀ (x : ℕ) → x + 0 ≡ x\n    _ = _+_ trivially-has-rid 0\n\n    _ : ∀ (x : ℕ) → x * 1 ≡ x\n    _ = _*_ trivially-has-rid 1\n\n    _ : ∀ (x : ℕ) → x * 1 ≡ x\n    _ = _^_ trivially-has-rid 1\n\nNote we could look at the type of the goal, find the operator `_⊕_` and the unit;\nthey need not be passed in. Later we will see how to reach into the goal type\nand pull pieces of it out for manipulation (•̀ᴗ•́)و\n\nIt would have been ideal if we could have defined our macro without using `foldn`;\nI could not figure out how to do that. 😧\n\nBefore one abstracts a pattern into a macro, it's useful to have a few instances\nof the pattern beforehand. When abstracting, one may want to compare how we think\nversus how Agda's thinking. For example, you may have noticed that in the previous\nmacro, Agda normalised the expression `suc n + 0` into `suc (n + 0)` by invoking the definition\nof `_+_`. We may inspect the goal of a function with the `quoteGoal ⋯ in ⋯` syntax:\n\n    +-rid′ : ∀{n} → n + 0 ≡ n\n    +-rid′ {zero}  = refl\n    +-rid′ {suc n} = quoteGoal e in\n      let\n\tsuc-n : Term\n\tsuc-n = con (quote suc) [ 𝓋𝓇𝒶 (var 0 []) ]\n\n\tlhs : Term\n\tlhs = def (quote _+_) (𝓋𝓇𝒶 suc-n ∷ 𝓋𝓇𝒶 (lit (nat 0)) ∷ [])\n\n\t{- Check our understanding of what the goal is “e”. -}\n\t_ : e ≡ def (quote _≡_)\n\t\t     (𝒽𝓇𝒶 (quoteTerm Level.zero) ∷ 𝒽𝓇𝒶 (quoteTerm ℕ)\n\t\t     ∷ 𝓋𝓇𝒶 lhs ∷ 𝓋𝓇𝒶 suc-n ∷ [])\n\t_ = refl\n\n\t{- What does it look normalised. -}\n\t_ :   quoteTerm (suc (n + 0) ≡ n)\n\t     ≡ unquote λ goal → (do g ← normalise goal; unify g goal)\n\t_ = refl\n      in\n      cong suc +-rid′\n\nIt would be really nice to simply replace the last line by a macro, say `induction`.\nUnfortunately, for that I would need to obtain the name `+-rid′`, which as far as I could\ntell is not possible with the current reflection mechanism.\n\n\n# Our First Real Proof Tactic\n\nWhen we have a proof `p : x ≡ y` it is a nuisance to have to write `sym p` to prove `y ≡ x`\n─we have to remember which ‘direction’ `p`. Let's alleviate such a small burden, then use\nthe tools here to alleviate a larger burden later; namely, rewriting subexpressions.\n\nGiven `p : x ≡ y`, we cannot simply yield `def (quote sym) [ 𝓋𝓇𝒶 p ]` since `sym` actually\ntakes four arguments ─compare when we quoted `_≡_` earlier. Instead, we infer type of `p`\nto be, say, `quoteTerm (_≡_ {ℓ} {A} x y)`. Then we can correctly provide all the required arguments.\n\n    ≡-type-info : Term → TC (Arg Term × Arg Term × Term × Term)\n    ≡-type-info (def (quote _≡_) (𝓁 ∷ 𝒯 ∷ arg _ l ∷ arg _ r ∷ [])) = returnTC (𝓁 , 𝒯 , l , r)\n    ≡-type-info _ = typeError [ strErr \"Term is not a ≡-type.\" ]\n\nWhat if later we decided that we did not want a proof of `x ≡ y`, but rather of `x ≡ y`.\nIn this case, the orginal proof `p` suffices. Rather than rewriting our proof term, our\nmacro could try providing it if the symmetry application fails.\n\n    {- Syntactic sugar for trying a computation, if it fails then try the other one -}\n    try-fun : ∀ {a} {A : Set a} → TC A → TC A → TC A\n    try-fun = catchTC\n\n    syntax try-fun t f = try t or-else f\n\nWith the setup in hand, we can now form our macro:\n\n    macro\n      apply₁ : Term → Term → TC ⊤\n      apply₁ p goal = try (do τ ← inferType p\n\t\t\t      𝓁 , 𝒯 , l , r ← ≡-type-info τ\n\t\t\t      unify goal (def (quote sym) (𝓁 ∷ 𝒯 ∷ 𝒽𝓇𝒶 l ∷ 𝒽𝓇𝒶 r ∷ 𝓋𝓇𝒶 p ∷ [])))\n\t\t      or-else\n\t\t\t   unify goal p\n\nFor example:\n\n    postulate 𝓍 𝓎 : ℕ\n    postulate 𝓆 : 𝓍 + 2 ≡ 𝓎\n\n    {- Same proof yields two theorems! (งಠ_ಠ)ง -}\n    _ : 𝓎 ≡ 𝓍 + 2\n    _ = apply₁ 𝓆\n\n    _ : 𝓍 + 2 ≡ 𝓎\n    _ = apply₁ 𝓆\n\nLet's furnish ourselves with the ability to inspect the *produced* proofs.\n\n    {- Type annotation -}\n    syntax has A a = a ∶ A\n\n    has : ∀ (A : Set) (a : A) → A\n    has A a = a\n\nWe are using the ‘ghost colon’ obtained with input `\\:`.\n\nLet's try this on an arbitrary type:\n\n    woah : {A : Set} (x y : A) → x ≡ y → (y ≡ x) × (x ≡ y)\n    woah x y p = apply₁ p , apply₁ p\n\n      where -- Each invocation generates a different proof, indeed:\n\n      first-pf : (apply₁ p ∶ (y ≡ x)) ≡ sym p\n      first-pf = refl\n\n      second-pf : (apply₁ p ∶ (x ≡ y)) ≡ p\n      second-pf = refl\n\nIt is interesting to note that on non ≡-terms, `apply₁` is just a no-op.\nWhy might this be the case?\n\n    _ : ∀ {A : Set} {x : A} → apply₁ x ≡ x\n    _ = refl\n\n    _ : apply₁ \"huh\" ≡ \"huh\"\n    _ = refl\n\n**Exercise:** When we manually form a proof invoking symmetry we simply write, for example, `sym p`\nand the implict arguments are inferred. We can actually do the same thing here! We were a bit dishonest above. 👂\nRewrite `apply₁`, call it `apply₂, so that the ~try` block is a single, unparenthesised, `unify` call.\n\n**Exercise:** Extend the previous macro so that we can prove statements of the form `x ≡ x` regardless of what `p`\nproves. Aesthetics hint: `try_or-else_` doesn't need brackets in this case, at all.\n\n    macro\n      apply₃ : Term → Term → TC ⊤\n      apply₃ p goal = ⋯\n\n    yummah : {A : Set} {x y : A} (p : x ≡ y)  →  x ≡ y  ×  y ≡ x  ×  y ≡ y\n    yummah p = apply₃ p , apply₃ p , apply₃ p\n\n**Exercise:** Write the following seemingly silly macro.\nHint: You cannot use the `≡-type-info` method directly, instead you must invoke `getType` beforehand.\n\n    ≡-type-info′ : Name → TC (Arg Term × Arg Term × Term × Term)\n    ≡-type-info′ = ⋯\n\n    macro\n      sumSides : Name → Term → TC ⊤\n      sumSides n goal = ⋯\n\n    _ : sumSides 𝓆 ≡ 𝓍 + 2 + 𝓎\n    _ = refl\n\n**Exercise:** Write two macros, `left` and `right`, such that\n`sumSides q  ≡ left q + right q`, where `q` is a known name.\nThese two macros provide the left and right hand sides of the\n≡-term they are given.\n\n\n# Heuristic for Writing a Macro\n\nI have found the following stepwise refinement approach to be useful in constructing\nmacros. ─Test Driven Development in a proof-centric setting─\n\n1.  Write a no-op macro: `mymacro p goal = unify p goal`.\n2.  Write the test case `mymacro p ≡ p`.\n3.  Feel good, you've succeeded.\n4.  Alter the test ever so slightly to become closer to your goal.\n5.  The test now breaks, go fix it.\n6.  Go to step 3.\n\nFor example, suppose we wish to consider proofs `p` of expressions of the form `h x ≡ y`\nand our macro is intended to obtain the function `h`. We proceed as follows:\n\n1.  Postulate `x, y, h, p` so the problem is well posed.\n2.  Use the above approach to form a no-op macro.\n3.  Refine the test to `mymacro p ≡ λ e → 0` and refine the macro as well.\n4.  Refine the test to `mymacro p ≡ λ e → e` and refine the macro as well.\n5.  Eventually succeeded in passing the desired test `mymacro p ≡ λ e → h e`\n    ─then eta reduce.\n\n    Along the way, it may be useful to return the *string* name of `h`\n    or rewrite the test as `_≡_ {Level.zero} {ℕ → ℕ} (mymacro p) ≡ ⋯`.\n    This may provide insight on how to repair or continue with macro construction.\n\n6.  Throw away the postultes, one at a time, making them arguments declared in the test;\n    refine macro each time so the test continues to pass as each postulate is removed.\n    Each postulate removal may require existing helper functions to be altered.\n\n7.  We have considered function applications, then variable funcctions, finally\n    consider constructors. Ensure tests cover all these, for this particular problem.\n\n**Exercise:** Carry this through to produce the above discussed example macro, call it `≡-head`. To help you on your\nway, here is a useful function:\n\n    {- If we have “f $ args” return “f”. -}\n    $-head : Term → Term\n    $-head (var v args) = var v []\n    $-head (con c args) = con c []\n    $-head (def f args) = def f []\n    $-head (pat-lam cs args) = pat-lam cs []\n    $-head t = t\n\nWith the ability to obtain functions being applied in propositional equalities,\nwe can now turn to lifiting a proof from `x ≡ y` to suffice proving `f x ≡ f y`.\nWe start with the desired goal and use the stepwise refinement approach outlined\nearlier to arrive at:\n\n    macro\n      apply₄ : Term → Term → TC ⊤\n      apply₄ p goal = try (do τ ← inferType goal\n\t\t\t      _ , _ , l , r ← ≡-type-info τ\n\t\t\t      unify goal ((def (quote cong) (𝓋𝓇𝒶 ($-head l) ∷ 𝓋𝓇𝒶 p ∷ []))))\n\t\t      or-else unify goal p\n\n    _ : ∀ {x y : ℕ} {f : ℕ → ℕ} (p : x ≡ y)  → f x ≡ f y\n    _ = λ p → apply₄ p\n\n    _ : ∀ {x y : ℕ} {f g : ℕ → ℕ} (p : x ≡ y)\n\t→  x ≡ y\n\t-- →  f x ≡ g y {- “apply₄ p” now has a unification error ^_^ -}\n    _ = λ p → apply₄ p\n\n\n# What about somewhere deep within a subexpression?\n\nConsider,\n\n      suc X + (X * suc X + suc X)\n    ≡⟨ cong (λ it → suc X + it) (+-suc _ _) ⟩\n      suc X + suc (X * suc X + X)\n\nCan we find `(λ it → suc X + it)` mechanically ;-)\n\nUsing the same refinement apporach outlined earlier, we begin with the following\nworking code then slowly, one piece at a time, replace the whole thing with an\n`unquote (unify (quoteTerm ⋯workingCodeHere⋯))`. Then we push the `quoteTerm`\nfurther in as much as possible and construct the helper functions to make\nthis transation transpire.\n\n    open import Data.Nat.Properties\n    {- +-suc : ∀ m n → m + suc n ≡ suc (m + n) -}\n\n    test₀ : ∀ {m n k : ℕ} → k + (m + suc n) ≡ k + suc (m + n)\n    test₀ {m} {n} {k} = cong (k +_) (+-suc m n)\n\nLet's follow the aforementioned approach by starting out with some postulates.\n\n    postulate 𝒳 : ℕ\n    postulate 𝒢 : suc 𝒳 + (𝒳 * suc 𝒳 + suc 𝒳)  ≡  suc 𝒳 + suc (𝒳 * suc 𝒳 + 𝒳)\n\n    𝒮𝒳 : Arg Term\n    𝒮𝒳 = 𝓋𝓇𝒶 (con (quote suc) [ 𝓋𝓇𝒶 (quoteTerm 𝒳) ])\n\n    𝒢ˡ 𝒢ʳ : Term\n    𝒢ˡ = def (quote _+_) (𝒮𝒳 ∷ 𝓋𝓇𝒶 (def (quote _+_) (𝓋𝓇𝒶 (def (quote _*_) (𝓋𝓇𝒶 (quoteTerm 𝒳) ∷ 𝒮𝒳 ∷ [])) ∷ 𝒮𝒳 ∷ [])) ∷ [])\n    𝒢ʳ = def (quote _+_) (𝒮𝒳 ∷ 𝓋𝓇𝒶 (con (quote suc) [ 𝓋𝓇𝒶 (def (quote _+_) (𝓋𝓇𝒶 (def (quote _*_) (𝓋𝓇𝒶 (quoteTerm 𝒳) ∷ 𝒮𝒳 ∷ [])) ∷ 𝓋𝓇𝒶 (quoteTerm 𝒳) ∷ [])) ]) ∷ [])\n\nIt seems that the left and right sides of 𝒢 “meet” at `def (quote _+_) (𝒮𝒳 ∷ [])`:\nWe check the equality of the quoted operator, `_+_`, then recursively check the arguments.\nWhence the following naive algorithm:\n\n    {- Should definitely be in the standard library -}\n    ⌊_⌋ : ∀ {a} {A : Set a} → Dec A → Bool\n    ⌊ yes p ⌋ = true\n    ⌊ no ¬p ⌋ = false\n\n    import Agda.Builtin.Reflection as Builtin\n\n    _$-≟_ : Term → Term → Bool\n    con c args $-≟ con c′ args′ = Builtin.primQNameEquality c c′\n    def f args $-≟ def f′ args′ = Builtin.primQNameEquality f f′\n    var x args $-≟ var x′ args′ = ⌊ x Nat.≟ x′ ⌋\n    _ $-≟ _ = false\n\n    {- Only gets heads and as much common args, not anywhere deep. :'( -}\n    infix 5 _⊓_\n    {-# TERMINATING #-} {- Fix this by adding fuel (con c args) ≔ 1 + length args -}\n    _⊓_ : Term → Term → Term\n    l ⊓ r with l $-≟ r | l | r\n    ...| false | x | y = unknown\n    ...| true | var f args | var f′ args′ = var f (List.zipWith (λ{ (arg i!! t) (arg j!! s) → arg i!! (t ⊓ s) }) args args′)\n    ...| true | con f args | con f′ args′ = con f (List.zipWith (λ{ (arg i!! t) (arg j!! s) → arg i!! (t ⊓ s) }) args args′)\n    ...| true | def f args | def f′ args′ = def f (List.zipWith (λ{ (arg i!! t) (arg j!! s) → arg i!! (t ⊓ s) }) args args′)\n    ...| true | ll | _ = ll {- Left biased; using ‘unknown’ does not ensure idempotence. -}\n\nThe bodies have names involving `!!`, this is to indicate a location of improvement.\nIndeed, this naive algorithm ignores visibility and relevance of arguments ─far from ideal.\n\nJoyously this works!  😂\n\n    _ : 𝒢ˡ ⊓ 𝒢ʳ ≡ def (quote _+_) (𝒮𝒳 ∷ 𝓋𝓇𝒶 unknown ∷ [])\n    _ = refl\n\n    {- test using argument function 𝒶 and argument number X -}\n    _ : {X : ℕ} {𝒶 : ℕ → ℕ}\n      →\n\tlet gl = quoteTerm (𝒶 X + (X * 𝒶 X + 𝒶 X))\n\t    gr = quoteTerm (𝒶 X + 𝒶 (X * 𝒶 X + X))\n\tin gl ⊓ gr ≡ def (quote _+_) (𝓋𝓇𝒶 (var 0 [ 𝓋𝓇𝒶 (var 1 []) ]) ∷ 𝓋𝓇𝒶 unknown ∷ [])\n    _ = refl\n\nThe `unknown` terms are far from desirable ─we ought to replace them with sections; i.e., an anonoymous lambda.\nMy naive algorithm to achieve a section from a term containing ‘unknown’s is as follows:\n\n1.  Replace every `unknown` with a De Bruijn index.\n2.  Then, find out how many unknowns there are, and for each, stick an anonoymous lambda at the front.\n    -   Sticking a lambda at the front breaks existing De Bruijn indices, so increment them for each lambda.\n\nThere is clear inefficiency here, but I'm not aiming to be efficient, just believable to some degree.\n\n    {- ‘unknown’ goes to a variable, a De Bruijn index -}\n    unknown-elim : ℕ → List (Arg Term) → List (Arg Term)\n    unknown-elim n [] = []\n    unknown-elim n (arg i unknown ∷ xs) = arg i (var n []) ∷ unknown-elim (n + 1) xs\n    unknown-elim n (arg i (var x args) ∷ xs) = arg i (var (n + suc x) args) ∷ unknown-elim n xs\n    unknown-elim n (arg i x ∷ xs)       = arg i x ∷ unknown-elim n xs\n    {- Essentially we want: body(unknownᵢ)  ⇒  λ _ → body(var 0)\n       However, now all “var 0” references in “body” refer to the wrong argument;\n       they now refer to “one more lambda away than before”. -}\n\n    unknown-count : List (Arg Term) → ℕ\n    unknown-count [] = 0\n    unknown-count (arg i unknown ∷ xs) = 1 + unknown-count xs\n    unknown-count (arg i _ ∷ xs) = unknown-count xs\n\n    unknown-λ : ℕ → Term → Term\n    unknown-λ zero body = body\n    unknown-λ (suc n) body = unknown-λ n (λ𝓋 \"section\" ↦ body)\n\n    {- Replace ‘unknown’ with sections -}\n    patch : Term → Term\n    patch it@(def f args) = unknown-λ (unknown-count args) (def f (unknown-elim 0 args))\n    patch it@(var f args) = unknown-λ (unknown-count args) (var f (unknown-elim 0 args))\n    patch it@(con f args) = unknown-λ (unknown-count args) (con f (unknown-elim 0 args))\n    patch t = t\n\nPutting meet, `_⊓_`, and this `patch` together into a macro:\n\n    macro\n      spine : Term → Term → TC ⊤\n      spine p goal\n\t= do τ ← inferType p\n\t     _ , _ , l , r ← ≡-type-info τ\n\t     unify goal (patch (l ⊓ r))\n\nThe expected tests pass ─so much joy :joy:\n\n    _ : spine 𝒢 ≡ suc 𝒳 +_\n    _ = refl\n\n    module testing-postulated-functions where\n      postulate 𝒶 : ℕ → ℕ\n      postulate _𝒷_ : ℕ → ℕ → ℕ\n      postulate 𝓰 : 𝒶 𝒳  𝒷  𝒳  ≡  𝒶 𝒳  𝒷  𝒶 𝓍\n\n      _ : spine 𝓰 ≡ (𝒶 𝒳 𝒷_)\n      _ = refl\n\n    _ : {X : ℕ} {G : suc X + (X * suc X + suc X)  ≡  suc X + suc (X * suc X + X)}\n      → quoteTerm G ≡ var 0 []\n    _ = refl\n\nThe tests for `≡-head` still go through using `spine`\nwhich can thus be thought of as a generalisation ;-)\n\nNow the original problem is dealt with as a macro:\n\n    macro\n      apply₅ : Term → Term → TC ⊤\n      apply₅ p hole\n\t= do τ ← inferType hole\n\t     _ , _ , l , r ← ≡-type-info τ\n\t     unify hole ((def (quote cong)\n\t\t  (𝓋𝓇𝒶 (patch (l ⊓ r)) ∷ 𝓋𝓇𝒶 p ∷ [])))\n\nCurious, why in the following tests we cannot simply use `+-suc _ _`?\n\n    _ : suc 𝒳 + (𝒳 * suc 𝒳 + suc 𝒳)  ≡  suc 𝒳 + suc (𝒳 * suc 𝒳 + 𝒳)\n    _ = apply₅ (+-suc (𝒳 * suc 𝒳) 𝒳)\n\n    test : ∀ {m n k : ℕ} → k + (m + suc n) ≡ k + suc (m + n)\n    test {m} {n} {k} = apply₅ (+-suc m n)\n\nThis is super neat stuff ^\\_^\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Falhassy%2Fgentle-intro-to-reflection","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Falhassy%2Fgentle-intro-to-reflection","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Falhassy%2Fgentle-intro-to-reflection/lists"}