{"id":13993015,"url":"https://github.com/leanprover-community/quote4","last_synced_at":"2026-04-02T18:45:23.876Z","repository":{"id":45541571,"uuid":"365590674","full_name":"leanprover-community/quote4","owner":"leanprover-community","description":"Intuitive, type-safe expression quotations for Lean 4.","archived":false,"fork":false,"pushed_at":"2026-03-25T00:01:06.000Z","size":290,"stargazers_count":102,"open_issues_count":26,"forks_count":20,"subscribers_count":5,"default_branch":"master","last_synced_at":"2026-03-26T05:11:10.637Z","etag":null,"topics":["lean4"],"latest_commit_sha":null,"homepage":"","language":"Lean","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/leanprover-community.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,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2021-05-08T19:00:07.000Z","updated_at":"2026-03-24T23:36:07.000Z","dependencies_parsed_at":"2023-01-21T16:45:10.789Z","dependency_job_id":"9bdb8d0d-a5e3-4076-bb5d-0d69a5afbce2","html_url":"https://github.com/leanprover-community/quote4","commit_stats":null,"previous_names":["leanprover-community/quote4","gebner/quote4"],"tags_count":48,"template":false,"template_full_name":null,"purl":"pkg:github/leanprover-community/quote4","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/leanprover-community%2Fquote4","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/leanprover-community%2Fquote4/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/leanprover-community%2Fquote4/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/leanprover-community%2Fquote4/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/leanprover-community","download_url":"https://codeload.github.com/leanprover-community/quote4/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/leanprover-community%2Fquote4/sbom","scorecard":{"id":581978,"data":{"date":"2025-08-11","repo":{"name":"github.com/leanprover-community/quote4","commit":"f85ad59c9b60647ef736719c23edd4578f723806"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":4.5,"checks":[{"name":"Maintained","score":10,"reason":"15 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 10","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Code-Review","score":1,"reason":"Found 5/26 approved changesets -- score normalized to 1","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Warn: no topLevel permission defined: .github/workflows/build.yml:1","Info: no jobLevel write permissions found"],"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Pinned-Dependencies","score":0,"reason":"dependency not pinned by hash detected -- score normalized to 0","details":["Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/build.yml:19: update your workflow using https://app.stepsecurity.io/secureworkflow/leanprover-community/quote4/build.yml/master?enable=pin","Info:   0 out of   1 GitHub-owned GitHubAction dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: Apache License 2.0: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 30 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}}]},"last_synced_at":"2025-08-20T19:25:01.439Z","repository_id":45541571,"created_at":"2025-08-20T19:25:01.439Z","updated_at":"2025-08-20T19:25:01.439Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31313298,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-02T12:59:32.332Z","status":"ssl_error","status_checked_at":"2026-04-02T12:54:48.875Z","response_time":89,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5: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":["lean4"],"created_at":"2024-08-09T14:02:12.273Z","updated_at":"2026-04-02T18:45:23.853Z","avatar_url":"https://github.com/leanprover-community.png","language":"Lean","funding_links":[],"categories":["Lean","Core packages"],"sub_categories":[],"readme":"# Expression quotations for Lean 4\n\nThis package implements type-safe expression\nquotations, which are a particularly\nconvenient way of constructing object-level\nexpressions (`Expr`) in meta-level code.\n\nIt combines the intuitiveness of modal sequent\ncalculus with the power and speed of\nLean 4's metaprogramming facilities.\n\n## Show me some code!\n\n```lean\nimport Qq open Qq Lean\n\n-- Construct an expression\ndef a : Expr := q([42 + 1])\n\n-- Construct a typed expression\ndef b : Q(List Nat) := q([42 + 1])\n\n-- Antiquotations\ndef c (n : Q(Nat)) := q([42 + $n])\n\n-- Dependently-typed antiquotations\ndef d (u : Level) (n : Q(Nat)) (x : Q(Type u × Fin ($n + 1))) : Q(Fin ($n + 3)) :=\n  q(⟨$x.2, Nat.lt_of_lt_of_le $x.2.2 (Nat.le_add_right _ 2)⟩)\n\n-- Use `q()` to generate a large term in a regular definition\ndef add_self_37 {α : Type u} [Add α] (a : α) : α :=\n  by_elabq return (List.range 36).foldr (init := q($a)) fun _ acc =\u003e q($acc + $a)\n```\n\n## Typing rules\n\nThe `Q(·)` modality quotes types:\n`Q(α)` denotes an expression of type `α`.\nThe type former comes with the following\nnatural introduction rule:\n\n```\n$a₁ :   α₁,   …,  $aₙ :   αₙ   ⊢    t  : Type\n---------------------------------------------\n a₁ : Q(α₁),  …,   aₙ : Q(αₙ)  ⊢  Q(t) : Type\n```\n\nThe lower-case `q(·)` macro serves\nas the modal inference rule,\nallowing us to construct values in `Q(·)`:\n```\n$a₁ :   α₁,   …,  $aₙ :   αₙ   ⊢    t  :   β\n---------------------------------------------\n a₁ : Q(α₁),  …,   aₙ : Q(αₙ)  ⊢  q(t) : Q(β)\n```\n\n## Example\n\nLet us write a type-safe version of `mkApp`:\n\n```lean\nimport Qq\nopen Qq\n\nset_option trace.compiler.ir.result true in\n\n-- Note: `betterApp` actually has two additional parameters\n-- `{u v : Lean.Level}` auto-generated due to option\n-- `autoBoundImplicitLocal`.\n\ndef betterApp {α : Q(Sort u)} {β : Q($α → Sort v)}\n  (f : Q((a : α) → $β a)) (a : Q($α)) : Q($β $a) :=\nq($f $a)\n\n#eval betterApp q(Int.toNat) q(42)\n```\n\nThere are many things going on here:\n1. The `betterApp` function compiles to a single `betaRev` call.\n1. It does not require the `MetaM` monad (in contrast to\n   `AppBuilder.lean` in the Lean 4 code).\n1. `Q(…)` is definitionally equal to `Expr`, so each variable\n   in the example is just an `Expr`.\n1. Nevertheless, implicit arguments of the definition (such as `α`\n   or `u`) get filled in by type inference, which reduces the\n   potential for errors even in the absence of strong type safety\n   at the meta level.\n1. All quoted expressions, i.e. all code inside `Q(·)` and `q(·)`,\n   are type-safe (under the assumption that the values of `α`,\n   `f`, etc. really have their declared types).\n1. The second argument in the `#eval` example, `q(42)`,\n   correctly constructs an expression of type `Int`, as\n   determined by the first argument.\n\nBecause `betterApp`\ntakes `α` and `u` (and `β` and `v`) as arguments,\nit can also perform more interesting tasks compared\nto the untyped function `mkApp`: for example,\nwe can change `q($f $a)` into `q(id $f $a)`\nwithout changing the interface\n(even though the resulting expression\nnow contains both the type and the universe level).\n\nThe arguments do not need to refer\nto concrete types like `Int` either:\n`List ((u : Level) × (α : Q(Sort u)) × List Q(Option $α))`\ndoes what you think it does!\n\nIn fact it is a crucial feature\nthat we can write metaprograms\ntransforming terms of nonconcrete types\nin inconsistent contexts:\n```lean\ndef tryProve (n : Q(Nat)) (i : Q(Fin $n)) : Option Q($i \u003e 0) := ...\n```\nIf the `i \u003e 0` in the return type were a concrete type in the metalanguage,\nthen we could not call `tryProve` with `n := 0`\n(because we would need to provide a value for `i : Fin 0`).\nFurthermore,\nif `n` were a concrete value,\nthen we could not call `tryProve` on\nthe subterm `t` of `fun n : Nat =\u003e t`.\n\n## Implementation\n\nThe type family on which this package is built is called `QQ`:\n\n```lean\ndef QQ (α : Expr) := Expr\n```\n\nThe intended meaning of `e : QQ t` is that\n`e` is an expression of type `t`.\nOr if you will,\n`isDefEq (← inferType e) t`.\n(This invariant is not enforced though,\nbut it can be checked with `QQ.check`.)\nThe `QQ` type is not meant to be used manually.\nYou should only interact with it\nusing the `Q(·)` and `q(·)` macros.\n\n## Comparison\n\nTemplate Haskell provides a similar mechanism\nfor type-safe quotations,\nwriting `Q Int` for an expression of type `Int`.\nThis is subtly different\nto the `QQ` type family considered here:\nin Lean notation,\nTH's family has the type `Q : Type u → Type`,\nwhile ours has the type `QQ : Expr → Type`.\nIn Lean, `Q` is not sufficiently expressive\ndue to universe polymorphism:\nwe might only know at runtime which universe the type is in,\nbut `Q` version fixes the universe at compile time.\nAnother lack of expressivity concerns dependent types:\na telescope such as `{α : Q Type} (a : Q α)` is not well-typed\nwith TH's `Q` constructor,\nbecause `α` is not a type.\n\n## To do\n\n- This has almost certainly been done before\n  somewhere else, by somebody else.\n\n- `ql(imax u (v+1))`\n\n- Automatically create free variables for recursion.\n  Maybe something like this:\n```lean\ndef turnExistsIntoForall : Q(Prop) → MetaM Q(Prop)\n  | ~q(∃ x, $p x) =\u003e do\n     q(∀ x, $(x =\u003e turnExistsIntoForall q($p $x)))\n  | e =\u003e e\n```\n\n- Matching should provide control over type-class diamonds, such as\n```lean\n~q((a + b : α) where\n  Semiring α\n  commutes ∀ n, OfNat α n\n  a + a defEq 0)\n```\n\n- Matching on types should be possible, that is,\n  `match (e : Expr) with | ~q($p ∧ $q) =\u003e ...`.\n\n- Other bug fixes, documentation, and assorted polishing.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fleanprover-community%2Fquote4","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fleanprover-community%2Fquote4","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fleanprover-community%2Fquote4/lists"}