diff --git a/.github/workflows/nix-ci.yml b/.github/workflows/nix-ci.yml deleted file mode 100644 index dfe2b9088b..0000000000 --- a/.github/workflows/nix-ci.yml +++ /dev/null @@ -1,112 +0,0 @@ -name: Nix CI -on: - push: - branches: - - master - tags: - - '*' - pull_request: - merge_group: - -concurrency: - group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true - -jobs: - # see ci.yml - configure: - runs-on: ubuntu-latest - outputs: - matrix: ${{ steps.set-matrix.outputs.result }} - steps: - - name: Configure build matrix - id: set-matrix - uses: actions/github-script@v7 - with: - script: | - let large = ${{ github.repository == 'leanprover/lean4' }}; - let matrix = [ - { - "name": "Nix Linux", - "os": large ? "nscloud-ubuntu-22.04-amd64-8x8" : "ubuntu-latest", - } - ]; - console.log(`matrix:\n${JSON.stringify(matrix, null, 2)}`); - return matrix; - - Build: - needs: [configure] - runs-on: ${{ matrix.os }} - defaults: - run: - shell: nix run .#ciShell -- bash -euxo pipefail {0} - strategy: - matrix: - include: ${{fromJson(needs.configure.outputs.matrix)}} - # complete all jobs - fail-fast: false - name: ${{ matrix.name }} - env: - NIX_BUILD_ARGS: --print-build-logs --fallback - steps: - - name: Checkout - uses: actions/checkout@v4 - with: - # the default is to use a virtual merge commit between the PR and master: just use the PR - ref: ${{ github.event.pull_request.head.sha }} - - name: Set Up Nix Cache - uses: actions/cache@v4 - with: - path: nix-store-cache - key: ${{ matrix.name }}-nix-store-cache-${{ github.sha }} - # fall back to (latest) previous cache - restore-keys: | - ${{ matrix.name }}-nix-store-cache - save-always: true - - name: Further Set Up Nix Cache - shell: bash -euxo pipefail {0} - run: | - # Nix seems to mutate the cache, so make a copy - cp -r nix-store-cache nix-store-cache-copy || true - - name: Install Nix - uses: DeterminateSystems/nix-installer-action@main - with: - extra-conf: | - extra-sandbox-paths = /nix/var/cache/ccache? - substituters = file://${{ github.workspace }}/nix-store-cache-copy?priority=10&trusted=true https://cache.nixos.org - - name: Prepare CCache Cache - run: | - sudo mkdir -m0770 -p /nix/var/cache/ccache - sudo chown -R $USER /nix/var/cache/ccache - - name: Setup CCache Cache - uses: actions/cache@v4 - with: - path: /nix/var/cache/ccache - key: ${{ matrix.name }}-nix-ccache-${{ github.sha }} - # fall back to (latest) previous cache - restore-keys: | - ${{ matrix.name }}-nix-ccache - save-always: true - - name: Further Set Up CCache Cache - run: | - sudo chown -R root:nixbld /nix/var/cache - sudo chmod -R 770 /nix/var/cache - - name: Build - run: | - nix build $NIX_BUILD_ARGS .#cacheRoots -o push-build - - name: Test - run: | - nix build --keep-failed $NIX_BUILD_ARGS .#test -o push-test || (ln -s /tmp/nix-build-*/build/source/src/build ./push-test; false) - - name: Test Summary - uses: test-summary/action@v2 - with: - paths: push-test/test-results.xml - if: always() - continue-on-error: true - - name: Rebuild Nix Store Cache - run: | - rm -rf nix-store-cache || true - nix copy ./push-* --to file://$PWD/nix-store-cache?compression=none - - name: Fixup CCache Cache - run: | - sudo chown -R $USER /nix/var/cache diff --git a/README.md b/README.md index 613b1c5370..380b82e3df 100644 --- a/README.md +++ b/README.md @@ -2,20 +2,19 @@ This is the repository for **Lean 4**. # About -- [Quickstart](https://lean-lang.org/lean4/doc/quickstart.html) +- [Quickstart](https://lean-lang.org/documentation/setup/) - [Homepage](https://lean-lang.org) - [Theorem Proving Tutorial](https://lean-lang.org/theorem_proving_in_lean4/) - [Functional Programming in Lean](https://lean-lang.org/functional_programming_in_lean/) -- [Documentation Overview](https://lean-lang.org/lean4/doc/) +- [Documentation Overview](https://lean-lang.org/documentation/) - [Language Reference](https://lean-lang.org/doc/reference/latest/) - [Release notes](RELEASES.md) starting at v4.0.0-m3 -- [Examples](https://lean-lang.org/lean4/doc/examples.html) +- [Examples](https://lean-lang.org/documentation/examples/) - [External Contribution Guidelines](CONTRIBUTING.md) -- [FAQ](https://lean-lang.org/lean4/doc/faq.html) # Installation -See [Setting Up Lean](https://lean-lang.org/lean4/doc/setup.html). +See [Setting Up Lean](https://lean-lang.org/documentation/setup/). # Contributing @@ -23,4 +22,4 @@ Please read our [Contribution Guidelines](CONTRIBUTING.md) first. # Building from Source -See [Building Lean](https://lean-lang.org/lean4/doc/make/index.html) (documentation source: [doc/make/index.md](doc/make/index.md)). +See [Building Lean](doc/make/index.md). diff --git a/doc/README.md b/doc/README.md new file mode 100644 index 0000000000..a9c5e44352 --- /dev/null +++ b/doc/README.md @@ -0,0 +1,10 @@ +# Developer Documentation and Examples + +This directory contains documentation that describes how to work on +Lean itself, as well as examples that are included in documentation +that's hosted on the Lean website. The `make` directory contains +information on building Lean, and the `dev` directory describes how to +work on Lean. + +The [documentation section](https://lean-lang.org/documentation) has +links to documentation that describes how to use Lean itself. diff --git a/doc/SUMMARY.md b/doc/SUMMARY.md deleted file mode 100644 index d64479f494..0000000000 --- a/doc/SUMMARY.md +++ /dev/null @@ -1,46 +0,0 @@ -# Summary - -- [What is Lean](./whatIsLean.md) -- [Tour of Lean](./tour.md) -- [Setting Up Lean](./quickstart.md) - - [Extended Setup Notes](./setup.md) -- [Theorem Proving in Lean](./tpil.md) -- [Functional Programming in Lean](fplean.md) -- [Examples](./examples.md) - - [Palindromes](examples/palindromes.lean.md) - - [Binary Search Trees](examples/bintree.lean.md) - - [A Certified Type Checker](examples/tc.lean.md) - - [The Well-Typed Interpreter](examples/interp.lean.md) - - [Dependent de Bruijn Indices](examples/deBruijn.lean.md) - - [Parametric Higher-Order Abstract Syntax](examples/phoas.lean.md) - - [Syntax Examples](./syntax_examples.md) - - [Balanced Parentheses](./syntax_example.md) - - [Arithmetic DSL](./metaprogramming-arith.md) - -# Language Manual - -- [The Lean Reference Manual](./reference.md) - -# Other - -- [Frequently Asked Questions](./faq.md) -- [Significant Changes from Lean 3](./lean3changes.md) -- [Syntax Highlighting Lean in LaTeX](./syntax_highlight_in_latex.md) -- [User Widgets](examples/widgets.lean.md) -- [Semantic Highlighting](./semantic_highlighting.md) - -# Development - -- [Development Guide](./dev/index.md) -- [Building Lean](./make/index.md) - - [Ubuntu Setup](./make/ubuntu.md) - - [macOS Setup](./make/osx-10.9.md) - - [Windows MSYS2 Setup](./make/msys2.md) - - [Windows with WSL](./make/wsl.md) -- [Bootstrapping](./dev/bootstrap.md) -- [Testing](./dev/testing.md) -- [Debugging](./dev/debugging.md) -- [Commit Convention](./dev/commit_convention.md) -- [Release checklist](./dev/release_checklist.md) -- [Building This Manual](./dev/mdbook.md) -- [Foreign Function Interface](./dev/ffi.md) diff --git a/doc/alectryon.css b/doc/alectryon.css deleted file mode 100644 index 6481909ef9..0000000000 --- a/doc/alectryon.css +++ /dev/null @@ -1,786 +0,0 @@ -@charset "UTF-8"; -/* -Copyright © 2019 Clément Pit-Claudel - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. -*/ - -/*******************************/ -/* CSS reset for .alectryon-io */ -/*******************************/ - -.content { - /* - Use `initial` instead of `contents` to avoid a browser bug which removes - the element from the accessibility tree. - https://developer.mozilla.org/en-US/docs/Web/CSS/display#display_contents - */ - display: initial; -} - -.alectryon-io blockquote { - line-height: inherit; -} - -.alectryon-io blockquote:after { - display: none; -} - -.alectryon-io label { - display: inline; - font-size: inherit; - margin: 0; -} - -.alectryon-io a { - text-decoration: none !important; - font-style: oblique !important; - color: unset; -} - -/* Undo and
, added to improve RSS rendering. */ - -.alectryon-io small.alectryon-output, -.alectryon-io small.alectryon-type-info { - font-size: inherit; -} - -.alectryon-io blockquote.alectryon-goal, -.alectryon-io blockquote.alectryon-message { - font-weight: normal; - font-size: inherit; -} - -/***************/ -/* Main styles */ -/***************/ - -.alectryon-coqdoc .doc .code, -.alectryon-coqdoc .doc .comment, -.alectryon-coqdoc .doc .inlinecode, -.alectryon-mref, -.alectryon-block, .alectryon-io, -.alectryon-toggle-label, .alectryon-banner { - font-family: "Source Code Pro", Consolas, "Ubuntu Mono", Menlo, "DejaVu Sans Mono", monospace, monospace !important; - font-size: 0.875em; - font-feature-settings: "COQX" 1 /* Coq ligatures */, "XV00" 1 /* Legacy */, "calt" 1 /* Fallback */; - line-height: initial; -} - -.alectryon-io, .alectryon-block, .alectryon-toggle-label, .alectryon-banner { - overflow: visible; - overflow-wrap: break-word; - position: relative; - white-space: pre-wrap; -} - -/* -CoqIDE doesn't turn off the unicode bidirectional algorithm (and PG simply -respects the user's `bidi-display-reordering` setting), so don't turn it off -here either. But beware unexpected results like `Definition test_אב := 0.` - -.alectryon-io span { - direction: ltr; - unicode-bidi: bidi-override; -} - -In any case, make an exception for comments: - -.highlight .c { - direction: embed; - unicode-bidi: initial; -} -*/ - -.alectryon-mref, -.alectryon-mref-marker { - align-self: center; - box-sizing: border-box; - display: inline-block; - font-size: 80%; - font-weight: bold; - line-height: 1; - box-shadow: 0 0 0 1pt black; - padding: 1pt 0.3em; - text-decoration: none; -} - -.alectryon-block .alectryon-mref-marker, -.alectryon-io .alectryon-mref-marker { - user-select: none; - margin: -0.25em 0 -0.25em 0.5em; -} - -.alectryon-inline .alectryon-mref-marker { - margin: -0.25em 0.15em -0.25em 0.625em; /* 625 = 0.5em / 80% */ -} - -.alectryon-mref { - color: inherit; - margin: -0.5em 0.25em; -} - -.alectryon-goal:target .goal-separator .alectryon-mref-marker, -:target > .alectryon-mref-marker { - animation: blink 0.2s step-start 0s 3 normal none; - background-color: #fcaf3e; - position: relative; -} - -@keyframes blink { - 50% { - box-shadow: 0 0 0 3pt #fcaf3e, 0 0 0 4pt black; - z-index: 10; - } -} - -.alectryon-toggle, -.alectryon-io .alectryon-extra-goal-toggle { - display: none; -} - -.alectryon-bubble, -.alectryon-io label, -.alectryon-toggle-label { - cursor: pointer; -} - -.alectryon-toggle-label { - display: block; - font-size: 0.8em; -} - -.alectryon-io .alectryon-input { - padding: 0.1em 0; /* Enlarge the hitbox slightly to fill interline gaps */ -} - -.alectryon-io .alectryon-token { - white-space: pre-wrap; - display: inline; -} - -.alectryon-io .alectryon-sentence.alectryon-target .alectryon-input { - /* FIXME if keywords were ‘bolder’ we wouldn't need !important */ - font-weight: bold !important; /* Use !important to avoid a * selector */ -} - -.alectryon-bubble:before, -.alectryon-toggle-label:before, -.alectryon-io label.alectryon-input:after, -.alectryon-io .alectryon-goal > label:before { - border: 1px solid #babdb6; - border-radius: 1em; - box-sizing: border-box; - content: ''; - display: inline-block; - font-weight: bold; - height: 0.25em; - margin-bottom: 0.15em; - vertical-align: middle; - width: 0.75em; -} - -.alectryon-toggle-label:before, -.alectryon-io .alectryon-goal > label:before { - margin-right: 0.25em; -} - -.alectryon-io .alectryon-goal > label:before { - margin-top: 0.125em; -} - -.alectryon-io label.alectryon-input { - padding-right: 1em; /* Prevent line wraps before the checkbox bubble */ -} - -.alectryon-io label.alectryon-input:after { - margin-left: 0.25em; - margin-right: -1em; /* Compensate for the anti-wrapping space */ -} - -.alectryon-failed { - /* Underlines are broken in Chrome (they reset at each element boundary)… */ - /* text-decoration: red wavy underline; */ - /* … but it isn't too noticeable with dots */ - text-decoration: red dotted underline; - text-decoration-skip-ink: none; - /* Chrome prints background images in low resolution, yielding a blurry underline */ - /* background: bottom / 0.3em auto repeat-x url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyLjY0NiAxLjg1MiIgaGVpZ2h0PSI4IiB3aWR0aD0iMTAiPjxwYXRoIGQ9Ik0wIC4yNjVjLjc5NCAwIC41MyAxLjMyMiAxLjMyMyAxLjMyMi43OTQgMCAuNTMtMS4zMjIgMS4zMjMtMS4zMjIiIGZpbGw9Im5vbmUiIHN0cm9rZT0icmVkIiBzdHJva2Utd2lkdGg9Ii41MjkiLz48L3N2Zz4=); */ -} - -/* Wrapping :hover rules in a media query ensures that tapping a Coq sentence - doesn't trigger its :hover state (otherwise, on mobile, tapping a sentence to - hide its output causes it to remain visible (its :hover state gets triggered. - We only do it for the default style though, since other styles don't put the - output over the main text, so showing too much is not an issue. */ -@media (any-hover: hover) { - .alectryon-bubble:hover:before, - .alectryon-toggle-label:hover:before, - .alectryon-io label.alectryon-input:hover:after { - background: #eeeeec; - } - - .alectryon-io label.alectryon-input:hover { - text-decoration: underline dotted #babdb6; - text-shadow: 0 0 1px rgb(46, 52, 54, 0.3); /* #2e3436 + opacity */ - } - - .alectryon-io .alectryon-sentence:hover .alectryon-output, - .alectryon-io .alectryon-token:hover .alectryon-type-info-wrapper, - .alectryon-io .alectryon-token:hover .alectryon-type-info-wrapper { - z-index: 2; /* Place hovered goals above .alectryon-sentence.alectryon-target ones */ - } -} - -.alectryon-toggle:checked + .alectryon-toggle-label:before, -.alectryon-io .alectryon-sentence > .alectryon-toggle:checked + label.alectryon-input:after, -.alectryon-io .alectryon-extra-goal-toggle:checked + .alectryon-goal > label:before { - background-color: #babdb6; - border-color: #babdb6; -} - -/* Disable clicks on sentences when the document-wide toggle is set. */ -.alectryon-toggle:checked + label + .alectryon-container label.alectryon-input { - cursor: unset; - pointer-events: none; -} - -/* Hide individual checkboxes when the document-wide toggle is set. */ -.alectryon-toggle:checked + label + .alectryon-container label.alectryon-input:after { - display: none; -} - -/* .alectryon-output is displayed by toggles, :hover, and .alectryon-target rules */ -.alectryon-io .alectryon-output { - box-sizing: border-box; - display: none; - left: 0; - right: 0; - position: absolute; - padding: 0.25em 0; - overflow: visible; /* Let box-shadows overflow */ - z-index: 1; /* Default to an index lower than that used by :hover */ -} - -.alectryon-io .alectryon-type-info-wrapper { - position: absolute; - display: inline-block; - width: 100%; -} - -.alectryon-io .alectryon-type-info-wrapper.full-width { - left: 0; - min-width: 100%; - max-width: 100%; -} - -.alectryon-io .alectryon-type-info .goal-separator { - height: unset; - margin-top: 0em; -} - -.alectryon-io .alectryon-type-info-wrapper .alectryon-type-info { - box-sizing: border-box; - bottom: 100%; - position: absolute; - /*padding: 0.25em 0;*/ - visibility: hidden; - overflow: visible; /* Let box-shadows overflow */ - z-index: 1; /* Default to an index lower than that used by :hover */ - white-space: pre-wrap !important; -} - -.alectryon-io .alectryon-type-info-wrapper .alectryon-type-info .alectryon-goal.alectryon-docstring { - white-space: pre-wrap !important; -} - -@media (any-hover: hover) { /* See note above about this @media query */ - .alectryon-io .alectryon-sentence:hover .alectryon-output:not(:hover) { - display: block; - } - - .alectryon-io.output-hidden .alectryon-sentence:hover .alectryon-output:not(:hover) { - display: none !important; - } - - .alectryon-io.type-info-hidden .alectryon-token:hover .alectryon-type-info-wrapper .alectryon-type-info, - .alectryon-io.type-info-hidden .alectryon-token:hover .alectryon-type-info-wrapper .alectryon-type-info { - /*visibility: hidden !important;*/ - } - - .alectryon-io .alectryon-token:hover .alectryon-type-info-wrapper .alectryon-type-info, - .alectryon-io .alectryon-token:hover .alectryon-type-info-wrapper .alectryon-type-info { - visibility: visible; - transition-delay: 0.5s; - } -} - -.alectryon-io .alectryon-sentence.alectryon-target .alectryon-output { - display: block; -} - -/* Indicate active (hovered or targeted) goals with a shadow. */ -.alectryon-io .alectryon-sentence:hover .alectryon-output:not(:hover) .alectryon-messages, -.alectryon-io .alectryon-sentence.alectryon-target .alectryon-output .alectryon-messages, -.alectryon-io .alectryon-sentence:hover .alectryon-output:not(:hover) .alectryon-goals, -.alectryon-io .alectryon-sentence.alectryon-target .alectryon-output .alectryon-goals, -.alectryon-io .alectryon-token:hover .alectryon-type-info-wrapper .alectryon-type-info { - box-shadow: 2px 2px 2px gray; -} - -.alectryon-io .alectryon-extra-goals .alectryon-goal .goal-hyps { - display: none; -} - -.alectryon-io .alectryon-extra-goals .alectryon-extra-goal-toggle:not(:checked) + .alectryon-goal label.goal-separator hr { - /* Dashes indicate that the hypotheses are hidden */ - border-top-style: dashed; -} - - -/* Show just a small preview of the other goals; this is undone by the - "extra-goal" toggle and by :hover and .alectryon-target in windowed mode. */ -.alectryon-io .alectryon-extra-goals .alectryon-goal .goal-conclusion { - max-height: 5.2em; - overflow-y: auto; - /* Combining ‘overflow-y: auto’ with ‘display: inline-block’ causes extra space - to be added below the box. ‘vertical-align: middle’ gets rid of it. */ - vertical-align: middle; -} - -.alectryon-io .alectryon-goals, -.alectryon-io .alectryon-messages { - background: #f6f7f6; - /*border: thin solid #d3d7cf; /* Convenient when pre's background is already #EEE */ - display: block; - padding: 0.25em; -} - -.alectryon-message::before { - content: ''; - float: right; - /* etc/svg/square-bubble-xl.svg */ - background: url("data:image/svg+xml,%3Csvg width='14' height='14' viewBox='0 0 3.704 3.704' xmlns='http://www.w3.org/2000/svg'%3E%3Cg fill-rule='evenodd' stroke='%23000' stroke-width='.264'%3E%3Cpath d='M.794.934h2.115M.794 1.463h1.455M.794 1.992h1.852'/%3E%3C/g%3E%3Cpath d='M.132.14v2.646h.794v.661l.926-.661h1.72V.14z' fill='none' stroke='%23000' stroke-width='.265'/%3E%3C/svg%3E") top right no-repeat; - height: 14px; - width: 14px; -} - -.alectryon-toggle:checked + label + .alectryon-container { - width: unset; -} - -/* Show goals when a toggle is set */ -.alectryon-toggle:checked + label + .alectryon-container label.alectryon-input + .alectryon-output, -.alectryon-io .alectryon-sentence > .alectryon-toggle:checked ~ .alectryon-output { - display: block; - position: static; - width: unset; - background: unset; /* Override the backgrounds set in floating in windowed mode */ - padding: 0.25em 0; /* Re-assert so that later :hover rules don't override this padding */ -} - -.alectryon-toggle:checked + label + .alectryon-container label.alectryon-input + .alectryon-output .goal-hyps, -.alectryon-io .alectryon-sentence > .alectryon-toggle:checked ~ .alectryon-output .goal-hyps { - /* Overridden back in windowed style */ - flex-flow: row wrap; - justify-content: flex-start; -} - -.alectryon-toggle:checked + label + .alectryon-container .alectryon-sentence .alectryon-output > div, -.alectryon-io .alectryon-sentence > .alectryon-toggle:checked ~ .alectryon-output > div { - display: block; -} - -.alectryon-io .alectryon-extra-goal-toggle:checked + .alectryon-goal .goal-hyps { - display: flex; -} - -.alectryon-io .alectryon-extra-goal-toggle:checked + .alectryon-goal .goal-conclusion { - max-height: unset; - overflow-y: unset; -} - -.alectryon-toggle:checked + label + .alectryon-container .alectryon-sentence > .alectryon-toggle ~ .alectryon-wsp, -.alectryon-io .alectryon-sentence > .alectryon-toggle:checked ~ .alectryon-wsp { - display: none; -} - -.alectryon-io .alectryon-messages, -.alectryon-io .alectryon-message, -.alectryon-io .alectryon-goals, -.alectryon-io .alectryon-goal, -.alectryon-io .goal-hyps > span, -.alectryon-io .goal-conclusion { - border-radius: 0.15em; -} - -.alectryon-io .alectryon-goal, -.alectryon-io .alectryon-message { - align-items: center; - background: #f6f7f6; - border: 0em; - display: block; - flex-direction: column; - margin: 0.25em; - padding: 0.5em; - position: relative; -} - -.alectryon-io .goal-hyps { - align-content: space-around; - align-items: baseline; - display: flex; - flex-flow: column nowrap; /* re-stated in windowed mode */ - justify-content: space-around; - /* LATER use a ‘gap’ property instead of margins once supported */ - margin: -0.15em -0.25em; /* -0.15em to cancel the item spacing */ - padding-bottom: 0.35em; /* 0.5em-0.15em to cancel the 0.5em of .goal-separator */ -} - -.alectryon-io .goal-hyps > br { - display: none; /* Only for RSS readers */ -} - -.alectryon-io .goal-hyps > span, -.alectryon-io .goal-conclusion { - /*background: #eeeeec;*/ - display: inline-block; - padding: 0.15em 0.35em; -} - -.alectryon-io .goal-hyps > span { - align-items: baseline; - display: inline-flex; - margin: 0.15em 0.25em; -} - -.alectryon-block var, -.alectryon-inline var, -.alectryon-io .goal-hyps > span > var { - font-weight: 600; - font-style: unset; -} - -.alectryon-io .goal-hyps > span > var { - /* Shrink the list of names, but let it grow as long as space is available. */ - flex-basis: min-content; - flex-grow: 1; -} - -.alectryon-io .goal-hyps > span b { - font-weight: 600; - margin: 0 0 0 0.5em; - white-space: pre; -} - -.alectryon-io .hyp-body, -.alectryon-io .hyp-type { - display: flex; - align-items: baseline; -} - -.alectryon-io .goal-separator { - align-items: center; - display: flex; - flex-direction: row; - height: 1em; /* Fixed height to ignore goal name and markers */ - margin-top: -0.5em; /* Compensated in .goal-hyps when shown */ -} - -.alectryon-io .goal-separator hr { - border: none; - border-top: thin solid #555753; - display: block; - flex-grow: 1; - margin: 0; -} - -.alectryon-io .goal-separator .goal-name { - font-size: 0.75em; - margin-left: 0.5em; -} - -/**********/ -/* Banner */ -/**********/ - -.alectryon-banner { - background: #eeeeec; - border: 1px solid #babcbd; - font-size: 0.75em; - padding: 0.25em; - text-align: center; - margin: 1em 0; -} - -.alectryon-banner a { - cursor: pointer; - text-decoration: underline; -} - -.alectryon-banner kbd { - background: #d3d7cf; - border-radius: 0.15em; - border: 1px solid #babdb6; - box-sizing: border-box; - display: inline-block; - font-family: inherit; - font-size: 0.9em; - height: 1.3em; - line-height: 1.2em; - margin: -0.25em 0; - padding: 0 0.25em; - vertical-align: middle; -} - -/**********/ -/* Toggle */ -/**********/ - -.alectryon-toggle-label { - margin: 1rem 0; -} - -/******************/ -/* Floating style */ -/******************/ - -/* If there's space, display goals to the right of the code, not below it. */ -@media (min-width: 80rem) { - /* Unlike the windowed case, we don't want to move output blocks to the side - when they are both :checked and -targeted, since it gets confusing as - things jump around; hence the commented-output part of the selector, - which would otherwise increase specificity */ - .alectryon-floating .alectryon-sentence.alectryon-target /* > .alectryon-toggle ~ */ .alectryon-output, - .alectryon-floating .alectryon-sentence:hover .alectryon-output { - top: 0; - left: 100%; - right: -100%; - padding: 0 0.5em; - position: absolute; - } - - .alectryon-floating .alectryon-output { - min-height: 100%; - } - - .alectryon-floating .alectryon-sentence:hover .alectryon-output { - background: white; /* Ensure that short goals hide long ones */ - } - - /* This odd margin-bottom property prevents the sticky div from bumping - against the bottom of its container (.alectryon-output). The alternative - would be enlarging .alectryon-output, but that would cause overflows, - enlarging scrollbars and yielding scrolling towards the bottom of the - page. Doing things this way instead makes it possible to restrict - .alectryon-output to a reasonable size (100%, through top = bottom = 0). - See also https://stackoverflow.com/questions/43909940/. */ - /* See note on specificity above */ - .alectryon-floating .alectryon-sentence.alectryon-target /* > .alectryon-toggle ~ */ .alectryon-output > div, - .alectryon-floating .alectryon-sentence:hover .alectryon-output > div { - margin-bottom: -200%; - position: sticky; - top: 0; - } - - .alectryon-floating .alectryon-toggle:checked + label + .alectryon-container .alectryon-sentence .alectryon-output > div, - .alectryon-floating .alectryon-io .alectryon-sentence > .alectryon-toggle:checked ~ .alectryon-output > div { - margin-bottom: unset; /* Undo the margin */ - } - - /* Float underneath the current fragment - @media (max-width: 80rem) { - .alectryon-floating .alectryon-output { - top: 100%; - } - } */ -} - -/********************/ -/* Multi-pane style */ -/********************/ - -.alectryon-windowed { - border: 0 solid #2e3436; - box-sizing: border-box; -} - -.alectryon-windowed .alectryon-sentence:hover .alectryon-output { - background: white; /* Ensure that short goals hide long ones */ -} - -.alectryon-windowed .alectryon-output { - position: fixed; /* Overwritten by the ‘:checked’ rules */ -} - -/* See note about specificity below */ -.alectryon-windowed .alectryon-sentence:hover .alectryon-output, -.alectryon-windowed .alectryon-sentence.alectryon-target > .alectryon-toggle ~ .alectryon-output { - padding: 0.5em; - overflow-y: auto; /* Windowed contents may need to scroll */ -} - -.alectryon-windowed .alectryon-io .alectryon-sentence:hover .alectryon-output:not(:hover) .alectryon-messages, -.alectryon-windowed .alectryon-io .alectryon-sentence.alectryon-target .alectryon-output .alectryon-messages, -.alectryon-windowed .alectryon-io .alectryon-sentence:hover .alectryon-output:not(:hover) .alectryon-goals, -.alectryon-windowed .alectryon-io .alectryon-sentence.alectryon-target .alectryon-output .alectryon-goals { - box-shadow: none; /* A shadow is unnecessary here and incompatible with overflow-y set to auto */ -} - -.alectryon-windowed .alectryon-io .alectryon-sentence.alectryon-target .alectryon-output .goal-hyps { - /* Restated to override the :checked style */ - flex-flow: column nowrap; - justify-content: space-around; -} - - -.alectryon-windowed .alectryon-sentence.alectryon-target .alectryon-extra-goals .alectryon-goal .goal-conclusion -/* Like .alectryon-io .alectryon-extra-goal-toggle:checked + .alectryon-goal .goal-conclusion */ { - max-height: unset; - overflow-y: unset; -} - -.alectryon-windowed .alectryon-output > div { - display: flex; /* Put messages after goals */ - flex-direction: column-reverse; -} - -/*********************/ -/* Standalone styles */ -/*********************/ - -.alectryon-standalone { - font-family: 'IBM Plex Serif', 'PT Serif', 'Merriweather', 'DejaVu Serif', serif; - line-height: 1.5; -} - -@media screen and (min-width: 50rem) { - html.alectryon-standalone { - /* Prevent flickering when hovering a block causes scrollbars to appear. */ - margin-left: calc(100vw - 100%); - margin-right: 0; - } -} - -/* Coqdoc */ - -.alectryon-coqdoc .doc .code, -.alectryon-coqdoc .doc .inlinecode, -.alectryon-coqdoc .doc .comment { - display: inline; -} - -.alectryon-coqdoc .doc .comment { - color: #eeeeec; -} - -.alectryon-coqdoc .doc .paragraph { - height: 0.75em; -} - -/* Centered, Floating */ - -.alectryon-standalone .alectryon-centered, -.alectryon-standalone .alectryon-floating { - max-width: 50rem; - margin: auto; -} - -@media (min-width: 80rem) { - .alectryon-standalone .alectryon-floating { - max-width: 80rem; - } - - .alectryon-standalone .alectryon-floating > * { - width: 50%; - margin-left: 0; - } -} - -/* Windowed */ - -.alectryon-standalone .alectryon-windowed { - display: block; - margin: 0; - overflow-y: auto; - position: absolute; - padding: 0 1em; -} - -.alectryon-standalone .alectryon-windowed > * { - /* Override properties of docutils_basic.css */ - margin-left: 0; - max-width: unset; -} - -.alectryon-standalone .alectryon-windowed .alectryon-io { - box-sizing: border-box; - width: 100%; -} - -/* No need to predicate the ‘:hover’ rules below on ‘:not(:checked)’, since ‘left’, - ‘right’, ‘top’, and ‘bottom’ will be inactived by the :checked rules setting - ‘position’ to ‘static’ */ - - -/* Specificity: We want the output to stay inline when hovered while unfolded - (:checked), but we want it to move when it's targeted (i.e. when the user - is browsing goals one by one using the keyboard, in which case we want to - goals to appear in consistent locations). The selectors below ensure - that :hover < :checked < -targeted in terms of specificity. */ -/* LATER: Reimplement this stuff with CSS variables */ -.alectryon-windowed .alectryon-sentence.alectryon-target > .alectryon-toggle ~ .alectryon-output { - position: fixed; -} - -@media screen and (min-width: 60rem) { - .alectryon-standalone .alectryon-windowed { - border-right-width: thin; - bottom: 0; - left: 0; - right: 50%; - top: 0; - } - - .alectryon-standalone .alectryon-windowed .alectryon-sentence:hover .alectryon-output, - .alectryon-standalone .alectryon-windowed .alectryon-sentence.alectryon-target .alectryon-output { - bottom: 0; - left: 50%; - right: 0; - top: 0; - } -} - -@media screen and (max-width: 60rem) { - .alectryon-standalone .alectryon-windowed { - border-bottom-width: 1px; - bottom: 40%; - left: 0; - right: 0; - top: 0; - } - - .alectryon-standalone .alectryon-windowed .alectryon-sentence:hover .alectryon-output, - .alectryon-standalone .alectryon-windowed .alectryon-sentence.alectryon-target .alectryon-output { - bottom: 0; - left: 0; - right: 0; - top: 60%; - } -} diff --git a/doc/alectryon.js b/doc/alectryon.js deleted file mode 100644 index d503e0fd24..0000000000 --- a/doc/alectryon.js +++ /dev/null @@ -1,190 +0,0 @@ -var Alectryon; -(function(Alectryon) { - (function (slideshow) { - function anchor(sentence) { return "#" + sentence.id; } - - function current_sentence() { return slideshow.sentences[slideshow.pos]; } - - function unhighlight() { - var sentence = current_sentence(); - if (sentence) sentence.classList.remove("alectryon-target"); - slideshow.pos = -1; - } - - function highlight(sentence) { - sentence.classList.add("alectryon-target"); - } - - function scroll(sentence) { - // Put the top of the current fragment close to the top of the - // screen, but scroll it out of view if showing it requires pushing - // the sentence past half of the screen. If sentence is already in - // a reasonable position, don't move. - var parent = sentence.parentElement; - /* We want to scroll the whole document, so start at root… */ - while (parent && !parent.classList.contains("alectryon-root")) - parent = parent.parentElement; - /* … and work up from there to find a scrollable element. - parent.scrollHeight can be greater than parent.clientHeight - without showing scrollbars, so we add a 10px buffer. */ - while (parent && parent.scrollHeight <= parent.clientHeight + 10) - parent = parent.parentElement; - /* and elements can have their client rect overflow - * the window if their height is unset, so scroll the window - * instead */ - if (parent && (parent.nodeName == "BODY" || parent.nodeName == "HTML")) - parent = null; - - var rect = function(e) { return e.getBoundingClientRect(); }; - var parent_box = parent ? rect(parent) : { y: 0, height: window.innerHeight }, - sentence_y = rect(sentence).y - parent_box.y, - fragment_y = rect(sentence.parentElement).y - parent_box.y; - - // The assertion below sometimes fails for the first element in a block. - // console.assert(sentence_y >= fragment_y); - - if (sentence_y < 0.1 * parent_box.height || - sentence_y > 0.7 * parent_box.height) { - (parent || window).scrollBy( - 0, Math.max(sentence_y - 0.5 * parent_box.height, - fragment_y - 0.1 * parent_box.height)); - } - } - - function highlighted(pos) { - return slideshow.pos == pos; - } - - function navigate(pos, inhibitScroll) { - unhighlight(); - slideshow.pos = Math.min(Math.max(pos, 0), slideshow.sentences.length - 1); - var sentence = current_sentence(); - highlight(sentence); - if (!inhibitScroll) - scroll(sentence); - } - - var keys = { - PAGE_UP: 33, - PAGE_DOWN: 34, - ARROW_UP: 38, - ARROW_DOWN: 40, - h: 72, l: 76, p: 80, n: 78 - }; - - function onkeydown(e) { - e = e || window.event; - if (e.ctrlKey || e.metaKey) { - if (e.keyCode == keys.ARROW_UP) - slideshow.previous(); - else if (e.keyCode == keys.ARROW_DOWN) - slideshow.next(); - else - return; - } else { - // if (e.keyCode == keys.PAGE_UP || e.keyCode == keys.p || e.keyCode == keys.h) - // slideshow.previous(); - // else if (e.keyCode == keys.PAGE_DOWN || e.keyCode == keys.n || e.keyCode == keys.l) - // slideshow.next(); - // else - return; - } - e.preventDefault(); - } - - function start() { - slideshow.navigate(0); - } - - function toggleHighlight(idx) { - if (highlighted(idx)) - unhighlight(); - else - navigate(idx, true); - } - - function handleClick(evt) { - if (evt.ctrlKey || evt.metaKey) { - var sentence = evt.currentTarget; - - // Ensure that the goal is shown on the side, not inline - var checkbox = sentence.getElementsByClassName("alectryon-toggle")[0]; - if (checkbox) - checkbox.checked = false; - - toggleHighlight(sentence.alectryon_index); - evt.preventDefault(); - } - } - - function init() { - document.onkeydown = onkeydown; - slideshow.pos = -1; - slideshow.sentences = Array.from(document.getElementsByClassName("alectryon-sentence")); - slideshow.sentences.forEach(function (s, idx) { - s.addEventListener('click', handleClick, false); - s.alectryon_index = idx; - }); - } - - slideshow.start = start; - slideshow.end = unhighlight; - slideshow.navigate = navigate; - slideshow.next = function() { navigate(slideshow.pos + 1); }; - slideshow.previous = function() { navigate(slideshow.pos + -1); }; - window.addEventListener('DOMContentLoaded', init); - })(Alectryon.slideshow || (Alectryon.slideshow = {})); - - (function (styles) { - var styleNames = ["centered", "floating", "windowed"]; - - function className(style) { - return "alectryon-" + style; - } - - function setStyle(style) { - var root = document.getElementsByClassName("alectryon-root")[0]; - styleNames.forEach(function (s) { - root.classList.remove(className(s)); }); - root.classList.add(className(style)); - } - - function init() { - var banner = document.getElementsByClassName("alectryon-banner")[0]; - if (banner) { - banner.append(" Style: "); - styleNames.forEach(function (styleName, idx) { - var s = styleName; - var a = document.createElement("a"); - a.onclick = function() { setStyle(s); }; - a.append(styleName); - if (idx > 0) banner.append("; "); - banner.appendChild(a); - }); - banner.append("."); - } - } - - window.addEventListener('DOMContentLoaded', init); - - styles.setStyle = setStyle; - })(Alectryon.styles || (Alectryon.styles = {})); -})(Alectryon || (Alectryon = {})); - -function setHidden(elements, isVisible, token) { - for (let i = 0; i < elements.length; i++) { - if (isVisible) { - elements[i].classList.remove(token) - } else { - elements[i].classList.add(token) - } - } -} - -function toggleShowTypes(checkbox) { - setHidden(document.getElementsByClassName("alectryon-io"), checkbox.checked, "type-info-hidden") -} - -function toggleShowGoals(checkbox) { - setHidden(document.getElementsByClassName("alectryon-io"), checkbox.checked, "output-hidden") -} \ No newline at end of file diff --git a/doc/bin/README.md b/doc/bin/README.md deleted file mode 100644 index d161c0af92..0000000000 --- a/doc/bin/README.md +++ /dev/null @@ -1,14 +0,0 @@ -Lean binary distribution ------------------------- - -The binary distribution package contains: - -- Lean executable (located in the sub-directory bin) -- Standard library (located in the sub-directory lib/lean/library) - -Assuming you are in the same directory this file is located, -the following command executes a simple set of examples - -% bin/lean examples/ex.lean - -For more information on Lean and supported editors, please see https://lean-lang.org/documentation/. diff --git a/doc/book.toml b/doc/book.toml deleted file mode 100644 index 8b481f25a4..0000000000 --- a/doc/book.toml +++ /dev/null @@ -1,21 +0,0 @@ -[book] -authors = ["Leonardo de Moura", "Sebastian Ullrich"] -language = "en" -multilingual = false -src = "." -title = "Lean Documentation Overview" - -[build] -build-dir = "out" - -[output.html] -git-repository-url = "https://github.com/leanprover/lean4" -additional-css = ["alectryon.css", "pygments.css"] -additional-js = ["alectryon.js"] - -[output.html.fold] -enable = true -level = 0 - -[output.html.playground.boring-prefixes] -lean = "# " diff --git a/doc/bool.md b/doc/bool.md deleted file mode 100644 index 3d7bb6cfd3..0000000000 --- a/doc/bool.md +++ /dev/null @@ -1 +0,0 @@ -# Booleans diff --git a/doc/declarations.md b/doc/declarations.md deleted file mode 100644 index 2b0f6ed9d1..0000000000 --- a/doc/declarations.md +++ /dev/null @@ -1,885 +0,0 @@ -# Declarations - --- TODO (fix) - -Declaration Names -================= - -A declaration name is a hierarchical [identifier](lexical_structure.md#identifiers) that is interpreted relative to the current namespace as well as (during lookup) to the set of open namespaces. - -```lean -namespace A - opaque B.c : Nat - #print B.c -- opaque A.B.c : Nat -end A - -#print A.B.c -- opaque A.B.c : Nat -open A -#print B.c -- opaque A.B.c : Nat -``` - -Declaration names starting with an underscore are reserved for internal use. Names starting with the special atomic name ``_root_`` are interpreted as absolute names. - -```lean -opaque a : Nat -namespace A - opaque a : Int - #print _root_.a -- opaque a : Nat - #print A.a -- opaque A.a : Int -end A -``` - -Contexts and Telescopes -======================= - -When processing user input, Lean first parses text to a raw expression format. It then uses background information and type constants to disambiguate overloaded symbols and infer implicit arguments, resulting in a fully-formed expression. This process is known as *elaboration*. - -As hinted in [Expression Syntax](expressions.md#expression_syntax), -expressions are parsed and elaborated with respect to an *environment* -and a *local context*. Roughly speaking, an environment represents the -state of Lean at the point where an expression is parsed, including -previously declared axioms, constants, definitions, and theorems. In a -given environment, a *local context* consists of a sequence ``(a₁ : -α₁) (a₂ : α₂) ... (aₙ : αₙ)`` where each ``aᵢ`` is a name denoting a -local constant and each ``αᵢ`` is an expression of type ``Sort u`` for -some ``u`` which can involve elements of the environment and the local -constants ``aⱼ`` for ``j < i``. - -Intuitively, a local context is a list of variables that are held constant while an expression is being elaborated. Consider the following - -```lean -def f (a b : Nat) : Nat → Nat := fun c => a + (b + c) -``` - -Here the expression ``fun c => a + (b + c)`` is elaborated in the context ``(a : Nat) (b : Nat)`` and the expression ``a + (b + c)`` is elaborated in the context ``(a : Nat) (b : Nat) (c : Nat)``. If you replace the expression ``a + (b + c)`` with an underscore, the error message from Lean will include the current *goal*: - -``` -a b c : Nat -⊢ Nat -``` - -Here ``a b c : Nat`` indicates the local context, and the second ``Nat`` indicates the expected type of the result. - -A *context* is sometimes called a *telescope*, but the latter is used more generally to include a sequence of declarations occurring relative to a given context. For example, relative to the context ``(a₁ : α₁) (a₂ : α₂) ... (aₙ : αₙ)``, the types ``βᵢ`` in a telescope ``(b₁ : β₁) (b₂ : β₂) ... (bₙ : βₙ)`` can refer to ``a₁, ..., aₙ``. Thus a context can be viewed as a telescope relative to the empty context. - -Telescopes are often used to describe a list of arguments, or parameters, to a declaration. In such cases, it is often notationally convenient to let ``(a : α)`` stand for a telescope rather than just a single argument. In general, the annotations described in [Implicit Arguments](expressions.md#implicit_arguments) can be used to mark arguments as implicit. - -.. _basic_declarations: - -Basic Declarations -================== - -Lean provides ways of adding new objects to the environment. The following provide straightforward ways of declaring new objects: - -* ``axiom c : α`` : declare a constant named ``c`` of type ``α``, it is postulating that `α` is not an empty type. -* ``def c : α := v`` : defines ``c`` to denote ``v``, which should have type ``α``. -* ``theorem c : p := v`` : similar to ``def``, but intended to be used when ``p`` is a proposition. -* ``opaque c : α (:= v)?`` : declares a opaque constant named ``c`` of type ``α``, the optional value `v` is must have type `α` - and can be viewed as a certificate that ``α`` is not an empty type. If the value is not provided, Lean tries to find one - using a procedure based on type class resolution. The value `v` is hidden from the type checker. You can assume that - Lean "forgets" `v` after type checking this kind of declaration. - -It is sometimes useful to be able to simulate a definition or theorem without naming it or adding it to the environment. - -* ``example : α := t`` : elaborates ``t`` and checks that it has sort ``α`` (often a proposition), without adding it to the environment. - -In ``def``, the type (``α`` or ``p``, respectively) can be omitted when it can be inferred by Lean. Constants declared with ``theorem`` are marked as ``irreducible``. - -Any of ``def``, ``theorem``, ``axiom``, or ``example`` can take a list of arguments (that is, a context) before the colon. If ``(a : α)`` is a context, the definition ``def foo (a : α) : β := t`` -is interpreted as ``def foo : (a : α) → β := fun a : α => t``. Similarly, a theorem ``theorem foo (a : α) : p := t`` is interpreted as ``theorem foo : ∀ a : α, p := fun a : α => t``. - -```lean -opaque c : Nat -opaque d : Nat -axiom cd_eq : c = d - -def foo : Nat := 5 -def bar := 6 -def baz (x y : Nat) (s : List Nat) := [x, y] ++ s - -theorem foo_eq_five : foo = 5 := rfl -theorem baz_theorem (x y : Nat) : baz x y [] = [x, y] := rfl - -example (x y : Nat) : baz x y [] = [x, y] := rfl -``` - -Inductive Types -=============== - -Lean's axiomatic foundation allows users to declare arbitrary -inductive families, following the pattern described by [Dybjer]_. To -make the presentation more manageable, we first describe inductive -*types*, and then describe the generalization to inductive *families* -in the next section. The declaration of an inductive type has the -following form: - -``` -inductive Foo (a : α) where - | constructor₁ : (b : β₁) → Foo a - | constructor₂ : (b : β₂) → Foo a - ... - | constructorₙ : (b : βₙ) → Foo a -``` - -Here ``(a : α)`` is a context and each ``(b : βᵢ)`` is a telescope in the context ``(a : α)`` together with ``Foo``, subject to the following constraints. - -Suppose the telescope ``(b : βᵢ)`` is ``(b₁ : βᵢ₁) ... (bᵤ : βᵢᵤ)``. Each argument in the telescope is either *nonrecursive* or *recursive*. - -- An argument ``(bⱼ : βᵢⱼ)`` is *nonrecursive* if ``βᵢⱼ`` does not refer to ``foo,`` the inductive type being defined. In that case, ``βᵢⱼ`` can be any type, so long as it does not refer to any nonrecursive arguments. - -- An argument ``(bⱼ : βᵢⱼ)`` is *recursive* if it ``βᵢⱼ`` of the form ``Π (d : δ), foo`` where ``(d : δ)`` is a telescope which does not refer to ``foo`` or any nonrecursive arguments. - -The inductive type ``foo`` represents a type that is freely generated by the constructors. Each constructor can take arbitrary data and facts as arguments (the nonrecursive arguments), as well as indexed sequences of elements of ``foo`` that have been previously constructed (the recursive arguments). In set theoretic models, such sets can be represented by well-founded trees labeled by the constructor data, or they can defined using other transfinite or impredicative means. - -The declaration of the type ``foo`` as above results in the addition of the following constants to the environment: - -- the *type former* ``foo : Π (a : α), Sort u`` -- for each ``i``, the *constructor* ``foo.constructorᵢ : Π (a : α) (b : βᵢ), foo a`` -- the *eliminator* ``foo.rec``, which takes arguments - - + ``(a : α)`` (the parameters) - + ``{C : foo a → Type u}`` (the *motive* of the elimination) - + for each ``i``, the *minor premise* corresponding to ``constructorᵢ`` - + ``(x : foo)`` (the *major premise*) - - and returns an element of ``C x``. Here, The ith minor premise is a function which takes - - + ``(b : βᵢ)`` (the arguments to the constructor) - + an argument of type ``Π (d : δ), C (bⱼ d)`` corresponding to each recursive argument ``(bⱼ : βᵢⱼ)``, where ``βᵢⱼ`` is of the form ``Π (d : δ), foo`` (the recursive values of the function being defined) - - and returns an element of ``C (constructorᵢ a b)``, the intended value of the function at ``constructorᵢ a b``. - -The eliminator represents a principle of recursion: to construct an element of ``C x`` where ``x : foo a``, it suffices to consider each of the cases where ``x`` is of the form ``constructorᵢ a b`` and to provide an auxiliary construction in each case. In the case where some of the arguments to ``constructorᵢ`` are recursive, we can assume that we have already constructed values of ``C y`` for each value ``y`` constructed at an earlier stage. - -Under the propositions-as-type correspondence, when ``C x`` is an element of ``Prop``, the eliminator represents a principle of induction. In order to show ``∀ x, C x``, it suffices to show that ``C`` holds for each constructor, under the inductive hypothesis that it holds for all recursive inputs to the constructor. - -The eliminator and constructors satisfy the following identities, in which all the arguments are shown explicitly. Suppose we set ``F := foo.rec a C f₁ ... fₙ``. Then for each constructor, we have the definitional reduction: - -``` -F (constructorᵢ a b) = fᵢ b ... (fun d : δᵢⱼ => F (bⱼ d)) ... -``` - -where the ellipses include one entry for each recursive argument. - -Below are some common examples of inductive types, many of which are defined in the core library. - -```lean -namespace Hide -universe u v - --- BEGIN -inductive Empty : Type - -inductive Unit : Type -| unit : Unit - -inductive Bool : Type -| false : Bool -| true : Bool - -inductive Prod (α : Type u) (β : Type v) : Type (max u v) -| mk : α → β → Prod α β - -inductive Sum (α : Type u) (β : Type v) -| inl : α → Sum α β -| inr : β → Sum α β - -inductive Sigma (α : Type u) (β : α → Type v) -| mk : (a : α) → β a → Sigma α β - -inductive false : Prop - -inductive True : Prop -| trivial : True - -inductive And (p q : Prop) : Prop -| intro : p → q → And p q - -inductive Or (p q : Prop) : Prop -| inl : p → Or p q -| inr : q → Or p q - -inductive Exists (α : Type u) (p : α → Prop) : Prop -| intro : ∀ x : α, p x → Exists α p - -inductive Subtype (α : Type u) (p : α → Prop) : Type u -| intro : ∀ x : α, p x → Subtype α p - -inductive Nat : Type -| zero : Nat -| succ : Nat → Nat - -inductive List (α : Type u) -| nil : List α -| cons : α → List α → List α - --- full binary tree with nodes and leaves labeled from α -inductive BinTree (α : Type u) -| leaf : α → BinTree α -| node : BinTree α → α → BinTree α → BinTree α - --- every internal node has subtrees indexed by Nat -inductive CBT (α : Type u) -| leaf : α → CBT α -| node : (Nat → CBT α) → CBT α --- END -end Hide -``` - -Note that in the syntax of the inductive definition ``Foo``, the context ``(a : α)`` is left implicit. In other words, constructors and recursive arguments are written as though they have return type ``Foo`` rather than ``Foo a``. - -Elements of the context ``(a : α)`` can be marked implicit as described in [Implicit Arguments](#implicit.md#implicit_arguments). These annotations bear only on the type former, ``Foo``. Lean uses a heuristic to determine which arguments to the constructors should be marked implicit, namely, an argument is marked implicit if it can be inferred from the type of a subsequent argument. If the annotation ``{}`` appears after the constructor, a argument is marked implicit if it can be inferred from the type of a subsequent argument *or the return type*. For example, it is useful to let ``nil`` denote the empty list of any type, since the type can usually be inferred in the context in which it appears. These heuristics are imperfect, and you may sometimes wish to define your own constructors in terms of the default ones. In that case, use the ``[match_pattern]`` [attribute](TODO: missing link) to ensure that these will be used appropriately by the [Equation Compiler](#the-equation-compiler). - -There are restrictions on the universe ``u`` in the return type ``Sort u`` of the type former. There are also restrictions on the universe ``u`` in the return type ``Sort u`` of the motive of the eliminator. These will be discussed in the next section in the more general setting of inductive families. - -Lean allows some additional syntactic conveniences. You can omit the return type of the type former, ``Sort u``, in which case Lean will infer the minimal possible nonzero value for ``u``. As with function definitions, you can list arguments to the constructors before the colon. In an enumerated type (that is, one where the constructors have no arguments), you can also leave out the return type of the constructors. - -```lean -namespace Hide -universe u - --- BEGIN -inductive Weekday -| sunday | monday | tuesday | wednesday -| thursday | friday | saturday - -inductive Nat -| zero -| succ (n : Nat) : Nat - -inductive List (α : Type u) -| nil : List α -| cons (a : α) (l : List α) : List α - -@[match_pattern] -def List.nil' (α : Type u) : List α := List.nil - -def length {α : Type u} : List α → Nat -| (List.nil' _) => 0 -| (List.cons a l) => 1 + length l --- END - -end Hide -``` - -The type former, constructors, and eliminator are all part of Lean's axiomatic foundation, which is to say, they are part of the trusted kernel. In addition to these axiomatically declared constants, Lean automatically defines some additional objects in terms of these, and adds them to the environment. These include the following: - -- ``Foo.recOn`` : a variant of the eliminator, in which the major premise comes first -- ``Foo.casesOn`` : a restricted version of the eliminator which omits any recursive calls -- ``Foo.noConfusionType``, ``Foo.noConfusion`` : functions which witness the fact that the inductive type is freely generated, i.e. that the constructors are injective and that distinct constructors produce distinct objects -- ``Foo.below``, ``Foo.ibelow`` : functions used by the equation compiler to implement structural recursion -- ``instance : SizeOf Foo`` : a measure which can be used for well-founded recursion - -Note that it is common to put definitions and theorems related to a datatype ``foo`` in a namespace of the same name. This makes it possible to use projection notation described in [Structures](struct.md#structures) and [Namespaces](namespaces.md#namespaces). - -```lean -namespace Hide -universe u - --- BEGIN -inductive Nat -| zero -| succ (n : Nat) : Nat - -#check Nat -#check @Nat.rec -#check Nat.zero -#check Nat.succ - -#check @Nat.recOn -#check @Nat.casesOn -#check @Nat.noConfusionType -#check @Nat.noConfusion -#check @Nat.brecOn -#check Nat.below -#check Nat.ibelow -#check Nat._sizeOf_1 - --- END - -end Hide -``` - -.. _inductive_families: - -Inductive Families -================== - -In fact, Lean implements a slight generalization of the inductive types described in the previous section, namely, inductive *families*. The declaration of an inductive family in Lean has the following form: - -``` -inductive Foo (a : α) : Π (c : γ), Sort u -| constructor₁ : Π (b : β₁), Foo t₁ -| constructor₂ : Π (b : β₂), Foo t₂ -... -| constructorₙ : Π (b : βₙ), Foo tₙ -``` - -Here ``(a : α)`` is a context, ``(c : γ)`` is a telescope in context ``(a : α)``, each ``(b : βᵢ)`` is a telescope in the context ``(a : α)`` together with ``(Foo : Π (c : γ), Sort u)`` subject to the constraints below, and each ``tᵢ`` is a tuple of terms in the context ``(a : α) (b : βᵢ)`` having the types ``γ``. Instead of defining a single inductive type ``Foo a``, we are now defining a family of types ``Foo a c`` indexed by elements ``c : γ``. Each constructor, ``constructorᵢ``, places its result in the type ``Foo a tᵢ``, the member of the family with index ``tᵢ``. - -The modifications to the scheme in the previous section are straightforward. Suppose the telescope ``(b : βᵢ)`` is ``(b₁ : βᵢ₁) ... (bᵤ : βᵢᵤ)``. - -- As before, an argument ``(bⱼ : βᵢⱼ)`` is *nonrecursive* if ``βᵢⱼ`` does not refer to ``Foo,`` the inductive type being defined. In that case, ``βᵢⱼ`` can be any type, so long as it does not refer to any nonrecursive arguments. - -- An argument ``(bⱼ : βᵢⱼ)`` is *recursive* if ``βᵢⱼ`` is of the form ``Π (d : δ), Foo s`` where ``(d : δ)`` is a telescope which does not refer to ``Foo`` or any nonrecursive arguments and ``s`` is a tuple of terms in context ``(a : α)`` and the previous nonrecursive ``bⱼ``'s with types ``γ``. - -The declaration of the type ``Foo`` as above results in the addition of the following constants to the environment: - -- the *type former* ``Foo : Π (a : α) (c : γ), Sort u`` -- for each ``i``, the *constructor* ``Foo.constructorᵢ : Π (a : α) (b : βᵢ), Foo a tᵢ`` -- the *eliminator* ``Foo.rec``, which takes arguments - - + ``(a : α)`` (the parameters) - + ``{C : Π (c : γ), Foo a c → Type u}`` (the motive of the elimination) - + for each ``i``, the minor premise corresponding to ``constructorᵢ`` - + ``(x : Foo a)`` (the major premise) - - and returns an element of ``C x``. Here, The ith minor premise is a function which takes - - + ``(b : βᵢ)`` (the arguments to the constructor) - + an argument of type ``Π (d : δ), C s (bⱼ d)`` corresponding to each recursive argument ``(bⱼ : βᵢⱼ)``, where ``βᵢⱼ`` is of the form ``Π (d : δ), Foo s`` - - and returns an element of ``C tᵢ (constructorᵢ a b)``. - -Suppose we set ``F := Foo.rec a C f₁ ... fₙ``. Then for each constructor, we have the definitional reduction, as before: - -``` -F (constructorᵢ a b) = fᵢ b ... (fun d : δᵢⱼ => F (bⱼ d)) ... -``` - -where the ellipses include one entry for each recursive argument. - -The following are examples of inductive families. - -```lean -namespace Hide -universe u - --- BEGIN -inductive Vector (α : Type u) : Nat → Type u -| nil : Vector 0 -| succ : Π n, Vector n → Vector (n + 1) - --- 'IsProd s n' means n is a product of elements of s -inductive IsProd (s : Set Nat) : Nat → Prop -| base : ∀ n ∈ s, IsProd n -| step : ∀ m n, IsProd m → IsProd n → IsProd (m * n) - -inductive Eq {α : Sort u} (a : α) : α → Prop -| refl : Eq a --- END - -end Hide -``` - -We can now describe the constraints on the return type of the type former, ``Sort u``. We can always take ``u`` to be ``0``, in which case we are defining an inductive family of propositions. If ``u`` is nonzero, however, it must satisfy the following constraint: for each type ``βᵢⱼ : Sort v`` occurring in the constructors, we must have ``u ≥ v``. In the set-theoretic interpretation, this ensures that the universe in which the resulting type resides is large enough to contain the inductively generated family, given the number of distinctly-labeled constructors. The restriction does not hold for inductively defined propositions, since these contain no data. - -Putting an inductive family in ``Prop``, however, does impose a restriction on the eliminator. Generally speaking, for an inductive family in ``Prop``, the motive in the eliminator is required to be in ``Prop``. But there is an exception to this rule: you are allowed to eliminate from an inductively defined ``Prop`` to an arbitrary ``Sort`` when there is only one constructor, and each argument to that constructor is either in ``Prop`` or an index. The intuition is that in this case the elimination does not make use of any information that is not already given by the mere fact that the type of argument is inhabited. This special case is known as *singleton elimination*. - -.. _mutual_and_nested_inductive_definitions: - -Mutual and Nested Inductive Definitions -======================================= - -Lean supports two generalizations of the inductive families described above, namely, *mutual* and *nested* inductive definitions. These are *not* implemented natively in the kernel. Rather, the definitions are compiled down to the primitive inductive types and families. - -The first generalization allows for multiple inductive types to be defined simultaneously. - -``` -mutual - -inductive Foo (a : α) : Π (c : γ₁), Sort u -| constructor₁₁ : Π (b : β₁₁), Foo a t₁₁ -| constructor₁₂ : Π (b : β₁₂), Foo a t₁₂ -... -| constructor₁ₙ : Π (b : β₁ₙ), Foo a t₁ₙ - -inductive Bar (a : α) : Π (c : γ₂), Sort u -| constructor₂₁ : Π (b : β₂₁), Bar a t₂₁ -| constructor₂₂ : Π (b : β₂₂), Bar a t₂₂ -... -| constructor₂ₘ : Π (b : β₂ₘ), Bar a t₂ₘ - -end -``` - -Here the syntax is shown for defining two inductive families, ``Foo`` and ``Bar``, but any number is allowed. The restrictions are almost the same as for ordinary inductive families. For example, each ``(b : βᵢⱼ)`` is a telescope relative to the context ``(a : α)``. The difference is that the constructors can now have recursive arguments whose return types are any of the inductive families currently being defined, in this case ``Foo`` and ``Bar``. Note that all of the inductive definitions share the same parameters ``(a : α)``, though they may have different indices. - -A mutual inductive definition is compiled down to an ordinary inductive definition using an extra finite-valued index to distinguish the components. The details of the internal construction are meant to be hidden from most users. Lean defines the expected type formers ``Foo`` and ``Bar`` and constructors ``constructorᵢⱼ`` from the internal inductive definition. There is no straightforward elimination principle, however. Instead, Lean defines an appropriate ``sizeOf`` measure, meant for use with well-founded recursion, with the property that the recursive arguments to a constructor are smaller than the constructed value. - -The second generalization relaxes the restriction that in the recursive definition of ``Foo``, ``Foo`` can only occur strictly positively in the type of any of its recursive arguments. Specifically, in a nested inductive definition, ``Foo`` can appear as an argument to another inductive type constructor, so long as the corresponding parameter occurs strictly positively in the constructors for *that* inductive type. This process can be iterated, so that additional type constructors can be applied to those, and so on. - -A nested inductive definition is compiled down to an ordinary inductive definition using a mutual inductive definition to define copies of all the nested types simultaneously. Lean then constructs isomorphisms between the mutually defined nested types and their independently defined counterparts. Once again, the internal details are not meant to be manipulated by users. Rather, the type former and constructors are made available and work as expected, while an appropriate ``sizeOf`` measure is generated for use with well-founded recursion. - -```lean -universe u --- BEGIN -mutual -inductive Even : Nat → Prop -| even_zero : Even 0 -| even_succ : ∀ n, Odd n → Even (n + 1) -inductive Odd : Nat → Prop -| odd_succ : ∀ n, Even n → Odd (n + 1) -end - -inductive Tree (α : Type u) -| mk : α → List (Tree α) → Tree α - -inductive DoubleTree (α : Type u) -| mk : α → List (DoubleTree α) × List (DoubleTree α) → DoubleTree α --- END -``` - -.. _the_equation_compiler: - -The Equation Compiler -===================== - -The equation compiler takes an equational description of a function or proof and tries to define an object meeting that specification. It expects input with the following syntax: - -``` -def foo (a : α) : Π (b : β), γ -| [patterns₁] => t₁ -... -| [patternsₙ] => tₙ -``` - -Here ``(a : α)`` is a telescope, ``(b : β)`` is a telescope in the context ``(a : α)``, and ``γ`` is an expression in the context ``(a : α) (b : β)`` denoting a ``Type`` or a ``Prop``. - -Each ``patternsᵢ`` is a sequence of patterns of the same length as ``(b : β)``. A pattern is either: - -- a variable, denoting an arbitrary value of the relevant type, -- an underscore, denoting a *wildcard* or *anonymous variable*, -- an inaccessible term (see below), or -- a constructor for the inductive type of the corresponding argument, applied to a sequence of patterns. - -In the last case, the pattern must be enclosed in parentheses. - -Each term ``tᵢ`` is an expression in the context ``(a : α)`` together with the variables introduced on the left-hand side of the token ``=>``. The term ``tᵢ`` can also include recursive calls to ``foo``, as described below. The equation compiler does case splitting on the variables ``(b : β)`` as necessary to match the patterns, and defines ``foo`` so that it has the value ``tᵢ`` in each of the cases. In ideal circumstances (see below), the equations hold definitionally. Whether they hold definitionally or only propositionally, the equation compiler proves the relevant equations and assigns them internal names. They are accessible by the ``rewrite`` and ``simp`` tactics under the name ``foo`` (see [Rewrite](tactics.md#rewrite) and _[TODO: where is simplifier tactic documented?]_. If some of the patterns overlap, the equation compiler interprets the definition so that the first matching pattern applies in each case. Thus, if the last pattern is a variable, it covers all the remaining cases. If the patterns that are presented do not cover all possible cases, the equation compiler raises an error. - -When identifiers are marked with the ``[match_pattern]`` attribute, the equation compiler unfolds them in the hopes of exposing a constructor. For example, this makes it possible to write ``n+1`` and ``0`` instead of ``Nat.succ n`` and ``Nat.zero`` in patterns. - -For a nonrecursive definition involving case splits, the defining equations will hold definitionally. With inductive types like ``Char``, ``String``, and ``Fin n``, a case split would produce definitions with an inordinate number of cases. To avoid this, the equation compiler uses ``if ... then ... else`` instead of ``casesOn`` when defining the function. In this case, the defining equations hold definitionally as well. - -```lean -open Nat - -def sub2 : Nat → Nat -| zero => 0 -| succ zero => 0 -| succ (succ a) => a - -def bar : Nat → List Nat → Bool → Nat -| 0, _, false => 0 -| 0, b :: _, _ => b -| 0, [], true => 7 -| a+1, [], false => a -| a+1, [], true => a + 1 -| a+1, b :: _, _ => a + b - -def baz : Char → Nat -| 'A' => 1 -| 'B' => 2 -| _ => 3 -``` - -The case where patterns are matched against an argument whose type is an inductive family is known as *dependent pattern matching*. This is more complicated, because the type of the function being defined can impose constraints on the patterns that are matched. In this case, the equation compiler will detect inconsistent cases and rule them out. - -```lean -universe u - -inductive Vector (α : Type u) : Nat → Type u - | nil : Vector α 0 - | cons : α → Vector α n → Vector α (n+1) - -namespace Vector - -def head : Vector α (n+1) → α - | cons h t => h - -def tail : Vector α (n+1) → Vector α n - | cons h t => t - -def map (f : α → β → γ) : Vector α n → Vector β n → Vector γ n - | nil, nil => nil - | cons a va, cons b vb => cons (f a b) (map f va vb) - -end Vector -``` - -.. _recursive_functions: - -Recursive functions -=================== - -Lean must ensure that a recursive function terminates, for which there are two strategies: _structural recursion_, in which all recursive calls are made on smaller parts of the input data, and _well-founded recursion_, in which recursive calls are justified by showing that arguments to recursive calls are smaller according to some other measure. - -Structural recursion --------------------- - -If the definition of a function contains recursive calls, Lean first tries to interpret the definition as a structural recursion. In order for that to succeed, the recursive arguments must be subterms of the corresponding arguments on the left-hand side. - -The function is then defined using a *course of values* recursion, using automatically generated functions ``below`` and ``brec`` in the namespace corresponding to the inductive type of the recursive argument. In this case the defining equations hold definitionally, possibly with additional case splits. - -```lean -namespace Hide - --- BEGIN -def fib : Nat → Nat -| 0 => 1 -| 1 => 1 -| (n+2) => fib (n+1) + fib n - -def append {α : Type} : List α → List α → List α -| [], l => l -| h::t, l => h :: append t l - -example : append [(1 : Nat), 2, 3] [4, 5] = [1, 2, 3, 4, 5] => rfl --- END - -end Hide -``` - -Well-founded recursion ---------------------- - -If structural recursion fails, the equation compiler falls back on well-founded recursion. It tries to infer an instance of ``SizeOf`` for the type of each argument, and then tries to find a permutation of the arguments such that each recursive call is decreasing under the lexicographic order with respect to ``sizeOf`` measures. Lean uses information in the local context, so you can often provide the relevant proof manually using ``have`` in the body of the definition. - -In the case of well-founded recursion, the equation used to declare the function holds only propositionally, but not definitionally, and can be accessed using ``unfold``, ``simp`` and ``rewrite`` with the function name (for example ``unfold foo`` or ``simp [foo]``, where ``foo`` is the function defined with well-founded recursion). - -```lean -namespace Hide -open Nat - --- BEGIN -def div : Nat → Nat → Nat -| x, y => - if h : 0 < y ∧ y ≤ x then - have : x - y < x := - sub_lt (Nat.lt_of_lt_of_le h.left h.right) h.left - div (x - y) y + 1 - else - 0 - -example (x y : Nat) : - div x y = if 0 < y ∧ y ≤ x then div (x - y) y + 1 else 0 := -by rw [div]; rfl --- END - -end Hide -``` - -If Lean cannot find a permutation of the arguments for which all recursive calls are decreasing, it will print a table that contains, for every recursive call, which arguments Lean could prove to be decreasing. For example, a function with three recursive calls and four parameters might cause the following message to be printed - -``` -example.lean:37:0-43:31: error: Could not find a decreasing measure. -The arguments relate at each recursive call as follows: -(<, ≤, =: relation proved, ? all proofs failed, _: no proof attempted) - x1 x2 x3 x4 -1) 39:6-27 = = _ = -2) 40:6-25 = ? _ < -3) 41:6-25 < _ _ _ -Please use `termination_by` to specify a decreasing measure. -``` - -This table should be read as follows: - - * In the first recursive call, in line 39, arguments 1, 2 and 4 are equal to the function's parameters. - * The second recursive call, in line 40, has an equal first argument, a smaller fourth argument, and nothing could be inferred for the second argument. - * The third recursive call, in line 41, has a decreasing first argument. - * No other proofs were attempted, either because the parameter has a type without a non-trivial ``WellFounded`` instance (parameter 3), or because it is already clear that no decreasing measure can be found. - - -Lean will print the termination measure it found if ``set_option showInferredTerminationBy true`` is set. - -If Lean does not find the termination measure, or if you want to be explicit, you can append a `termination_by` clause to the function definition, after the function's body, but before the `where` clause if present. It is of the form -``` -termination_by e -``` -where ``e`` is an expression that depends on the parameters of the function and should be decreasing at each recursive call. The type of `e` should be an instance of the class ``WellFoundedRelation``, which determines how to compare two values of that type. - -If ``f`` has parameters “after the ``:``” (for example when defining functions via patterns using `|`), then these can be brought into scope using the syntax -``` -termination_by a₁ … aₙ => e -``` - -By default, Lean uses the tactic ``decreasing_tactic`` when proving that an argument is decreasing; see its documentation for how to globally extend it. You can also choose to use a different tactic for a given function definition with the clause -``` -decreasing_by -``` -which should come after ``termination_by`, if present. - - -Note that recursive definitions can in general require nested recursions, that is, recursion on different arguments of ``foo`` in the template above. The equation compiler handles this by abstracting later arguments, and recursively defining higher-order functions to meet the specification. - -Mutual recursion ----------------- - -The equation compiler also allows mutual recursive definitions, with a syntax similar to that of [Mutual and Nested Inductive Definitions](#mutual-and-nested-inductive-definitions). Mutual definitions are always compiled using well-founded recursion, and so once again the defining equations hold only propositionally. - -```lean -mutual -def even : Nat → Bool -| 0 => true -| a+1 => odd a -def odd : Nat → Bool -| 0 => false -| a+1 => even a -end - -example (a : Nat) : even (a + 1) = odd a := -by simp [even] - -example (a : Nat) : odd (a + 1) = even a := -by simp [odd] -``` - -Well-founded recursion is especially useful with [Mutual and Nested Inductive Definitions](#mutual-and-nested-inductive-definitions), since it provides the canonical way of defining functions on these types. - -```lean -mutual -inductive Even : Nat → Prop -| even_zero : Even 0 -| even_succ : ∀ n, Odd n → Even (n + 1) -inductive Odd : Nat → Prop -| odd_succ : ∀ n, Even n → Odd (n + 1) -end - -open Even Odd - -theorem not_odd_zero : ¬ Odd 0 := fun x => nomatch x - -mutual -theorem even_of_odd_succ : ∀ n, Odd (n + 1) → Even n -| _, odd_succ n h => h -theorem odd_of_even_succ : ∀ n, Even (n + 1) → Odd n -| _, even_succ n h => h -end - -inductive Term -| const : String → Term -| app : String → List Term → Term - -open Term - -mutual -def num_consts : Term → Nat -| .const n => 1 -| .app n ts => num_consts_lst ts -def num_consts_lst : List Term → Nat -| [] => 0 -| t::ts => num_consts t + num_consts_lst ts -end -``` - -In a set of mutually recursive function, either all or no functions must have an explicit termination measure (``termination_by``). A change of the default termination tactic (``decreasing_by``) only affects the proofs about the recursive calls of that function, not the other functions in the group. - -``` -mutual -theorem even_of_odd_succ : ∀ n, Odd (n + 1) → Even n -| _, odd_succ n h => h -termination_by n h => h -decreasing_by decreasing_tactic - -theorem odd_of_even_succ : ∀ n, Even (n + 1) → Odd n -| _, even_succ n h => h -termination_by n h => h -end -``` - -Another way to express mutual recursion is using local function definitions in ``where`` or ``let rec`` clauses: these can be mutually recursive with each other and their containing function: - -``` -theorem even_of_odd_succ : ∀ n, Odd (n + 1) → Even n - | _, odd_succ n h => h -termination_by n h => h - where - theorem odd_of_even_succ : ∀ n, Even (n + 1) → Odd n - | _, even_succ n h => h - termination_by n h => h -``` - -.. _match_expressions: - -Match Expressions -================= - -Lean supports a ``match ... with ...`` construct similar to ones found in most functional programming languages. The syntax is as follows: - -``` -match t₁, ..., tₙ with -| p₁₁, ..., p₁ₙ => s₁ -... -| pₘ₁, ..., pₘₙ => sₘ -``` - -Here ``t₁, ..., tₙ`` are any terms in the context in which the expression appears, the expressions ``pᵢⱼ`` are patterns, and the terms ``sᵢ`` are expressions in the local context together with variables introduced by the patterns on the left-hand side. Each ``sᵢ`` should have the expected type of the entire ``match`` expression. - -Any ``match`` expression is interpreted using the equation compiler, which generalizes ``t₁, ..., tₙ``, defines an internal function meeting the specification, and then applies it to ``t₁, ..., tₙ``. In contrast to the definitions in [The Equation Compiler](declarations.md#the-equation-compiler), the terms ``tᵢ`` are arbitrary terms rather than just variables, and the expression can occur anywhere within a Lean expression, not just at the top level of a definition. Note that the syntax here is somewhat different: both the terms ``tᵢ`` and the patterns ``pᵢⱼ`` are separated by commas. - -```lean -def foo (n : Nat) (b c : Bool) := -5 + match n - 5, b && c with - | 0, true => 0 - | m+1, true => m + 7 - | 0, false => 5 - | m+1, false => m + 3 -``` - -When a ``match`` has only one line, Lean provides alternative syntax with a destructuring ``let``, as well as a destructuring lambda abstraction. Thus the following definitions all have the same net effect. - -```lean -def bar₁ : Nat × Nat → Nat -| (m, n) => m + n - -def bar₂ (p : Nat × Nat) : Nat := -match p with | (m, n) => m + n - -def bar₃ : Nat × Nat → Nat := -fun ⟨m, n⟩ => m + n - -def bar₄ (p : Nat × Nat) : Nat := -let ⟨m, n⟩ := p; m + n -``` - -Information about the term being matched can be preserved in each branch using the syntax `match h : t with`. For example, a user may want to match a term `ns ++ ms : List Nat`, while tracking the hypothesis `ns ++ ms = []` or `ns ++ ms= h :: t` in the respective match arm: - -```lean -def foo (ns ms : List Nat) (h1 : ns ++ ms ≠ []) (k : Nat -> Char) : Char := - match h2 : ns ++ ms with - -- in this arm, we have the hypothesis `h2 : ns ++ ms = []` - | [] => absurd h2 h1 - -- in this arm, we have the hypothesis `h2 : ns ++ ms = h :: t` - | h :: t => k h - --- '7' -#eval foo [7, 8, 9] [] (by decide) Nat.digitChar -``` - -.. _structures_and_records: - -Structures and Records -====================== - -The ``structure`` command in Lean is used to define an inductive data type with a single constructor and to define its projections at the same time. The syntax is as follows: - -``` -structure Foo (a : α) : Sort u extends Bar, Baz := -constructor :: (field₁ : β₁) ... (fieldₙ : βₙ) -``` - -Here ``(a : α)`` is a telescope, that is, the parameters to the inductive definition. The name ``constructor`` followed by the double colon is optional; if it is not present, the name ``mk`` is used by default. The keyword ``extends`` followed by a list of previously defined structures is also optional; if it is present, an instance of each of these structures is included among the fields to ``Foo``, and the types ``βᵢ`` can refer to their fields as well. The output type, ``Sort u``, can be omitted, in which case Lean infers to smallest non-``Prop`` sort possible (unless all the fields are ``Prop``, in which case it infers ``Prop``). -Finally, ``(field₁ : β₁) ... (fieldₙ : βₙ)`` is a telescope relative to ``(a : α)`` and the fields in ``bar`` and ``baz``. - -The declaration above is syntactic sugar for an inductive type declaration, and so results in the addition of the following constants to the environment: - -- the type former : ``Foo : Π (a : α), Sort u`` -- the single constructor : - -``` -Foo.constructor : Π (a : α) (toBar : Bar) (toBaz : Baz) - (field₁ : β₁) ... (fieldₙ : βₙ), Foo a -``` - -- the eliminator ``Foo.rec`` for the inductive type with that constructor - -In addition, Lean defines - -- the projections : ``fieldᵢ : Π (a : α) (c : Foo) : βᵢ`` for each ``i`` - -where any other fields mentioned in ``βᵢ`` are replaced by the relevant projections from ``c``. - -Given ``c : Foo``, Lean offers the following convenient syntax for the projection ``Foo.fieldᵢ c``: - -- *anonymous projections* : ``c.fieldᵢ`` -- *numbered projections* : ``c.i`` - -These can be used in any situation where Lean can infer that the type of ``c`` is of the form ``Foo a``. The convention for anonymous projections is extended to any function ``f`` defined in the namespace ``Foo``, as described in [Namespaces](namespaces.md). - -Similarly, Lean offers the following convenient syntax for constructing elements of ``Foo``. They are equivalent to ``Foo.constructor b₁ b₂ f₁ f₁ ... fₙ``, where ``b₁ : Bar``, ``b₂ : Baz``, and each ``fᵢ : βᵢ`` : - -- *anonymous constructor*: ``⟨ b₁, b₂, f₁, ..., fₙ ⟩`` -- *record notation*: - -``` -{ toBar := b₁, toBaz := b₂, field₁ := f₁, ..., - fieldₙ := fₙ : Foo a } -``` - -The anonymous constructor can be used in any context where Lean can infer that the expression should have a type of the form ``Foo a``. The unicode brackets are entered as ``\<`` and ``\>`` respectively. - -When using record notation, you can omit the annotation ``: Foo a`` when Lean can infer that the expression should have a type of the form ``Foo a``. You can replace either ``toBar`` or ``toBaz`` by assignments to *their* fields as well, essentially acting as though the fields of ``Bar`` and ``Baz`` are simply imported into ``Foo``. Finally, record notation also supports - -- *record updates*: ``{ t with ... fieldᵢ := fᵢ ...}`` - -Here ``t`` is a term of type ``Foo a`` for some ``a``. The notation instructs Lean to take values from ``t`` for any field assignment that is omitted from the list. - -Lean also allows you to specify a default value for any field in a structure by writing ``(fieldᵢ : βᵢ := t)``. Here ``t`` specifies the value to use when the field ``fieldᵢ`` is left unspecified in an instance of record notation. - -```lean -universe u v - -structure Vec (α : Type u) (n : Nat) := -(l : List α) (h : l.length = n) - -structure Foo (α : Type u) (β : Nat → Type v) : Type (max u v) := -(a : α) (n : Nat) (b : β n) - -structure Bar := -(c : Nat := 8) (d : Nat) - -structure Baz extends Foo Nat (Vec Nat), Bar := -(v : Vec Nat n) - -#check Foo -#check @Foo.mk -#check @Foo.rec - -#check Foo.a -#check Foo.n -#check Foo.b - -#check Baz -#check @Baz.mk -#check @Baz.rec - -#check Baz.toFoo -#check Baz.toBar -#check Baz.v - -def bzz := Vec.mk [1, 2, 3] rfl - -#check Vec.l bzz -#check Vec.h bzz -#check bzz.l -#check bzz.h -#check bzz.1 -#check bzz.2 - -example : Vec Nat 3 := Vec.mk [1, 2, 3] rfl -example : Vec Nat 3 := ⟨[1, 2, 3], rfl⟩ -example : Vec Nat 3 := { l := [1, 2, 3], h := rfl : Vec Nat 3 } -example : Vec Nat 3 := { l := [1, 2, 3], h := rfl } - -example : Foo Nat (Vec Nat) := ⟨1, 3, bzz⟩ - -example : Baz := ⟨⟨1, 3, bzz⟩, ⟨5, 7⟩, bzz⟩ -example : Baz := { a := 1, n := 3, b := bzz, c := 5, d := 7, v := bzz} -def fzz : Foo Nat (Vec Nat) := {a := 1, n := 3, b := bzz} - -example : Foo Nat (Vec Nat) := { fzz with a := 7 } -example : Baz := { fzz with c := 5, d := 7, v := bzz } - -example : Bar := { c := 8, d := 9 } -example : Bar := { d := 9 } -- uses the default value for c -``` - -.. _type_classes: - -Type Classes -============ - -(Classes and instances. Anonymous instances. Local instances.) - - -.. [Dybjer] Dybjer, Peter, *Inductive Families*. Formal Aspects of Computing 6, 1994, pages 440-465. diff --git a/doc/definitions.md b/doc/definitions.md deleted file mode 100644 index 57e5bd97c4..0000000000 --- a/doc/definitions.md +++ /dev/null @@ -1 +0,0 @@ -# Definitions diff --git a/doc/dep.md b/doc/dep.md deleted file mode 100644 index a8254c1d3f..0000000000 --- a/doc/dep.md +++ /dev/null @@ -1,66 +0,0 @@ -## What makes dependent type theory dependent? - -The short explanation is that what makes dependent type theory dependent is that types can depend on parameters. -You have already seen a nice example of this: the type ``List α`` depends on the argument ``α``, and -this dependence is what distinguishes ``List Nat`` and ``List Bool``. -For another example, consider the type ``Vector α n``, the type of vectors of elements of ``α`` of length ``n``. -This type depends on *two* parameters: the type ``α : Type`` of the elements in the vector and the length ``n : Nat``. - -Suppose we wish to write a function ``cons`` which inserts a new element at the head of a list. -What type should ``cons`` have? Such a function is *polymorphic*: we expect the ``cons`` function for ``Nat``, ``Bool``, -or an arbitrary type ``α`` to behave the same way. -So it makes sense to take the type to be the first argument to ``cons``, so that for any type, ``α``, ``cons α`` -is the insertion function for lists of type ``α``. In other words, for every ``α``, ``cons α`` is the function that takes an element ``a : α`` -and a list ``as : List α``, and returns a new list, so we have ``cons α a as : list α``. - -It is clear that ``cons α`` should have type ``α → List α → List α``. But what type should ``cons`` have? -A first guess might be ``Type → α → list α → list α``, but, on reflection, this does not make sense: -the ``α`` in this expression does not refer to anything, whereas it should refer to the argument of type ``Type``. -In other words, *assuming* ``α : Type`` is the first argument to the function, the type of the next two elements are ``α`` and ``List α``. -These types vary depending on the first argument, ``α``. - -This is an instance of a *dependent function type*, or *dependent arrow type*. Given ``α : Type`` and ``β : α → Type``, -think of ``β`` as a family of types over ``α``, that is, a type ``β a`` for each ``a : α``. -In that case, the type ``(a : α) → β a`` denotes the type of functions ``f`` with the property that, -for each ``a : α``, ``f a`` is an element of ``β a``. In other words, the type of the value returned by ``f`` depends on its input. - -Notice that ``(a : α) → β`` makes sense for any expression ``β : Type``. When the value of ``β`` depends on ``a`` -(as does, for example, the expression ``β a`` in the previous paragraph), ``(a : α) → β`` denotes a dependent function type. -When ``β`` doesn't depend on ``a``, ``(a : α) → β`` is no different from the type ``α → β``. -Indeed, in dependent type theory (and in Lean), ``α → β`` is just notation for ``(a : α) → β`` when ``β`` does not depend on ``a``. - -Returning to the example of lists, we can use the command `#check` to inspect the type of the following `List` functions -We will explain the ``@`` symbol and the difference between the round and curly braces momentarily. - -```lean -#check @List.cons -- {α : Type u_1} → α → List α → List α -#check @List.nil -- {α : Type u_1} → List α -#check @List.length -- {α : Type u_1} → List α → Nat -#check @List.append -- {α : Type u_1} → List α → List α → List α -``` - -Just as dependent function types ``(a : α) → β a`` generalize the notion of a function type ``α → β`` by allowing ``β`` to depend on ``α``, -dependent Cartesian product types ``(a : α) × β a`` generalize the Cartesian product ``α × β`` in the same way. Dependent products are also -called *sigma* types, and you can also write them as `Σ a : α, β a`. You can use `⟨a, b⟩` or `Sigma.mk a b` to create a dependent pair. - -```lean -universe u v - -def f (α : Type u) (β : α → Type v) (a : α) (b : β a) : (a : α) × β a := - ⟨a, b⟩ - -def g (α : Type u) (β : α → Type v) (a : α) (b : β a) : Σ a : α, β a := - Sigma.mk a b - -#reduce f -#reduce g - -#reduce f Type (fun α => α) Nat 10 -#reduce g Type (fun α => α) Nat 10 - -#reduce (f Type (fun α => α) Nat 10).1 -- Nat -#reduce (g Type (fun α => α) Nat 10).1 -- Nat -#reduce (f Type (fun α => α) Nat 10).2 -- 10 -#reduce (g Type (fun α => α) Nat 10).2 -- 10 -``` -The function `f` and `g` above denote the same function. diff --git a/doc/deptypes.md b/doc/deptypes.md deleted file mode 100644 index a7c5932946..0000000000 --- a/doc/deptypes.md +++ /dev/null @@ -1,3 +0,0 @@ -# Dependent Types - -In this section, we introduce simple type theory, types as objects, definitions, and explain what makes dependent type theory *dependent*. diff --git a/doc/dev/mdbook.md b/doc/dev/mdbook.md deleted file mode 100644 index eab9f4a187..0000000000 --- a/doc/dev/mdbook.md +++ /dev/null @@ -1,109 +0,0 @@ -# Documentation - -The Lean `doc` folder contains the [Lean Manual](https://lean-lang.org/lean4/doc/) and is -authored in a combination of markdown (`*.md`) files and literate Lean files. The .lean files are -preprocessed using a tool called [LeanInk](https://github.com/leanprover/leanink) and -[Alectryon](https://github.com/Kha/alectryon) which produces a generated markdown file. We then run -`mdbook` on the result to generate the html pages. - - -## Settings - -We are using the following settings while editing the markdown docs. - -```json -{ - "files.insertFinalNewline": true, - "files.trimTrailingWhitespace": true, - "[markdown]": { - "rewrap.wrappingColumn": 70 - } -} -``` - -## Build - -### Using Nix - -Building the manual using Nix (which is what the CI does) is as easy as -```bash -$ nix build --update-input lean ./doc -``` -You can also open a shell with `mdbook` for running the commands mentioned below with -`nix develop ./doc#book`. Otherwise, read on. - -### Manually - -To build and test the book you have to preprocess the .lean files with Alectryon then use our own -fork of the Rust tool named [mdbook](https://github.com/leanprover/mdbook). We have our own fork of -mdBook with the following additional features: - -* Add support for hiding lines in other languages - [#1339](https://github.com/rust-lang/mdBook/pull/1339) -* Make `mdbook test` call the `lean` compiler to test the snippets. -* Ability to test a single chapter at a time which is handy when you -are working on that chapter. See the `--chapter` option. - -So you need to setup these tools before you can run `mdBook`. - -1. install [Rust](https://www.rust-lang.org/tools/install) -which provides you with the `cargo` tool for building rust packages. -Then run the following: - ```bash - cargo install --git https://github.com/leanprover/mdBook mdbook - ``` - -1. Clone https://github.com/leanprover/LeanInk.git and run `lake build` then make the resulting - binary available to Alectryon using e.g. - ```bash - # make `leanInk` available in the current shell - export PATH=$PWD/build/bin:$PATH - ``` - -1. Create a Python 3.10 environment. - -1. Install Alectryon: - ``` - python3 -m pip install git+https://github.com/Kha/alectryon.git@typeid - ``` - -1. Now you are ready to process the `*.lean` files using Alectryon as follows: - - ``` - cd lean4/doc - alectryon --frontend lean4+markup examples/palindromes.lean --backend webpage -o palindromes.lean.md - ``` - - Repeat this for the other .lean files you care about or write a script to process them all. - -1. Now you can build the book using: - ``` - cd lean4/doc - mdbook build - ``` - -This will put the HTML in a `out` folder so you can load `out/index.html` in your web browser and -it should look like https://lean-lang.org/lean4/doc/. - -1. It is also handy to use e.g. [`mdbook watch`](https://rust-lang.github.io/mdBook/cli/watch.html) - in the `doc/` folder so that it keeps the html up to date while you are editing. - - ```bash - mdbook watch --open # opens the output in `out/` in your default browser - ``` - -## Testing Lean Snippets - -You can run the following in the `doc/` folder to test all the lean code snippets. - - ```bash - mdbook test - ``` - -and you can use the `--chapter` option to test a specific chapter that you are working on: - - ```bash - mdbook test --chapter Array - ``` - -Use chapter name `?` to get a list of all the chapter names. diff --git a/doc/examples.md b/doc/examples.md deleted file mode 100644 index cdecaae835..0000000000 --- a/doc/examples.md +++ /dev/null @@ -1,9 +0,0 @@ -Examples -======== - -- [Palindromes](examples/palindromes.lean.md) -- [Binary Search Trees](examples/bintree.lean.md) -- [A Certified Type Checker](examples/tc.lean.md) -- [The Well-Typed Interpreter](examples/interp.lean.md) -- [Dependent de Bruijn Indices](examples/deBruijn.lean.md) -- [Parametric Higher-Order Abstract Syntax](examples/phoas.lean.md) diff --git a/doc/examples/README.md b/doc/examples/README.md new file mode 100644 index 0000000000..6be7d6958c --- /dev/null +++ b/doc/examples/README.md @@ -0,0 +1,4 @@ +These examples are checked in Lean's CI to ensure that they continue +to work. They are included in the documentation section of the Lean +website via a script that copies the latest version, in order to +ensure that the website tracks Lean releases rather than `master`. diff --git a/doc/examples/bintree.lean.md b/doc/examples/bintree.lean.md deleted file mode 100644 index a9584d5478..0000000000 --- a/doc/examples/bintree.lean.md +++ /dev/null @@ -1,5 +0,0 @@ -(this example is rendered by Alectryon in the CI) - -```lean -{{#include bintree.lean}} -``` diff --git a/doc/examples/deBruijn.lean.md b/doc/examples/deBruijn.lean.md deleted file mode 100644 index 6a0b8c5060..0000000000 --- a/doc/examples/deBruijn.lean.md +++ /dev/null @@ -1,5 +0,0 @@ -(this example is rendered by Alectryon in the CI) - -```lean -{{#include deBruijn.lean}} -``` diff --git a/doc/examples/interp.lean.md b/doc/examples/interp.lean.md deleted file mode 100644 index d6989e2d83..0000000000 --- a/doc/examples/interp.lean.md +++ /dev/null @@ -1,5 +0,0 @@ -(this example is rendered by Alectryon in the CI) - -```lean -{{#include interp.lean}} -``` diff --git a/doc/examples/palindromes.lean.md b/doc/examples/palindromes.lean.md deleted file mode 100644 index 453239f4d7..0000000000 --- a/doc/examples/palindromes.lean.md +++ /dev/null @@ -1,5 +0,0 @@ -(this example is rendered by Alectryon in the CI) - -```lean -{{#include palindromes.lean}} -``` diff --git a/doc/examples/phoas.lean.md b/doc/examples/phoas.lean.md deleted file mode 100644 index 938a42c41d..0000000000 --- a/doc/examples/phoas.lean.md +++ /dev/null @@ -1,5 +0,0 @@ -(this example is rendered by Alectryon in the CI) - -```lean -{{#include phoas.lean}} -``` diff --git a/doc/examples/tc.lean.md b/doc/examples/tc.lean.md deleted file mode 100644 index 4de865d0cb..0000000000 --- a/doc/examples/tc.lean.md +++ /dev/null @@ -1,5 +0,0 @@ -(this example is rendered by Alectryon in the CI) - -```lean -{{#include tc.lean}} -``` diff --git a/doc/examples/widgets.lean.md b/doc/examples/widgets.lean.md deleted file mode 100644 index c674d80be5..0000000000 --- a/doc/examples/widgets.lean.md +++ /dev/null @@ -1,5 +0,0 @@ -(this chapter is rendered by Alectryon in the CI) - -```lean -{{#include widgets.lean}} -``` diff --git a/doc/expressions.md b/doc/expressions.md deleted file mode 100644 index b8a9bb8910..0000000000 --- a/doc/expressions.md +++ /dev/null @@ -1,550 +0,0 @@ -Expressions -=========== - -Every expression in Lean has a [Type](types.md). Every type is also an -expression of type `Sort u` for some universe level u. See [Type -Universes](types.md#type_universes). - -Expression Syntax -================= - -The set of expressions in Lean is defined inductively as follows: - -* ``Sort u`` : the universe of types at universe level ``u`` -* ``c`` : where ``c`` is an identifier denoting a declared constant or a defined object -* ``x`` : where ``x`` is a variable in the local context in which the expression is interpreted -* `m?` : where `m?` is a metavariable in the metavariable context in which the expression is interpreted, - you can view metavariable as a "hole" that still needs to be synthesized -* ``(x : α) → β`` : the type of functions taking an element ``x`` of ``α`` to an element of ``β``, - where ``β`` is an expression whose type is a ``Sort`` -* ``s t`` : the result of applying ``s`` to ``t``, where ``s`` and ``t`` are expressions -* ``fun x : α => t`` or `λ x : α => t`: the function mapping any value ``x`` of type ``α`` to ``t``, where ``t`` is an expression -* ``let x := t; s`` : a local definition, denotes the value of ``s`` when ``x`` is replaced by ``t`` -* `s.i` : a projection, denotes the value of the `i`-th field of `s` -* `lit` : a natural number or string literal -* `mdata k s` : the expression `s` decorated with metadata `k`, where is a key-value map - -Every well formed term in Lean has a *type*, which itself is an expression of type ``Sort u`` for some ``u``. The fact that a term ``t`` has type ``α`` is written ``t : α``. - -For an expression to be well formed, its components have to satisfy certain typing constraints. These, in turn, determine the type of the resulting term, as follows: - -* ``Sort u : Sort (u + 1)`` -* ``c : α``, where ``α`` is the type that ``c`` has been declared or defined to have -* ``x : α``, where ``α`` is the type that ``x`` has been assigned in the local context where it is interpreted -* ``?m : α``, where ``α`` is the type that ``?m`` has been declared in the metavariable context where it is interpreted -* ``(x : α) → β : Sort (imax u v)`` where ``α : Sort u``, and ``β : Sort v`` assuming ``x : α`` -* ``s t : β[t/x]`` where ``s`` has type ``(x : α) → β`` and ``t`` has type ``α`` -* ``(fun x : α => t) : (x : α) → β`` if ``t`` has type ``β`` whenever ``x`` has type ``α`` -* ``(let x := t; s) : β[t/x]`` where ``t`` has type ``α`` and ``s`` has type ``β`` assuming ``x : α`` -* `lit : Nat` if `lit` is a numeral -* `lit : String` if `lit` is a string literal -* `mdata k s : α` if `s : α` -* `s.i : α` if `s : β` and `β` is an inductive datatype with only one constructor, and `i`-th field has type `α` - -``Prop`` abbreviates ``Sort 0``, ``Type`` abbreviates ``Sort 1``, and -``Type u`` abbreviates ``Sort (u + 1)`` when ``u`` is a universe -variable. We say "``α`` is a type" to express ``α : Type u`` for some -``u``, and we say "``p`` is a proposition" to express -``p : Prop``. Using the *propositions as types* correspondence, given -``p : Prop``, we refer to an expression ``t : p`` as a *proof* of ``p``. In -contrast, given ``α : Type u`` for some ``u`` and ``t : α``, we -sometimes refer to ``t`` as *data*. - -When the expression ``β`` in ``(x : α) → β`` does not depend on ``x``, -it can be written ``α → β``. As usual, the variable ``x`` is bound in -``(x : α) → β``, ``fun x : α => t``, and ``let x := t; s``. The -expression ``∀ x : α, β`` is alternative syntax for ``(x : α) → β``, -and is intended to be used when ``β`` is a proposition. An underscore -can be used to generate an internal variable in a binder, as in -``fun _ : α => t``. - -*Metavariables*, that is, temporary placeholders, are used in the -process of constructing terms. Terms that are added to the -environment contain neither metavariable nor variables, which is to -say, they are fully elaborated and make sense in the empty context. - -Axioms can be declared using the ``axiom`` keyword. -Similarly, objects can be defined in various ways, such as using ``def`` and ``theorem`` keywords. -See [Chapter Declarations](./declarations.md) for more information. - -Writing an expression ``(t : α)`` forces Lean to elaborate ``t`` so that it has type ``α`` or report an error if it fails. - -Lean supports anonymous constructor notation, anonymous projections, -and various forms of match syntax, including destructuring ``fun`` and -``let``. These, as well as notation for common data types (like pairs, -lists, and so on) are discussed in [Chapter Declarations](./declarations.md) -in connection with inductive types. - -```lean -universe u - -#check Sort 0 -#check Prop -#check Sort 1 -#check Type -#check Sort u -#check Sort (u+1) - -#check Nat → Bool -#check (α : Type u) → List α -#check (α : Type u) → (β : Type u) → Sum α β -#check fun x : Nat => x -#check fun (α : Type u) (x : α) => x -#check let x := 5; x * 2 -#check "hello" -#check (fun x => x) true -``` - -Implicit Arguments -================== - -When declaring arguments to defined objects in Lean (for example, with -``def``, ``theorem``, ``axiom``, ``constant``, ``inductive``, or -``structure``; see [Chapter Declarations](./declarations.md) or when -declaring variables in sections (see [Other Commands](./other_commands.md)), -arguments can be annotated as *explicit* or *implicit*. -This determines how expressions containing the object are interpreted. - -* ``(x : α)`` : an explicit argument of type ``α`` -* ``{x : α}`` : an implicit argument, eagerly inserted -* ``⦃x : α⦄`` or ``{{x : α}}`` : an implicit argument, weakly inserted -* ``[x : α]`` : an implicit argument that should be inferred by type class resolution -* ``(x : α := v)`` : an optional argument, with default value ``v`` -* ``(x : α := by tac)`` : an implicit argument, to be synthesized by tactic ``tac`` - -The name of the variable can be omitted from a class resolution -argument, in which case an internal name is generated. - -When a function has an explicit argument, you can nonetheless ask -Lean's elaborator to infer the argument automatically, by entering it -as an underscore (``_``). Conversely, writing ``@foo`` indicates that -all of the arguments to be ``foo`` are to be given explicitly, -independent of how ``foo`` was declared. You can also provide a value -for an implicit parameter using named arguments. Named arguments -enable you to specify an argument for a parameter by matching the -argument with its name rather than with its position in the parameter -list. If you don't remember the order of the parameters but know -their names, you can send the arguments in any order. You may also -provide the value for an implicit parameter whenLean failed to infer -it. Named arguments also improve the readability of your code by -identifying what each argument represents. - - -```lean -def add (x y : Nat) : Nat := - x + y - -#check add 2 3 -- Nat -#eval add 2 3 -- 5 - -def id1 (α : Type u) (x : α) : α := x - -#check id1 Nat 3 -#check id1 _ 3 - -def id2 {α : Type u} (x : α) : α := x - -#check id2 3 -#check @id2 Nat 3 -#check id2 (α := Nat) 3 -#check id2 -#check id2 (α := Nat) - -def id3 {{α : Type u}} (x : α) : α := x - -#check id3 3 -#check @id3 Nat 3 -#check (id3 : (α : Type) → α → α) - -class Cls where - val : Nat - -instance Cls_five : Cls where - val := 5 - -def ex2 [c : Cls] : Nat := c.val - -example : ex2 = 5 := rfl - -def ex2a [Cls] : Nat := ex2 - -example : ex2a = 5 := rfl - -def ex3 (x : Nat := 5) := x - -#check ex3 2 -#check ex3 - -example : ex3 = 5 := rfl - -def ex4 (x : Nat) (y : Nat := x) : Nat := - x * y - -example : ex4 x = x * x := - rfl -``` - -Basic Data Types and Assertions -=============================== - -The core library contains a number of basic data types, such as the -natural numbers (`Nat`), the integers (`Int`), the -booleans (``Bool``), and common operations on these, as well as the -usual logical quantifiers and connectives. Some example are given -below. A list of common notations and their precedences can be found -in a [file](https://github.com/leanprover/lean4/blob/master/src/Init/Notation.lean) -in the core library. The core library also contains a number of basic -data type constructors. Definitions can also be found the -[Data](https://github.com/leanprover/lean4/blob/master/src/Init/Data) -directory of the core library. For more information, see also [Chapter libraries](./libraries.md). - -``` -/- numbers -/ -def f1 (a b c : Nat) : Nat := - a^2 + b^2 + c^2 - -def p1 (a b c d : Nat) : Prop := - (a + b)^c ≤ d - -def p2 (i j k : Int) : Prop := - i % (j * k) = 0 - - -/- booleans -/ - -def f2 (a b c : Bool) : Bool := - a && (b || c) - -/- pairs -/ - -#eval (1, 2) - -def p : Nat × Bool := (1, false) - -section -variable (a b c : Nat) (p : Nat × bool) - -#check (1, 2) -#check p.1 * 2 -#check p.2 && tt -#check ((1, 2, 3) : Nat × Nat × Nat) -end - -/- lists -/ -section -variable x y z : Nat -variable xs ys zs : list Nat -open list - -#check (1 :: xs) ++ (y :: zs) ++ [1,2,3] -#check append (cons 1 xs) (cons y zs) -#check map (λ x, x^2) [1, 2, 3] -end - -/- sets -/ -section -variable s t u : set Nat - -#check ({1, 2, 3} ∩ s) ∪ ({x | x < 7} ∩ t) -end - -/- strings and characters -/ -#check "hello world" -#check 'a' - -/- assertions -/ -#check ∀ a b c n : Nat, - a ≠ 0 ∧ b ≠ 0 ∧ c ≠ 0 ∧ n > 2 → a^n + b^n ≠ c^n - -def unbounded (f : Nat → Nat) : Prop := ∀ M, ∃ n, f n ≥ M -``` -.. _constructors_projections_and_matching: - -Constructors, Projections, and Matching -======================================= - -Lean's foundation, the *Calculus of Inductive Constructions*, supports the declaration of *inductive types*. Such types can have any number of *constructors*, and an associated *eliminator* (or *recursor*). Inductive types with one constructor, known as *structures*, have *projections*. The full syntax of inductive types is described in [Declarations](declarations.md), but here we describe some syntactic elements that facilitate their use in expressions. - -When Lean can infer the type of an expression and it is an inductive type with one constructor, then one can write ``⟨a1, a2, ..., an⟩`` to apply the constructor without naming it. For example, ``⟨a, b⟩`` denotes ``prod.mk a b`` in a context where the expression can be inferred to be a pair, and ``⟨h₁, h₂⟩`` denotes ``and.intro h₁ h₂`` in a context when the expression can be inferred to be a conjunction. The notation will nest constructions automatically, so ``⟨a1, a2, a3⟩`` is interpreted as ``prod.mk a1 (prod.mk a2 a3)`` when the expression is expected to have a type of the form ``α1 × α2 × α3``. (The latter is interpreted as ``α1 × (α2 × α3)``, since the product associates to the right.) - -Similarly, one can use "dot notation" for projections: one can write ``p.fst`` and ``p.snd`` for ``prod.fst p`` and ``prod.snd p`` when Lean can infer that ``p`` is an element of a product, and ``h.left`` and ``h.right`` for ``and.left h`` and ``and.right h`` when ``h`` is a conjunction. - -The anonymous projector notation can used more generally for any objects defined in a *namespace* (see [Other Commands](other_commands.md)). For example, if ``l`` has type ``list α`` then ``l.map f`` abbreviates ``list.map f l``, in which ``l`` has been placed at the first argument position where ``list.map`` expects a ``list``. - -Finally, for data types with one constructor, one destruct an element by pattern matching using the ``let`` and ``assume`` constructs, as in the examples below. Internally, these are interpreted using the ``match`` construct, which is in turn compiled down for the eliminator for the inductive type, as described in [Declarations](declarations.md). - -.. code-block:: lean - - universes u v - variable {α : Type u} {β : Type v} - - def p : Nat × ℤ := ⟨1, 2⟩ - #check p.fst - #check p.snd - - def p' : Nat × ℤ × bool := ⟨1, 2, tt⟩ - #check p'.fst - #check p'.snd.fst - #check p'.snd.snd - - def swap_pair (p : α × β) : β × α := - ⟨p.snd, p.fst⟩ - - theorem swap_conj {a b : Prop} (h : a ∧ b) : b ∧ a := - ⟨h.right, h.left⟩ - - #check [1, 2, 3].append [2, 3, 4] - #check [1, 2, 3].map (λ x, x^2) - - example (p q : Prop) : p ∧ q → q ∧ p := - λ h, ⟨h.right, h.left⟩ - - def swap_pair' (p : α × β) : β × α := - let (x, y) := p in (y, x) - - theorem swap_conj' {a b : Prop} (h : a ∧ b) : b ∧ a := - let ⟨ha, hb⟩ := h in ⟨hb, ha⟩ - - def swap_pair'' : α × β → β × α := - λ ⟨x, y⟩, (y, x) - - theorem swap_conj'' {a b : Prop} : a ∧ b → b ∧ a := - assume ⟨ha, hb⟩, ⟨hb, ha⟩ - -Structured Proofs -================= - -Syntactic sugar is provided for writing structured proof terms: - -* ``have h : p := s; t`` is sugar for ``(fun h : p => t) s`` -* ``suffices h : p from s; t`` is sugar for ``(λ h : p => s) t`` -* ``suffices h : p by s; t`` is sugar for ``(suffixes h : p from by s; t)`` -* ``show p from t`` is sugar for ``(have this : p := t; this)`` -* ``show p by tac`` is sugar for ``(show p from by tac)`` - -Types can be omitted when they can be inferred by Lean. Lean also -allows ``have : p := t; s``, which gives the assumption the -name ``this`` in the local context. Similarly, Lean recognizes the -variant ``suffices p from s; t``, which use the name ``this`` for the new hypothesis. - -The notation ``‹p›`` is notation for ``(by assumption : p)``, and can -therefore be used to apply hypotheses in the local context. - -As noted in [Constructors, Projections and Matching](#constructors_projections_and_matching), -anonymous constructors and projections and match syntax can be used in proofs just as in expressions that denote data. - -.. code-block:: lean - - example (p q r : Prop) : p → (q ∧ r) → p ∧ q := - assume h₁ : p, - assume h₂ : q ∧ r, - have h₃ : q, from and.left h₂, - show p ∧ q, from and.intro h₁ h₃ - - example (p q r : Prop) : p → (q ∧ r) → p ∧ q := - assume : p, - assume : q ∧ r, - have q, from and.left this, - show p ∧ q, from and.intro ‹p› this - - example (p q r : Prop) : p → (q ∧ r) → p ∧ q := - assume h₁ : p, - assume h₂ : q ∧ r, - suffices h₃ : q, from and.intro h₁ h₃, - show q, from and.left h₂ - -Lean also supports a calculational environment, which is introduced with the keyword ``calc``. The syntax is as follows: - -.. code-block:: text - - calc - _0 'op_1' _1 ':' _1 - '...' 'op_2' _2 ':' _2 - ... - '...' 'op_n' _n ':' _n - -Each ``_i`` is a proof for ``_{i-1} op_i _i``. - -Here is an example: - -.. code-block:: lean - - variable (a b c d e : Nat) - variable h1 : a = b - variable h2 : b = c + 1 - variable h3 : c = d - variable h4 : e = 1 + d - - theorem T : a = e := - calc - a = b : h1 - ... = c + 1 : h2 - ... = d + 1 : congr_arg _ h3 - ... = 1 + d : add_comm d (1 : Nat) - ... = e : eq.symm h4 - -The style of writing proofs is most effective when it is used in conjunction with the ``simp`` and ``rewrite`` tactics. - -.. _computation: - -Computation -=========== - -Two expressions that differ up to a renaming of their bound variables are said to be *α-equivalent*, and are treated as syntactically equivalent by Lean. - -Every expression in Lean has a natural computational interpretation, unless it involves classical elements that block computation, as described in the next section. The system recognizes the following notions of *reduction*: - -* *β-reduction* : An expression ``(λ x, t) s`` β-reduces to ``t[s/x]``, that is, the result of replacing ``x`` by ``s`` in ``t``. -* *ζ-reduction* : An expression ``let x := s in t`` ζ-reduces to ``t[s/x]``. -* *δ-reduction* : If ``c`` is a defined constant with definition ``t``, then ``c`` δ-reduces to ``t``. -* *ι-reduction* : When a function defined by recursion on an inductive type is applied to an element given by an explicit constructor, the result ι-reduces to the specified function value, as described in [Inductive Types](inductive.md). - -The reduction relation is transitive, which is to say, is ``s`` reduces to ``s'`` and ``t`` reduces to ``t'``, then ``s t`` reduces to ``s' t'``, ``λ x, s`` reduces to ``λ x, s'``, and so on. If ``s`` and ``t`` reduce to a common term, they are said to be *definitionally equal*. Definitional equality is defined to be the smallest equivalence relation that satisfies all these properties and also includes α-equivalence and the following two relations: - -* *η-equivalence* : An expression ``(λx, t x)`` is η-equivalent to ``t``, assuming ``x`` does not occur in ``t``. -* *proof irrelevance* : If ``p : Prop``, ``s : p``, and ``t : p``, then ``s`` and ``t`` are considered to be equivalent. - -This last fact reflects the intuition that once we have proved a proposition ``p``, we only care that is has been proved; the proof does nothing more than witness the fact that ``p`` is true. - -Definitional equality is a strong notion of equality of values. Lean's logical foundations sanction treating definitionally equal terms as being the same when checking that a term is well-typed and/or that it has a given type. - -The reduction relation is believed to be strongly normalizing, which is to say, every sequence of reductions applied to a term will eventually terminate. The property guarantees that Lean's type-checking algorithm terminates, at least in principle. The consistency of Lean and its soundness with respect to set-theoretic semantics do not depend on either of these properties. - -Lean provides two commands to compute with expressions: - -* ``#reduce t`` : use the kernel type-checking procedures to carry out reductions on ``t`` until no more reductions are possible, and show the result -* ``#eval t`` : evaluate ``t`` using a fast bytecode evaluator, and show the result - -Every computable definition in Lean is compiled to bytecode at definition time. Bytecode evaluation is more liberal than kernel evaluation: types and all propositional information are erased, and functions are evaluated using a stack-based virtual machine. As a result, ``#eval`` is more efficient than ``#reduce,`` and can be used to execute complex programs. In contrast, ``#reduce`` is designed to be small and reliable, and to produce type-correct terms at each step. Bytecode is never used in type checking, so as far as soundness and consistency are concerned, only kernel reduction is part of the trusted computing base. - -.. code-block:: lean - - #reduce (fun x => x + 3) 5 - #eval (fun x => x + 3) 5 - - #reduce let x := 5; x + 3 - #eval let x := 5; x + 3 - - def f x := x + 3 - - #reduce f 5 - #eval f 5 - - #reduce @Nat.rec (λ n => Nat) (0 : Nat) - (λ n recval : Nat => recval + n + 1) (5 : Nat) - - def g : Nat → Nat - | 0 => 0 - | (n+1) => g n + n + 1 - - #reduce g 5 - #eval g 5 - - #eval g 5000 - - example : (fun x => x + 3) 5 = 8 := rfl - example : (fun x => f x) = f := rfl - example (p : Prop) (h₁ h₂ : p) : h₁ = h₂ := rfl - -Note: the combination of proof irrelevance and singleton ``Prop`` elimination in ι-reduction renders the ideal version of definitional equality, as described above, undecidable. Lean's procedure for checking definitional equality is only an approximation to the ideal. It is not transitive, as illustrated by the example below. Once again, this does not compromise the consistency or soundness of Lean; it only means that Lean is more conservative in the terms it recognizes as well typed, and this does not cause problems in practice. Singleton elimination will be discussed in greater detail in [Inductive Types](inductive.md). - -.. code-block:: lean - - def R (x y : unit) := false - def accrec := @acc.rec unit R (λ_, unit) (λ _ a ih, ()) () - example (h) : accrec h = accrec (acc.intro _ (λ y, acc.inv h)) := - rfl - example (h) : accrec (acc.intro _ (λ y, acc.inv h)) = () := rfl - example (h) : accrec h = () := sorry -- rfl fails - - -Axioms -====== - -Lean's foundational framework consists of: - -- type universes and dependent function types, as described above - -- inductive definitions, as described in [Inductive Types](inductive.md) and -[Inductive Families](declarations.md#inductive-families). - -In addition, the core library defines (and trusts) the following axiomatic extensions: - -- propositional extensionality: - - .. code-block:: lean - - namespace hide - - -- BEGIN - axiom propext {a b : Prop} : (a ↔ b) → a = b - -- END - - end hide - -- quotients: - - .. code-block:: lean - - namespace hide - -- BEGIN - universes u v - - constant quot : Π {α : Sort u}, (α → α → Prop) → Sort u - - constant quot.mk : Π {α : Sort u} (r : α → α → Prop), - α → quot r - - axiom quot.ind : ∀ {α : Sort u} {r : α → α → Prop} - {β : quot r → Prop}, - (∀ a, β (quot.mk r a)) → - ∀ (q : quot r), β q - - constant quot.lift : Π {α : Sort u} {r : α → α → Prop} - {β : Sort u} (f : α → β), - (∀ a b, r a b → f a = f b) → quot r → β - - axiom quot.sound : ∀ {α : Type u} {r : α → α → Prop} - {a b : α}, - r a b → quot.mk r a = quot.mk r b - -- END - end hide - - ``quot r`` represents the quotient of ``α`` by the smallest equivalence relation containing ``r``. ``quot.mk`` and ``quot.lift`` satisfy the following computation rule: - - .. code-block:: text - - quot.lift f h (quot.mk r a) = f a - -- choice: - - .. code-block:: lean - - namespace hide - universe u - - -- BEGIN - axiom choice {α : Sort u} : nonempty α → α - -- END - - end hide - - Here ``nonempty α`` is defined as follows: - - .. code-block:: lean - - namespace hide - universe u - - -- BEGIN - class inductive nonempty (α : Sort u) : Prop - | intro : α → nonempty - -- END - - end hide - - It is equivalent to ``∃ x : α, true``. - -The quotient construction implies function extensionality. The ``choice`` principle, in conjunction with the others, makes the axiomatic foundation classical; in particular, it implies the law of the excluded middle and propositional decidability. Functions that make use of ``choice`` to produce data are incompatible with a computational interpretation, and do not produce bytecode. They have to be declared ``noncomputable``. - -For metaprogramming purposes, Lean also allows the definition of objects which stand outside the object language. These are denoted with the ``meta`` keyword, as described in [Metaprogramming](metaprogramming.md). diff --git a/doc/faq.md b/doc/faq.md deleted file mode 100644 index 9ae9813755..0000000000 --- a/doc/faq.md +++ /dev/null @@ -1,55 +0,0 @@ -Frequently Asked Questions -========================== - -### What is Lean? - -Lean is a new open source theorem prover being developed at Microsoft Research. -It is a research project that aims to bridge the gap between interactive and automated theorem proving. -Lean can be also used as a programming language. Actually, some Lean features are implemented in Lean itself. - -### Should I use Lean? - -Lean is under heavy development, and we are constantly trying new -ideas and tweaking the system. It is a research project and not a product. -Things change rapidly, and we constantly break backward compatibility. -Lean comes "as is", you should not expect we will fix bugs and/or add new features for your project. -We have our own priorities, and will not change them to accommodate your needs. -Even if you implement a new feature or fix a bug, we may not want to merge it because -it may conflict with our plans for Lean, it may not be performant, we may not want to maintain it, -we may be busy, etc. If you really need this new feature or bug fix, we suggest you create your own fork and maintain it yourself. - -### Where is the documentation? - -This is the Lean 4 manual. It is a work in progress, but it will eventually cover the whole language. -A public and very active chat room dedicated to Lean is open on [Zulip](https://leanprover.zulipchat.com). -It is a good place to interact with other Lean users. - -### Should I use Lean to teach a course? - -Lean has been used to teach courses on logic, type theory and programming languages at CMU and the University of Washington. -The lecture notes for the CMU course [Logic and Proof](https://lean-lang.org/logic_and_proof) are available online, -but they are for Lean 3. -If you decide to teach a course using Lean, we suggest you prepare all material before the beginning of the course, and -make sure that Lean attends all your needs. You should not expect we will fix bugs and/or add features needed for your course. - -### Are there IDEs for Lean? - -Yes, see [Setting Up Lean](./setup.md). - -### Is Lean sound? How big is the kernel? Should I trust it? - -Lean has a relatively small kernel. -Several independent checkers have been implemented for Lean 3. Two of them are -[tc](https://github.com/leanprover/tc) and [trepplein](https://github.com/gebner/trepplein). -We expect similar independent checkers will be built for Lean 4. - -### Should I open a new issue? - -We use [GitHub](https://github.com/leanprover/lean4/issues) to track bugs and new features. -Bug reports are always welcome, but nitpicking issues are not (e.g., the error message is confusing). -See also our [contribution guidelines](https://github.com/leanprover/lean4/blob/master/CONTRIBUTING.md). - -### Is it Lean, LEAN, or L∃∀N? - -We always use "Lean" in writing. -When specifying a major version number, we append it together with a single space: Lean 4. diff --git a/doc/flake.lock b/doc/flake.lock deleted file mode 100644 index da279454f6..0000000000 --- a/doc/flake.lock +++ /dev/null @@ -1,151 +0,0 @@ -{ - "nodes": { - "alectryon": { - "flake": false, - "locked": { - "lastModified": 1654613606, - "narHash": "sha256-IGCn1PzTyw8rrwmyWUiw3Jo/dyZVGkMslnHYW7YB8yk=", - "owner": "Kha", - "repo": "alectryon", - "rev": "c3b16f650665745e1da4ddfcc048d3bd639f71d5", - "type": "github" - }, - "original": { - "owner": "Kha", - "ref": "typeid", - "repo": "alectryon", - "type": "github" - } - }, - "flake-utils": { - "inputs": { - "systems": "systems" - }, - "locked": { - "lastModified": 1710146030, - "narHash": "sha256-SZ5L6eA7HJ/nmkzGG7/ISclqe6oZdOZTNoesiInkXPQ=", - "owner": "numtide", - "repo": "flake-utils", - "rev": "b1d9ab70662946ef0850d488da1c9019f3a9752a", - "type": "github" - }, - "original": { - "owner": "numtide", - "repo": "flake-utils", - "type": "github" - } - }, - "lean": { - "inputs": { - "flake-utils": "flake-utils", - "nixpkgs": "nixpkgs", - "nixpkgs-old": "nixpkgs-old" - }, - "locked": { - "lastModified": 0, - "narHash": "sha256-saRAtQ6VautVXKDw1XH35qwP0KEBKTKZbg/TRa4N9Vw=", - "path": "../.", - "type": "path" - }, - "original": { - "path": "../.", - "type": "path" - } - }, - "leanInk": { - "flake": false, - "locked": { - "lastModified": 1704976501, - "narHash": "sha256-FSBUsbX0HxakSnYRYzRBDN2YKmH9EkA0q9p7TSPEJTI=", - "owner": "leanprover", - "repo": "LeanInk", - "rev": "51821e3c2c032c88e4b2956483899d373ec090c4", - "type": "github" - }, - "original": { - "owner": "leanprover", - "ref": "refs/pull/57/merge", - "repo": "LeanInk", - "type": "github" - } - }, - "mdBook": { - "flake": false, - "locked": { - "lastModified": 1660074464, - "narHash": "sha256-W30G7AeWBjdJE/CQZJU5vJjaDGZtpmxEKNMEvaYtuF8=", - "owner": "leanprover", - "repo": "mdBook", - "rev": "9321c10c502cd59eea8afc4325a84eab3ddf9391", - "type": "github" - }, - "original": { - "owner": "leanprover", - "repo": "mdBook", - "type": "github" - } - }, - "nixpkgs": { - "locked": { - "lastModified": 1710889954, - "narHash": "sha256-Pr6F5Pmd7JnNEMHHmspZ0qVqIBVxyZ13ik1pJtm2QXk=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "7872526e9c5332274ea5932a0c3270d6e4724f3b", - "type": "github" - }, - "original": { - "owner": "NixOS", - "ref": "nixpkgs-unstable", - "repo": "nixpkgs", - "type": "github" - } - }, - "nixpkgs-old": { - "flake": false, - "locked": { - "lastModified": 1581379743, - "narHash": "sha256-i1XCn9rKuLjvCdu2UeXKzGLF6IuQePQKFt4hEKRU5oc=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "34c7eb7545d155cc5b6f499b23a7cb1c96ab4d59", - "type": "github" - }, - "original": { - "owner": "NixOS", - "ref": "nixos-19.03", - "repo": "nixpkgs", - "type": "github" - } - }, - "root": { - "inputs": { - "alectryon": "alectryon", - "flake-utils": [ - "lean", - "flake-utils" - ], - "lean": "lean", - "leanInk": "leanInk", - "mdBook": "mdBook" - } - }, - "systems": { - "locked": { - "lastModified": 1681028828, - "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", - "owner": "nix-systems", - "repo": "default", - "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", - "type": "github" - }, - "original": { - "owner": "nix-systems", - "repo": "default", - "type": "github" - } - } - }, - "root": "root", - "version": 7 -} diff --git a/doc/flake.nix b/doc/flake.nix deleted file mode 100644 index 4edef9e4a8..0000000000 --- a/doc/flake.nix +++ /dev/null @@ -1,93 +0,0 @@ -{ - description = "Lean documentation"; - - inputs.lean.url = path:../.; - inputs.flake-utils.follows = "lean/flake-utils"; - inputs.mdBook = { - url = "github:leanprover/mdBook"; - flake = false; - }; - inputs.alectryon = { - url = "github:Kha/alectryon/typeid"; - flake = false; - }; - inputs.leanInk = { - url = "github:leanprover/LeanInk/refs/pull/57/merge"; - flake = false; - }; - - outputs = inputs@{ self, ... }: inputs.flake-utils.lib.eachDefaultSystem (system: - with inputs.lean.packages.${system}.deprecated; with nixpkgs; - let - doc-src = lib.sourceByRegex ../. ["doc.*" "tests(/lean(/beginEndAsMacro.lean)?)?"]; - in { - packages = rec { - lean-mdbook = mdbook.overrideAttrs (drv: rec { - name = "lean-${mdbook.name}"; - src = inputs.mdBook; - cargoDeps = drv.cargoDeps.overrideAttrs (_: { - inherit src; - outputHash = "sha256-CO3A9Kpp4sIvkT9X3p+GTidazk7Fn4jf0AP2PINN44A="; - }); - doCheck = false; - }); - book = stdenv.mkDerivation { - name ="lean-doc"; - src = doc-src; - buildInputs = [ lean-mdbook ]; - buildCommand = '' - mkdir $out - # necessary for `additional-css`...? - cp -r --no-preserve=mode $src/doc/* . - # overwrite stub .lean.md files - cp -r ${inked}/* . - mdbook build -d $out - ''; - }; - leanInk = (buildLeanPackage { - name = "Main"; - src = inputs.leanInk; - deps = [ (buildLeanPackage { - name = "LeanInk"; - src = inputs.leanInk; - }) ]; - executableName = "leanInk"; - linkFlags = ["-rdynamic"]; - }).executable; - alectryon = python3Packages.buildPythonApplication { - name = "alectryon"; - src = inputs.alectryon; - propagatedBuildInputs = - [ leanInk lean-all ] ++ - # https://github.com/cpitclaudel/alectryon/blob/master/setup.cfg - (with python3Packages; [ pygments dominate beautifulsoup4 docutils ]); - doCheck = false; - }; - renderLeanMod = mod: mod.overrideAttrs (final: prev: { - name = "${prev.name}.md"; - buildInputs = prev.buildInputs ++ [ alectryon ]; - outputs = [ "out" ]; - buildCommand = '' - dir=$(dirname $relpath) - mkdir -p $dir out/$dir - if [ -d $src ]; then cp -r $src/. $dir/; else cp $src $leanPath; fi - alectryon --frontend lean4+markup $leanPath --backend webpage -o $out/$leanPath.md - ''; - }); - renderPackage = pkg: symlinkJoin { - name = "${pkg.name}-mds"; - paths = map renderLeanMod (lib.attrValues pkg.mods); - }; - literate = buildLeanPackage { - name = "literate"; - src = ./.; - roots = [ - { mod = "examples"; glob = "submodules"; } - ]; - }; - inked = renderPackage literate; - doc = book; - }; - defaultPackage = self.packages.${system}.doc; - }); -} diff --git a/doc/fplean.md b/doc/fplean.md deleted file mode 100644 index 76e613884c..0000000000 --- a/doc/fplean.md +++ /dev/null @@ -1,7 +0,0 @@ -Functional Programming in Lean -======================= - -The goal of [this book](https://lean-lang.org/functional_programming_in_lean/) is to be an accessible introduction to using Lean 4 as a programming language. -It should be useful both to people who want to use Lean as a general-purpose programming language and to mathematicians who want to develop larger-scale proof automation but do not have a background in functional programming. -It does not assume any background with functional programming, though it's probably not a good first book on programming in general. -New content will be added once per month until it's done. diff --git a/doc/funabst.md b/doc/funabst.md deleted file mode 100644 index f63b4afe7f..0000000000 --- a/doc/funabst.md +++ /dev/null @@ -1,145 +0,0 @@ -## Function Abstraction and Evaluation - -We have seen that if we have ``m n : Nat``, then we have ``(m, n) : Nat × Nat``. -This gives us a way of creating pairs of natural numbers. -Conversely, if we have ``p : Nat × Nat``, then -we have ``p.1 : Nat`` and ``p.2 : Nat``. -This gives us a way of "using" a pair, by extracting its two components. - -We already know how to "use" a function ``f : α → β``, namely, -we can apply it to an element ``a : α`` to obtain ``f a : β``. -But how do we create a function from another expression? - -The companion to application is a process known as "lambda abstraction." -Suppose that giving a variable ``x : α`` we can construct an expression ``t : β``. -Then the expression ``fun (x : α) => t``, or, equivalently, ``λ (x : α) => t``, is an object of type ``α → β``. -Think of this as the function from ``α`` to ``β`` which maps any value ``x`` to the value ``t``, -which may depend on ``x``. - -```lean -#check fun (x : Nat) => x + 5 -#check λ (x : Nat) => x + 5 -#check fun x : Nat => x + 5 -#check λ x : Nat => x + 5 -``` - -Here are some more examples: - -```lean -constant f : Nat → Nat -constant h : Nat → Bool → Nat - -#check fun x : Nat => fun y : Bool => h (f x) y -- Nat → Bool → Nat -#check fun (x : Nat) (y : Bool) => h (f x) y -- Nat → Bool → Nat -#check fun x y => h (f x) y -- Nat → Bool → Nat -``` - -Lean interprets the final three examples as the same expression; in the last expression, -Lean infers the type of ``x`` and ``y`` from the types of ``f`` and ``h``. - -Some mathematically common examples of operations of functions can be described in terms of lambda abstraction: - -```lean -constant f : Nat → String -constant g : String → Bool -constant b : Bool - -#check fun x : Nat => x -- Nat → Nat -#check fun x : Nat => b -- Nat → Bool -#check fun x : Nat => g (f x) -- Nat → Bool -#check fun x => g (f x) -- Nat → Bool -``` - -Think about what these expressions mean. The expression ``fun x : Nat => x`` denotes the identity function on ``Nat``, -the expression ``fun x : α => b`` denotes the constant function that always returns ``b``, -and ``fun x : Nat => g (f x)``, denotes the composition of ``f`` and ``g``. -We can, in general, leave off the type annotation on a variable and let Lean infer it for us. -So, for example, we can write ``fun x => g (f x)`` instead of ``fun x : Nat => g (f x)``. - -We can abstract over the constants `f` and `g` in the previous definitions: - -```lean -#check fun (g : String → Bool) (f : Nat → String) (x : Nat) => g (f x) --- (String → Bool) → (Nat → String) → Nat → Bool -``` - -We can also abstract over types: - -```lean -#check fun (α β γ : Type) (g : β → γ) (f : α → β) (x : α) => g (f x) -``` -The last expression, for example, denotes the function that takes three types, ``α``, ``β``, and ``γ``, and two functions, ``g : β → γ`` and ``f : α → β``, and returns the composition of ``g`` and ``f``. (Making sense of the type of this function requires an understanding of dependent products, which we will explain below.) Within a lambda expression ``fun x : α => t``, the variable ``x`` is a "bound variable": it is really a placeholder, whose "scope" does not extend beyond ``t``. -For example, the variable ``b`` in the expression ``fun (b : β) (x : α) => b`` has nothing to do with the constant ``b`` declared earlier. -In fact, the expression denotes the same function as ``fun (u : β) (z : α), u``. Formally, the expressions that are the same up to a renaming of bound variables are called *alpha equivalent*, and are considered "the same." Lean recognizes this equivalence. - -Notice that applying a term ``t : α → β`` to a term ``s : α`` yields an expression ``t s : β``. -Returning to the previous example and renaming bound variables for clarity, notice the types of the following expressions: - -```lean -#check (fun x : Nat => x) 1 -- Nat -#check (fun x : Nat => true) 1 -- Bool - -constant f : Nat → String -constant g : String → Bool - -#check - (fun (α β γ : Type) (g : β → γ) (f : α → β) (x : α) => g (f x)) Nat String Bool g f 0 - -- Bool -``` - -As expected, the expression ``(fun x : Nat => x) 1`` has type ``Nat``. -In fact, more should be true: applying the expression ``(fun x : Nat => x)`` to ``1`` should "return" the value ``1``. And, indeed, it does: - -```lean -#reduce (fun x : Nat => x) 1 -- 1 -#reduce (fun x : Nat => true) 1 -- true - -constant f : Nat → String -constant g : String → Bool - -#reduce - (fun (α β γ : Type) (g : β → γ) (f : α → β) (x : α) => g (f x)) Nat String Bool g f 0 - -- g (f 0) -``` - -The command ``#reduce`` tells Lean to evaluate an expression by *reducing* it to its normal form, -which is to say, carrying out all the computational reductions that are sanctioned by its kernel. -The process of simplifying an expression ``(fun x => t) s`` to ``t[s/x]`` -- that is, ``t`` with ``s`` substituted for the variable ``x`` -- -is known as *beta reduction*, and two terms that beta reduce to a common term are called *beta equivalent*. -But the ``#reduce`` command carries out other forms of reduction as well: - -```lean -constant m : Nat -constant n : Nat -constant b : Bool - -#reduce (m, n).1 -- m -#reduce (m, n).2 -- n - -#reduce true && false -- false -#reduce false && b -- false -#reduce b && false -- Bool.rec false false b - -#reduce n + 0 -- n -#reduce n + 2 -- Nat.succ (Nat.succ n) -#reduce 2 + 3 -- 5 -``` - -We explain later how these terms are evaluated. -For now, we only wish to emphasize that this is an important feature of dependent type theory: -every term has a computational behavior, and supports a notion of reduction, or *normalization*. -In principle, two terms that reduce to the same value are called *definitionally equal*. -They are considered "the same" by Lean's type checker, and Lean does its best to recognize and support these identifications. -The `#reduce` command is mainly useful to understand why two terms are considered the same. - -Lean is also a programming language. It has a compiler to native code and an interpreter. -You can use the command `#eval` to execute expressions, and it is the preferred way of testing your functions. -Note that `#eval` and `#reduce` are *not* equivalent. The command `#eval` first compiles Lean expressions -into an intermediate representation (IR) and then uses an interpreter to execute the generated IR. -Some builtin types (e.g., `Nat`, `String`, `Array`) have a more efficient representation in the IR. -The IR has support for using foreign functions that are opaque to Lean. - -In contrast, the ``#reduce`` command relies on a reduction engine similar to the one used in Lean's trusted kernel, -the part of Lean that is responsible for checking and verifying the correctness of expressions and proofs. -It is less efficient than ``#eval``, and treats all foreign functions as opaque constants. -We later discuss other differences between the two commands. diff --git a/doc/highlight.js b/doc/highlight.js deleted file mode 100644 index 34bf0e1466..0000000000 --- a/doc/highlight.js +++ /dev/null @@ -1,1209 +0,0 @@ -/* - Highlight.js 10.3.2 (31e1fc40) - License: BSD-3-Clause - Copyright (c) 2006-2020, Ivan Sagalaev -*/ -var hljs=function(){"use strict";function e(n){Object.freeze(n) -;var t="function"==typeof n -;return Object.getOwnPropertyNames(n).forEach((function(r){ -!Object.hasOwnProperty.call(n,r)||null===n[r]||"object"!=typeof n[r]&&"function"!=typeof n[r]||t&&("caller"===r||"callee"===r||"arguments"===r)||Object.isFrozen(n[r])||e(n[r]) -})),n}class n{constructor(e){void 0===e.data&&(e.data={}),this.data=e.data} -ignoreMatch(){this.ignore=!0}}function t(e){ -return e.replace(/&/g,"&").replace(//g,">").replace(/"/g,""").replace(/'/g,"'") -}function r(e,...n){var t={};for(const n in e)t[n]=e[n] -;return n.forEach((function(e){for(const n in e)t[n]=e[n]})),t}function a(e){ -return e.nodeName.toLowerCase()}var i=Object.freeze({__proto__:null, -escapeHTML:t,inherit:r,nodeStream:function(e){var n=[];return function e(t,r){ -for(var i=t.firstChild;i;i=i.nextSibling)3===i.nodeType?r+=i.nodeValue.length:1===i.nodeType&&(n.push({ -event:"start",offset:r,node:i}),r=e(i,r),a(i).match(/br|hr|img|input/)||n.push({ -event:"stop",offset:r,node:i}));return r}(e,0),n},mergeStreams:function(e,n,r){ -var i=0,s="",o=[];function l(){ -return e.length&&n.length?e[0].offset!==n[0].offset?e[0].offset"}function u(e){ -s+=""}function g(e){("start"===e.event?c:u)(e.node)} -for(;e.length||n.length;){var d=l() -;if(s+=t(r.substring(i,d[0].offset)),i=d[0].offset,d===e){o.reverse().forEach(u) -;do{g(d.splice(0,1)[0]),d=l()}while(d===e&&d.length&&d[0].offset===i) -;o.reverse().forEach(c) -}else"start"===d[0].event?o.push(d[0].node):o.pop(),g(d.splice(0,1)[0])} -return s+t(r.substr(i))}});const s=e=>!!e.kind;class o{constructor(e,n){ -this.buffer="",this.classPrefix=n.classPrefix,e.walk(this)}addText(e){ -this.buffer+=t(e)}openNode(e){if(!s(e))return;let n=e.kind -;e.sublanguage||(n=`${this.classPrefix}${n}`),this.span(n)}closeNode(e){ -s(e)&&(this.buffer+="")}value(){return this.buffer}span(e){ -this.buffer+=``}}class l{constructor(){this.rootNode={ -children:[]},this.stack=[this.rootNode]}get top(){ -return this.stack[this.stack.length-1]}get root(){return this.rootNode}add(e){ -this.top.children.push(e)}openNode(e){const n={kind:e,children:[]} -;this.add(n),this.stack.push(n)}closeNode(){ -if(this.stack.length>1)return this.stack.pop()}closeAllNodes(){ -for(;this.closeNode(););}toJSON(){return JSON.stringify(this.rootNode,null,4)} -walk(e){return this.constructor._walk(e,this.rootNode)}static _walk(e,n){ -return"string"==typeof n?e.addText(n):n.children&&(e.openNode(n), -n.children.forEach((n=>this._walk(e,n))),e.closeNode(n)),e}static _collapse(e){ -"string"!=typeof e&&e.children&&(e.children.every((e=>"string"==typeof e))?e.children=[e.children.join("")]:e.children.forEach((e=>{ -l._collapse(e)})))}}class c extends l{constructor(e){super(),this.options=e} -addKeyword(e,n){""!==e&&(this.openNode(n),this.addText(e),this.closeNode())} -addText(e){""!==e&&this.add(e)}addSublanguage(e,n){const t=e.root -;t.kind=n,t.sublanguage=!0,this.add(t)}toHTML(){ -return new o(this,this.options).value()}finalize(){return!0}}function u(e){ -return e?"string"==typeof e?e:e.source:null} -const g="[a-zA-Z]\\w*",d="[a-zA-Z_]\\w*",h="\\b\\d+(\\.\\d+)?",f="(-?)(\\b0[xX][a-fA-F0-9]+|(\\b\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)",p="\\b(0b[01]+)",m={ -begin:"\\\\[\\s\\S]",relevance:0},b={className:"string",begin:"'",end:"'", -illegal:"\\n",contains:[m]},v={className:"string",begin:'"',end:'"', -illegal:"\\n",contains:[m]},x={ -begin:/\b(a|an|the|are|I'm|isn't|don't|doesn't|won't|but|just|should|pretty|simply|enough|gonna|going|wtf|so|such|will|you|your|they|like|more)\b/ -},E=function(e,n,t={}){var a=r({className:"comment",begin:e,end:n,contains:[] -},t);return a.contains.push(x),a.contains.push({className:"doctag", -begin:"(?:TODO|FIXME|NOTE|BUG|OPTIMIZE|HACK|XXX):",relevance:0}),a -},_=E("//","$"),w=E("/\\*","\\*/"),N=E("#","$");var y=Object.freeze({ -__proto__:null,IDENT_RE:g,UNDERSCORE_IDENT_RE:d,NUMBER_RE:h,C_NUMBER_RE:f, -BINARY_NUMBER_RE:p, -RE_STARTERS_RE:"!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|-|-=|/=|/|:|;|<<|<<=|<=|<|===|==|=|>>>=|>>=|>=|>>>|>>|>|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~", -SHEBANG:(e={})=>{const n=/^#![ ]*\//;return e.binary&&(e.begin=function(...e){ -return e.map((e=>u(e))).join("")}(n,/.*\b/,e.binary,/\b.*/)),r({ -className:"meta",begin:n,end:/$/,relevance:0,"on:begin":(e,n)=>{ -0!==e.index&&n.ignoreMatch()}},e)},BACKSLASH_ESCAPE:m,APOS_STRING_MODE:b, -QUOTE_STRING_MODE:v,PHRASAL_WORDS_MODE:x,COMMENT:E,C_LINE_COMMENT_MODE:_, -C_BLOCK_COMMENT_MODE:w,HASH_COMMENT_MODE:N,NUMBER_MODE:{className:"number", -begin:h,relevance:0},C_NUMBER_MODE:{className:"number",begin:f,relevance:0}, -BINARY_NUMBER_MODE:{className:"number",begin:p,relevance:0},CSS_NUMBER_MODE:{ -className:"number", -begin:h+"(%|em|ex|ch|rem|vw|vh|vmin|vmax|cm|mm|in|pt|pc|px|deg|grad|rad|turn|s|ms|Hz|kHz|dpi|dpcm|dppx)?", -relevance:0},REGEXP_MODE:{begin:/(?=\/[^/\n]*\/)/,contains:[{className:"regexp", -begin:/\//,end:/\/[gimuy]*/,illegal:/\n/,contains:[m,{begin:/\[/,end:/\]/, -relevance:0,contains:[m]}]}]},TITLE_MODE:{className:"title",begin:g,relevance:0 -},UNDERSCORE_TITLE_MODE:{className:"title",begin:d,relevance:0},METHOD_GUARD:{ -begin:"\\.\\s*[a-zA-Z_]\\w*",relevance:0},END_SAME_AS_BEGIN:function(e){ -return Object.assign(e,{"on:begin":(e,n)=>{n.data._beginMatch=e[1]}, -"on:end":(e,n)=>{n.data._beginMatch!==e[1]&&n.ignoreMatch()}})} -}),R="of and for in not or if then".split(" ");function k(e){function n(n,t){ -return RegExp(u(n),"m"+(e.case_insensitive?"i":"")+(t?"g":""))}class t{ -constructor(){ -this.matchIndexes={},this.regexes=[],this.matchAt=1,this.position=0} -addRule(e,n){ -n.position=this.position++,this.matchIndexes[this.matchAt]=n,this.regexes.push([n,e]), -this.matchAt+=function(e){return RegExp(e.toString()+"|").exec("").length-1 -}(e)+1}compile(){0===this.regexes.length&&(this.exec=()=>null) -;const e=this.regexes.map((e=>e[1]));this.matcherRe=n(function(e,n="|"){ -for(var t=/\[(?:[^\\\]]|\\.)*\]|\(\??|\\([1-9][0-9]*)|\\./,r=0,a="",i=0;i0&&(a+=n),a+="(";o.length>0;){var l=t.exec(o) -;if(null==l){a+=o;break} -a+=o.substring(0,l.index),o=o.substring(l.index+l[0].length), -"\\"===l[0][0]&&l[1]?a+="\\"+(Number(l[1])+s):(a+=l[0],"("===l[0]&&r++)}a+=")"} -return a}(e),!0),this.lastIndex=0}exec(e){ -this.matcherRe.lastIndex=this.lastIndex;const n=this.matcherRe.exec(e) -;if(!n)return null -;const t=n.findIndex(((e,n)=>n>0&&void 0!==e)),r=this.matchIndexes[t] -;return n.splice(0,t),Object.assign(n,r)}}class a{constructor(){ -this.rules=[],this.multiRegexes=[], -this.count=0,this.lastIndex=0,this.regexIndex=0}getMatcher(e){ -if(this.multiRegexes[e])return this.multiRegexes[e];const n=new t -;return this.rules.slice(e).forEach((([e,t])=>n.addRule(e,t))), -n.compile(),this.multiRegexes[e]=n,n}resumingScanAtSamePosition(){ -return 0!==this.regexIndex}considerAll(){this.regexIndex=0}addRule(e,n){ -this.rules.push([e,n]),"begin"===n.type&&this.count++}exec(e){ -const n=this.getMatcher(this.regexIndex);n.lastIndex=this.lastIndex -;let t=n.exec(e) -;if(this.resumingScanAtSamePosition())if(t&&t.index===this.lastIndex);else{ -const n=this.getMatcher(0);n.lastIndex=this.lastIndex+1,t=n.exec(e)} -return t&&(this.regexIndex+=t.position+1, -this.regexIndex===this.count&&this.considerAll()),t}}function i(e,n){ -const t=e.input[e.index-1],r=e.input[e.index+e[0].length] -;"."!==t&&"."!==r||n.ignoreMatch()} -if(e.contains&&e.contains.includes("self"))throw Error("ERR: contains `self` is not supported at the top-level of a language. See documentation.") -;return function t(s,o){const l=s;if(s.compiled)return l -;s.compiled=!0,s.__beforeBegin=null,s.keywords=s.keywords||s.beginKeywords -;let c=null -;if("object"==typeof s.keywords&&(c=s.keywords.$pattern,delete s.keywords.$pattern), -s.keywords&&(s.keywords=function(e,n){var t={} -;return"string"==typeof e?r("keyword",e):Object.keys(e).forEach((function(n){ -r(n,e[n])})),t;function r(e,r){ -n&&(r=r.toLowerCase()),r.split(" ").forEach((function(n){var r=n.split("|") -;t[r[0]]=[e,O(r[0],r[1])]}))} -}(s.keywords,e.case_insensitive)),s.lexemes&&c)throw Error("ERR: Prefer `keywords.$pattern` to `mode.lexemes`, BOTH are not allowed. (see mode reference) ") -;return l.keywordPatternRe=n(s.lexemes||c||/\w+/,!0), -o&&(s.beginKeywords&&(s.begin="\\b("+s.beginKeywords.split(" ").join("|")+")(?=\\b|\\s)", -s.__beforeBegin=i), -s.begin||(s.begin=/\B|\b/),l.beginRe=n(s.begin),s.endSameAsBegin&&(s.end=s.begin), -s.end||s.endsWithParent||(s.end=/\B|\b/), -s.end&&(l.endRe=n(s.end)),l.terminator_end=u(s.end)||"", -s.endsWithParent&&o.terminator_end&&(l.terminator_end+=(s.end?"|":"")+o.terminator_end)), -s.illegal&&(l.illegalRe=n(s.illegal)), -void 0===s.relevance&&(s.relevance=1),s.contains||(s.contains=[]), -s.contains=[].concat(...s.contains.map((function(e){return function(e){ -return e.variants&&!e.cached_variants&&(e.cached_variants=e.variants.map((function(n){ -return r(e,{variants:null},n)}))),e.cached_variants?e.cached_variants:M(e)?r(e,{ -starts:e.starts?r(e.starts):null}):Object.isFrozen(e)?r(e):e}("self"===e?s:e) -}))),s.contains.forEach((function(e){t(e,l) -})),s.starts&&t(s.starts,o),l.matcher=function(e){const n=new a -;return e.contains.forEach((e=>n.addRule(e.begin,{rule:e,type:"begin" -}))),e.terminator_end&&n.addRule(e.terminator_end,{type:"end" -}),e.illegal&&n.addRule(e.illegal,{type:"illegal"}),n}(l),l}(e)}function M(e){ -return!!e&&(e.endsWithParent||M(e.starts))}function O(e,n){ -return n?Number(n):function(e){return R.includes(e.toLowerCase())}(e)?0:1} -const L={props:["language","code","autodetect"],data:function(){return{ -detectedLanguage:"",unknownLanguage:!1}},computed:{className(){ -return this.unknownLanguage?"":"hljs "+this.detectedLanguage},highlighted(){ -if(!this.autoDetect&&!hljs.getLanguage(this.language))return console.warn(`The language "${this.language}" you specified could not be found.`), -this.unknownLanguage=!0,t(this.code);let e -;return this.autoDetect?(e=hljs.highlightAuto(this.code), -this.detectedLanguage=e.language):(e=hljs.highlight(this.language,this.code,this.ignoreIllegals), -this.detectectLanguage=this.language),e.value},autoDetect(){ -return!(this.language&&(e=this.autodetect,!e&&""!==e));var e}, -ignoreIllegals:()=>!0},render(e){return e("pre",{},[e("code",{ -class:this.className,domProps:{innerHTML:this.highlighted}})])}},j={install(e){ -e.component("highlightjs",L)} -},I=t,T=r,{nodeStream:S,mergeStreams:A}=i,B=Symbol("nomatch") -;return function(t){ -var r=[],a=Object.create(null),i=Object.create(null),s=[],o=!0,l=/(^(<[^>]+>|\t|)+|\n)/gm,u="Could not find the language '{}', did you forget to load/include a language module?" -;const g={disableAutodetect:!0,name:"Plain text",contains:[]};var d={ -noHighlightRe:/^(no-?highlight)$/i, -languageDetectRe:/\blang(?:uage)?-([\w-]+)\b/i,classPrefix:"hljs-", -tabReplace:null,useBR:!1,languages:null,__emitter:c};function h(e){ -return d.noHighlightRe.test(e)}function f(e,n,t,r){var a={code:n,language:e} -;N("before:highlight",a);var i=a.result?a.result:p(a.language,a.code,t,r) -;return i.code=a.code,N("after:highlight",i),i}function p(e,t,r,i){var s=t -;function l(e,n){var t=_.case_insensitive?n[0].toLowerCase():n[0] -;return Object.prototype.hasOwnProperty.call(e.keywords,t)&&e.keywords[t]} -function c(){null!=y.subLanguage?function(){if(""!==O){var e=null -;if("string"==typeof y.subLanguage){ -if(!a[y.subLanguage])return void M.addText(O) -;e=p(y.subLanguage,O,!0,R[y.subLanguage]),R[y.subLanguage]=e.top -}else e=m(O,y.subLanguage.length?y.subLanguage:null) -;y.relevance>0&&(L+=e.relevance),M.addSublanguage(e.emitter,e.language)} -}():function(){if(!y.keywords)return void M.addText(O);let e=0 -;y.keywordPatternRe.lastIndex=0;let n=y.keywordPatternRe.exec(O),t="";for(;n;){ -t+=O.substring(e,n.index);const r=l(y,n);if(r){const[e,a]=r -;M.addText(t),t="",L+=a,M.addKeyword(n[0],e)}else t+=n[0] -;e=y.keywordPatternRe.lastIndex,n=y.keywordPatternRe.exec(O)} -t+=O.substr(e),M.addText(t)}(),O=""}function g(e){ -return e.className&&M.openNode(e.className),y=Object.create(e,{parent:{value:y} -})}function h(e,t,r){let a=function(e,n){var t=e&&e.exec(n) -;return t&&0===t.index}(e.endRe,r);if(a){if(e["on:end"]){const r=new n(e) -;e["on:end"](t,r),r.ignore&&(a=!1)}if(a){for(;e.endsParent&&e.parent;)e=e.parent -;return e}}if(e.endsWithParent)return h(e.parent,t,r)}function f(e){ -return 0===y.matcher.regexIndex?(O+=e[0],1):(S=!0,0)}function b(e){ -var n=e[0],t=s.substr(e.index),r=h(y,e,t);if(!r)return B;var a=y -;a.skip?O+=n:(a.returnEnd||a.excludeEnd||(O+=n),c(),a.excludeEnd&&(O=n));do{ -y.className&&M.closeNode(),y.skip||y.subLanguage||(L+=y.relevance),y=y.parent -}while(y!==r.parent) -;return r.starts&&(r.endSameAsBegin&&(r.starts.endRe=r.endRe), -g(r.starts)),a.returnEnd?0:n.length}var v={};function x(t,a){var i=a&&a[0] -;if(O+=t,null==i)return c(),0 -;if("begin"===v.type&&"end"===a.type&&v.index===a.index&&""===i){ -if(O+=s.slice(a.index,a.index+1),!o){const n=Error("0 width match regex") -;throw n.languageName=e,n.badRule=v.rule,n}return 1} -if(v=a,"begin"===a.type)return function(e){var t=e[0],r=e.rule -;const a=new n(r),i=[r.__beforeBegin,r["on:begin"]] -;for(const n of i)if(n&&(n(e,a),a.ignore))return f(t) -;return r&&r.endSameAsBegin&&(r.endRe=RegExp(t.replace(/[-/\\^$*+?.()|[\]{}]/g,"\\$&"),"m")), -r.skip?O+=t:(r.excludeBegin&&(O+=t), -c(),r.returnBegin||r.excludeBegin||(O=t)),g(r),r.returnBegin?0:t.length}(a) -;if("illegal"===a.type&&!r){ -const e=Error('Illegal lexeme "'+i+'" for mode "'+(y.className||"")+'"') -;throw e.mode=y,e}if("end"===a.type){var l=b(a);if(l!==B)return l} -if("illegal"===a.type&&""===i)return 1 -;if(T>1e5&&T>3*a.index)throw Error("potential infinite loop, way more iterations than matches") -;return O+=i,i.length}var _=E(e) -;if(!_)throw console.error(u.replace("{}",e)),Error('Unknown language: "'+e+'"') -;var w=k(_),N="",y=i||w,R={},M=new d.__emitter(d);!function(){ -for(var e=[],n=y;n!==_;n=n.parent)n.className&&e.unshift(n.className) -;e.forEach((e=>M.openNode(e)))}();var O="",L=0,j=0,T=0,S=!1;try{ -for(y.matcher.considerAll();;){ -T++,S?S=!1:y.matcher.considerAll(),y.matcher.lastIndex=j -;const e=y.matcher.exec(s);if(!e)break;const n=x(s.substring(j,e.index),e) -;j=e.index+n}return x(s.substr(j)),M.closeAllNodes(),M.finalize(),N=M.toHTML(),{ -relevance:L,value:N,language:e,illegal:!1,emitter:M,top:y}}catch(n){ -if(n.message&&n.message.includes("Illegal"))return{illegal:!0,illegalBy:{ -msg:n.message,context:s.slice(j-100,j+100),mode:n.mode},sofar:N,relevance:0, -value:I(s),emitter:M};if(o)return{illegal:!1,relevance:0,value:I(s),emitter:M, -language:e,top:y,errorRaised:n};throw n}}function m(e,n){ -n=n||d.languages||Object.keys(a);var t=function(e){const n={relevance:0, -emitter:new d.__emitter(d),value:I(e),illegal:!1,top:g} -;return n.emitter.addText(e),n}(e),r=t -;return n.filter(E).filter(w).forEach((function(n){var a=p(n,e,!1);a.language=n, -a.relevance>r.relevance&&(r=a),a.relevance>t.relevance&&(r=t,t=a) -})),r.language&&(t.second_best=r),t}function b(e){ -return d.tabReplace||d.useBR?e.replace(l,(e=>"\n"===e?d.useBR?"
":e:d.tabReplace?e.replace(/\t/g,d.tabReplace):e)):e -}function v(e){let n=null;const t=function(e){var n=e.className+" " -;n+=e.parentNode?e.parentNode.className:"";const t=d.languageDetectRe.exec(n) -;if(t){var r=E(t[1]) -;return r||(console.warn(u.replace("{}",t[1])),console.warn("Falling back to no-highlight mode for this block.",e)), -r?t[1]:"no-highlight"}return n.split(/\s+/).find((e=>h(e)||E(e)))}(e) -;if(h(t))return;N("before:highlightBlock",{block:e,language:t -}),d.useBR?(n=document.createElement("div"), -n.innerHTML=e.innerHTML.replace(/\n/g,"").replace(//g,"\n")):n=e -;const r=n.textContent,a=t?f(t,r,!0):m(r),s=S(n);if(s.length){ -const e=document.createElement("div");e.innerHTML=a.value,a.value=A(s,S(e),r)} -a.value=b(a.value),N("after:highlightBlock",{block:e,result:a -}),e.innerHTML=a.value,e.className=function(e,n,t){var r=n?i[n]:t,a=[e.trim()] -;return e.match(/\bhljs\b/)||a.push("hljs"), -e.includes(r)||a.push(r),a.join(" ").trim() -}(e.className,t,a.language),e.result={language:a.language,re:a.relevance, -relavance:a.relevance},a.second_best&&(e.second_best={ -language:a.second_best.language,re:a.second_best.relevance, -relavance:a.second_best.relevance})}const x=()=>{if(!x.called){x.called=!0 -;var e=document.querySelectorAll("pre code");r.forEach.call(e,v)}} -;function E(e){return e=(e||"").toLowerCase(),a[e]||a[i[e]]} -function _(e,{languageName:n}){"string"==typeof e&&(e=[e]),e.forEach((e=>{i[e]=n -}))}function w(e){var n=E(e);return n&&!n.disableAutodetect}function N(e,n){ -var t=e;s.forEach((function(e){e[t]&&e[t](n)}))}Object.assign(t,{highlight:f, -highlightAuto:m,fixMarkup:function(e){ -return console.warn("fixMarkup is deprecated and will be removed entirely in v11.0"), -console.warn("Please see https://github.com/highlightjs/highlight.js/issues/2534"), -b(e)},highlightBlock:v,configure:function(e){ -e.useBR&&(console.warn("'useBR' option is deprecated and will be removed entirely in v11.0"), -console.warn("Please see https://github.com/highlightjs/highlight.js/issues/2559")), -d=T(d,e)},initHighlighting:x,initHighlightingOnLoad:function(){ -window.addEventListener("DOMContentLoaded",x,!1)}, -registerLanguage:function(e,n){var r=null;try{r=n(t)}catch(n){ -if(console.error("Language definition for '{}' could not be registered.".replace("{}",e)), -!o)throw n;console.error(n),r=g} -r.name||(r.name=e),a[e]=r,r.rawDefinition=n.bind(null,t), -r.aliases&&_(r.aliases,{languageName:e})},listLanguages:function(){ -return Object.keys(a)},getLanguage:E,registerAliases:_, -requireLanguage:function(e){var n=E(e);if(n)return n -;throw Error("The '{}' language is required, but not loaded.".replace("{}",e))}, -autoDetection:w,inherit:T,addPlugin:function(e){s.push(e)},vuePlugin:j -}),t.debugMode=function(){o=!1},t.safeMode=function(){o=!0 -},t.versionString="10.3.2";for(const n in y)"object"==typeof y[n]&&e(y[n]) -;return Object.assign(t,y),t}({})}() -;"object"==typeof exports&&"undefined"!=typeof module&&(module.exports=hljs); -hljs.registerLanguage("apache",function(){"use strict";return function(e){ -var n={className:"number", -begin:"\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}(:\\d{1,5})?"};return{ -name:"Apache config",aliases:["apacheconf"],case_insensitive:!0, -contains:[e.HASH_COMMENT_MODE,{className:"section",begin:"", -contains:[n,{className:"number",begin:":\\d{1,5}" -},e.inherit(e.QUOTE_STRING_MODE,{relevance:0})]},{className:"attribute", -begin:/\w+/,relevance:0,keywords:{ -nomarkup:"order deny allow setenv rewriterule rewriteengine rewritecond documentroot sethandler errordocument loadmodule options header listen serverroot servername" -},starts:{end:/$/,relevance:0,keywords:{literal:"on off all deny allow"}, -contains:[{className:"meta",begin:"\\s\\[",end:"\\]$"},{className:"variable", -begin:"[\\$%]\\{",end:"\\}",contains:["self",{className:"number", -begin:"[\\$%]\\d+"}]},n,{className:"number",begin:"\\d+"},e.QUOTE_STRING_MODE]} -}],illegal:/\S/}}}()); -hljs.registerLanguage("bash",function(){"use strict";return function(e){ -const s={};Object.assign(s,{className:"variable",variants:[{ -begin:/\$[\w\d#@][\w\d_]*/},{begin:/\$\{/,end:/\}/,contains:["self",{begin:/:-/, -contains:[s]}]}]});const n={className:"subst",begin:/\$\(/,end:/\)/, -contains:[e.BACKSLASH_ESCAPE]},t={begin:/<<-?\s*(?=\w+)/,starts:{ -contains:[e.END_SAME_AS_BEGIN({begin:/(\w+)/,end:/(\w+)/,className:"string"})]} -},a={className:"string",begin:/"/,end:/"/,contains:[e.BACKSLASH_ESCAPE,s,n]} -;n.contains.push(a);const i={begin:/\$\(\(/,end:/\)\)/,contains:[{ -begin:/\d+#[0-9a-f]+/,className:"number"},e.NUMBER_MODE,s]},c=e.SHEBANG({ -binary:"(fish|bash|zsh|sh|csh|ksh|tcsh|dash|scsh)",relevance:10}),o={ -className:"function",begin:/\w[\w\d_]*\s*\(\s*\)\s*\{/,returnBegin:!0, -contains:[e.inherit(e.TITLE_MODE,{begin:/\w[\w\d_]*/})],relevance:0};return{ -name:"Bash",aliases:["sh","zsh"],keywords:{$pattern:/\b[a-z._-]+\b/, -keyword:"if then else elif fi for while in do done case esac function", -literal:"true false", -built_in:"break cd continue eval exec exit export getopts hash pwd readonly return shift test times trap umask unset alias bind builtin caller command declare echo enable help let local logout mapfile printf read readarray source type typeset ulimit unalias set shopt autoload bg bindkey bye cap chdir clone comparguments compcall compctl compdescribe compfiles compgroups compquote comptags comptry compvalues dirs disable disown echotc echoti emulate fc fg float functions getcap getln history integer jobs kill limit log noglob popd print pushd pushln rehash sched setcap setopt stat suspend ttyctl unfunction unhash unlimit unsetopt vared wait whence where which zcompile zformat zftp zle zmodload zparseopts zprof zpty zregexparse zsocket zstyle ztcp" -},contains:[c,e.SHEBANG(),o,i,e.COMMENT("(?")+")",i={ -className:"keyword",begin:"\\b[a-z\\d_]*_t\\b"},s={className:"string", -variants:[{begin:'(u8?|U|L)?"',end:'"',illegal:"\\n", -contains:[e.BACKSLASH_ESCAPE]},{ -begin:"(u8?|U|L)?'(\\\\(x[0-9A-Fa-f]{2}|u[0-9A-Fa-f]{4,8}|[0-7]{3}|\\S)|.)", -end:"'",illegal:"."},e.END_SAME_AS_BEGIN({ -begin:/(?:u8?|U|L)?R"([^()\\ ]{0,16})\(/,end:/\)([^()\\ ]{0,16})"/})]},o={ -className:"number",variants:[{begin:"\\b(0b[01']+)"},{ -begin:"(-?)\\b([\\d']+(\\.[\\d']*)?|\\.[\\d']+)(u|U|l|L|ul|UL|f|F|b|B)"},{ -begin:"(-?)(\\b0[xX][a-fA-F0-9']+|(\\b[\\d']+(\\.[\\d']*)?|\\.[\\d']+)([eE][-+]?[\\d']+)?)" -}],relevance:0},c={className:"meta",begin:/#\s*[a-z]+\b/,end:/$/,keywords:{ -"meta-keyword":"if else elif endif define undef warning error line pragma _Pragma ifdef ifndef include" -},contains:[{begin:/\\\n/,relevance:0},e.inherit(s,{className:"meta-string"}),{ -className:"meta-string",begin:/<.*?>/,end:/$/,illegal:"\\n" -},n,e.C_BLOCK_COMMENT_MODE]},l={className:"title",begin:t(r)+e.IDENT_RE, -relevance:0},d=t(r)+e.IDENT_RE+"\\s*\\(",u={ -keyword:"int float while private char char8_t char16_t char32_t catch import module export virtual operator sizeof dynamic_cast|10 typedef const_cast|10 const for static_cast|10 union namespace unsigned long volatile static protected bool template mutable if public friend do goto auto void enum else break extern using asm case typeid wchar_t short reinterpret_cast|10 default double register explicit signed typename try this switch continue inline delete alignas alignof constexpr consteval constinit decltype concept co_await co_return co_yield requires noexcept static_assert thread_local restrict final override atomic_bool atomic_char atomic_schar atomic_uchar atomic_short atomic_ushort atomic_int atomic_uint atomic_long atomic_ulong atomic_llong atomic_ullong new throw return and and_eq bitand bitor compl not not_eq or or_eq xor xor_eq", -built_in:"std string wstring cin cout cerr clog stdin stdout stderr stringstream istringstream ostringstream auto_ptr deque list queue stack vector map set pair bitset multiset multimap unordered_set unordered_map unordered_multiset unordered_multimap priority_queue make_pair array shared_ptr abort terminate abs acos asin atan2 atan calloc ceil cosh cos exit exp fabs floor fmod fprintf fputs free frexp fscanf future isalnum isalpha iscntrl isdigit isgraph islower isprint ispunct isspace isupper isxdigit tolower toupper labs ldexp log10 log malloc realloc memchr memcmp memcpy memset modf pow printf putchar puts scanf sinh sin snprintf sprintf sqrt sscanf strcat strchr strcmp strcpy strcspn strlen strncat strncmp strncpy strpbrk strrchr strspn strstr tanh tan vfprintf vprintf vsprintf endl initializer_list unique_ptr _Bool complex _Complex imaginary _Imaginary", -literal:"true false nullptr NULL"},m=[c,i,n,e.C_BLOCK_COMMENT_MODE,o,s],p={ -variants:[{begin:/=/,end:/;/},{begin:/\(/,end:/\)/},{ -beginKeywords:"new throw return else",end:/;/}],keywords:u,contains:m.concat([{ -begin:/\(/,end:/\)/,keywords:u,contains:m.concat(["self"]),relevance:0}]), -relevance:0},_={className:"function",begin:"("+a+"[\\*&\\s]+)+"+d, -returnBegin:!0,end:/[{;=]/,excludeEnd:!0,keywords:u,illegal:/[^\w\s\*&:<>]/, -contains:[{begin:"decltype\\(auto\\)",keywords:u,relevance:0},{begin:d, -returnBegin:!0,contains:[l],relevance:0},{className:"params",begin:/\(/, -end:/\)/,keywords:u,relevance:0,contains:[n,e.C_BLOCK_COMMENT_MODE,s,o,i,{ -begin:/\(/,end:/\)/,keywords:u,relevance:0, -contains:["self",n,e.C_BLOCK_COMMENT_MODE,s,o,i]}] -},i,n,e.C_BLOCK_COMMENT_MODE,c]};return{ -aliases:["c","cc","h","c++","h++","hpp","hh","hxx","cxx"],keywords:u, -disableAutodetect:!0,illegal:"",keywords:u,contains:["self",i]},{begin:e.IDENT_RE+"::",keywords:u},{ -className:"class",beginKeywords:"enum class struct union",end:/[{;:<>=]/, -contains:[{beginKeywords:"final class struct"},e.TITLE_MODE]}]),exports:{ -preprocessor:c,strings:s,keywords:u}}}}()); -hljs.registerLanguage("c",function(){"use strict";return function(e){ -var n=e.requireLanguage("c-like").rawDefinition() -;return n.name="C",n.aliases=["c","h"],n}}()); -hljs.registerLanguage("coffeescript",function(){"use strict" -;const e=["as","in","of","if","for","while","finally","var","new","function","do","return","void","else","break","catch","instanceof","with","throw","case","default","try","switch","continue","typeof","delete","let","yield","const","class","debugger","async","await","static","import","from","export","extends"],n=["true","false","null","undefined","NaN","Infinity"],a=[].concat(["setInterval","setTimeout","clearInterval","clearTimeout","require","exports","eval","isFinite","isNaN","parseFloat","parseInt","decodeURI","decodeURIComponent","encodeURI","encodeURIComponent","escape","unescape"],["arguments","this","super","console","window","document","localStorage","module","global"],["Intl","DataView","Number","Math","Date","String","RegExp","Object","Function","Boolean","Error","Symbol","Set","Map","WeakSet","WeakMap","Proxy","Reflect","JSON","Promise","Float64Array","Int16Array","Int32Array","Int8Array","Uint16Array","Uint32Array","Float32Array","Array","Uint8Array","Uint8ClampedArray","ArrayBuffer"],["EvalError","InternalError","RangeError","ReferenceError","SyntaxError","TypeError","URIError"]) -;return function(r){var t,i={ -keyword:e.concat(["then","unless","until","loop","by","when","and","or","is","isnt","not"]).filter((t=["var","const","let","function","static"], -e=>!t.includes(e))).join(" "), -literal:n.concat(["yes","no","on","off"]).join(" "), -built_in:a.concat(["npm","print"]).join(" ")},s="[A-Za-z$_][0-9A-Za-z$_]*",o={ -className:"subst",begin:/#\{/,end:/}/,keywords:i -},c=[r.BINARY_NUMBER_MODE,r.inherit(r.C_NUMBER_MODE,{starts:{end:"(\\s*/)?", -relevance:0}}),{className:"string",variants:[{begin:/'''/,end:/'''/, -contains:[r.BACKSLASH_ESCAPE]},{begin:/'/,end:/'/,contains:[r.BACKSLASH_ESCAPE] -},{begin:/"""/,end:/"""/,contains:[r.BACKSLASH_ESCAPE,o]},{begin:/"/,end:/"/, -contains:[r.BACKSLASH_ESCAPE,o]}]},{className:"regexp",variants:[{begin:"///", -end:"///",contains:[o,r.HASH_COMMENT_MODE]},{begin:"//[gim]{0,3}(?=\\W)", -relevance:0},{begin:/\/(?![ *]).*?(?![\\]).\/[gim]{0,3}(?=\W)/}]},{begin:"@"+s -},{subLanguage:"javascript",excludeBegin:!0,excludeEnd:!0,variants:[{ -begin:"```",end:"```"},{begin:"`",end:"`"}]}];o.contains=c -;var l=r.inherit(r.TITLE_MODE,{begin:s}),d="(\\(.*\\))?\\s*\\B[-=]>",g={ -className:"params",begin:"\\([^\\(]",returnBegin:!0,contains:[{begin:/\(/, -end:/\)/,keywords:i,contains:["self"].concat(c)}]};return{name:"CoffeeScript", -aliases:["coffee","cson","iced"],keywords:i,illegal:/\/\*/, -contains:c.concat([r.COMMENT("###","###"),r.HASH_COMMENT_MODE,{ -className:"function",begin:"^\\s*"+s+"\\s*=\\s*"+d,end:"[-=]>",returnBegin:!0, -contains:[l,g]},{begin:/[:\(,=]\s*/,relevance:0,contains:[{className:"function", -begin:d,end:"[-=]>",returnBegin:!0,contains:[g]}]},{className:"class", -beginKeywords:"class",end:"$",illegal:/[:="\[\]]/,contains:[{ -beginKeywords:"extends",endsWithParent:!0,illegal:/[:="\[\]]/,contains:[l]},l] -},{begin:s+":",end:":",returnBegin:!0,returnEnd:!0,relevance:0}])}}}()); -hljs.registerLanguage("cpp",function(){"use strict";return function(e){ -var i=e.requireLanguage("c-like").rawDefinition();return i.disableAutodetect=!1, -i.name="C++",i.aliases=["cc","c++","h++","hpp","hh","hxx","cxx"],i}}()); -hljs.registerLanguage("csharp",function(){"use strict";return function(e){ -var n={ -keyword:["abstract","as","base","break","case","class","const","continue","do","else","event","explicit","extern","finally","fixed","for","foreach","goto","if","implicit","in","interface","internal","is","lock","namespace","new","operator","out","override","params","private","protected","public","readonly","record","ref","return","sealed","sizeof","stackalloc","static","struct","switch","this","throw","try","typeof","unchecked","unsafe","using","virtual","void","volatile","while"].concat(["add","alias","and","ascending","async","await","by","descending","equals","from","get","global","group","init","into","join","let","nameof","not","notnull","on","or","orderby","partial","remove","select","set","unmanaged","value","var","when","where","with","yield"]).join(" "), -built_in:"bool byte char decimal delegate double dynamic enum float int long nint nuint object sbyte short string ulong unit ushort", -literal:"default false null true"},i=e.inherit(e.TITLE_MODE,{ -begin:"[a-zA-Z](\\.?\\w)*"}),a={className:"number",variants:[{ -begin:"\\b(0b[01']+)"},{ -begin:"(-?)\\b([\\d']+(\\.[\\d']*)?|\\.[\\d']+)(u|U|l|L|ul|UL|f|F|b|B)"},{ -begin:"(-?)(\\b0[xX][a-fA-F0-9']+|(\\b[\\d']+(\\.[\\d']*)?|\\.[\\d']+)([eE][-+]?[\\d']+)?)" -}],relevance:0},s={className:"string",begin:'@"',end:'"',contains:[{begin:'""'}] -},t=e.inherit(s,{illegal:/\n/}),r={className:"subst",begin:"{",end:"}", -keywords:n},l=e.inherit(r,{illegal:/\n/}),c={className:"string",begin:/\$"/, -end:'"',illegal:/\n/,contains:[{begin:"{{"},{begin:"}}"},e.BACKSLASH_ESCAPE,l] -},o={className:"string",begin:/\$@"/,end:'"',contains:[{begin:"{{"},{begin:"}}" -},{begin:'""'},r]},d=e.inherit(o,{illegal:/\n/,contains:[{begin:"{{"},{ -begin:"}}"},{begin:'""'},l]}) -;r.contains=[o,c,s,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,a,e.C_BLOCK_COMMENT_MODE], -l.contains=[d,c,t,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,a,e.inherit(e.C_BLOCK_COMMENT_MODE,{ -illegal:/\n/})];var g={variants:[o,c,s,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE] -},E={begin:"<",end:">",contains:[{beginKeywords:"in out"},i] -},_=e.IDENT_RE+"(<"+e.IDENT_RE+"(\\s*,\\s*"+e.IDENT_RE+")*>)?(\\[\\])?",b={ -begin:"@"+e.IDENT_RE,relevance:0};return{name:"C#",aliases:["cs","c#"], -keywords:n,illegal:/::/,contains:[e.COMMENT("///","$",{returnBegin:!0, -contains:[{className:"doctag",variants:[{begin:"///",relevance:0},{ -begin:"\x3c!--|--\x3e"},{begin:""}]}] -}),e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,{className:"meta",begin:"#", -end:"$",keywords:{ -"meta-keyword":"if else elif endif define undef warning error line region endregion pragma checksum" -}},g,a,{beginKeywords:"class interface",end:/[{;=]/,illegal:/[^\s:,]/, -contains:[{beginKeywords:"where class" -},i,E,e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},{beginKeywords:"namespace", -end:/[{;=]/,illegal:/[^\s:]/, -contains:[i,e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},{ -beginKeywords:"record",end:/[{;=]/,illegal:/[^\s:]/, -contains:[i,E,e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},{className:"meta", -begin:"^\\s*\\[",excludeBegin:!0,end:"\\]",excludeEnd:!0,contains:[{ -className:"meta-string",begin:/"/,end:/"/}]},{ -beginKeywords:"new return throw await else",relevance:0},{className:"function", -begin:"("+_+"\\s+)+"+e.IDENT_RE+"\\s*(\\<.+\\>)?\\s*\\(",returnBegin:!0, -end:/\s*[{;=]/,excludeEnd:!0,keywords:n,contains:[{ -beginKeywords:"public private protected static internal protected abstract async extern override unsafe virtual new sealed partial" -},{begin:e.IDENT_RE+"\\s*(\\<.+\\>)?\\s*\\(",returnBegin:!0, -contains:[e.TITLE_MODE,E],relevance:0},{className:"params",begin:/\(/,end:/\)/, -excludeBegin:!0,excludeEnd:!0,keywords:n,relevance:0, -contains:[g,a,e.C_BLOCK_COMMENT_MODE] -},e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},b]}}}()); -hljs.registerLanguage("css",function(){"use strict";return function(e){var n={ -begin:/(?:[A-Z\_\.\-]+|--[a-zA-Z0-9_-]+)\s*:/,returnBegin:!0,end:";", -endsWithParent:!0,contains:[{className:"attribute",begin:/\S/,end:":", -excludeEnd:!0,starts:{endsWithParent:!0,excludeEnd:!0,contains:[{ -begin:/[\w-]+\(/,returnBegin:!0,contains:[{className:"built_in",begin:/[\w-]+/ -},{begin:/\(/,end:/\)/, -contains:[e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,e.CSS_NUMBER_MODE]}] -},e.CSS_NUMBER_MODE,e.QUOTE_STRING_MODE,e.APOS_STRING_MODE,e.C_BLOCK_COMMENT_MODE,{ -className:"number",begin:"#[0-9A-Fa-f]+"},{className:"meta",begin:"!important"}] -}}]};return{name:"CSS",case_insensitive:!0,illegal:/[=\/|'\$]/, -contains:[e.C_BLOCK_COMMENT_MODE,{className:"selector-id", -begin:/#[A-Za-z0-9_-]+/},{className:"selector-class",begin:/\.[A-Za-z0-9_-]+/},{ -className:"selector-attr",begin:/\[/,end:/\]/,illegal:"$", -contains:[e.APOS_STRING_MODE,e.QUOTE_STRING_MODE]},{className:"selector-pseudo", -begin:/:(:)?[a-zA-Z0-9\_\-\+\(\)"'.]+/},{begin:"@(page|font-face)", -lexemes:"@[a-z-]+",keywords:"@page @font-face"},{begin:"@",end:"[{;]", -illegal:/:/,returnBegin:!0,contains:[{className:"keyword", -begin:/@\-?\w[\w]*(\-\w+)*/},{begin:/\s/,endsWithParent:!0,excludeEnd:!0, -relevance:0,keywords:"and or not only",contains:[{begin:/[a-z-]+:/, -className:"attribute"},e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,e.CSS_NUMBER_MODE] -}]},{className:"selector-tag",begin:"[a-zA-Z-][a-zA-Z0-9_-]*",relevance:0},{ -begin:"{",end:"}",illegal:/\S/,contains:[e.C_BLOCK_COMMENT_MODE,n]}]}}}()); -hljs.registerLanguage("diff",function(){"use strict";return function(e){return{ -name:"Diff",aliases:["patch"],contains:[{className:"meta",relevance:10, -variants:[{begin:/^@@ +\-\d+,\d+ +\+\d+,\d+ +@@$/},{ -begin:/^\*\*\* +\d+,\d+ +\*\*\*\*$/},{begin:/^\-\-\- +\d+,\d+ +\-\-\-\-$/}]},{ -className:"comment",variants:[{begin:/Index: /,end:/$/},{begin:/={3,}/,end:/$/ -},{begin:/^\-{3}/,end:/$/},{begin:/^\*{3} /,end:/$/},{begin:/^\+{3}/,end:/$/},{ -begin:/^\*{15}$/}]},{className:"addition",begin:"^\\+",end:"$"},{ -className:"deletion",begin:"^\\-",end:"$"},{className:"addition",begin:"^\\!", -end:"$"}]}}}()); -hljs.registerLanguage("go",function(){"use strict";return function(e){var n={ -keyword:"break default func interface select case map struct chan else goto package switch const fallthrough if range type continue for import return var go defer bool byte complex64 complex128 float32 float64 int8 int16 int32 int64 string uint8 uint16 uint32 uint64 int uint uintptr rune", -literal:"true false iota nil", -built_in:"append cap close complex copy imag len make new panic print println real recover delete" -};return{name:"Go",aliases:["golang"],keywords:n,illegal:"e(n))).join("")}return function(a){var s={className:"number", -relevance:0,variants:[{begin:/([\+\-]+)?[\d]+_[\d_]+/},{begin:a.NUMBER_RE}] -},i=a.COMMENT();i.variants=[{begin:/;/,end:/$/},{begin:/#/,end:/$/}];var t={ -className:"variable",variants:[{begin:/\$[\w\d"][\w\d_]*/},{begin:/\$\{(.*?)}/}] -},r={className:"literal",begin:/\bon|off|true|false|yes|no\b/},l={ -className:"string",contains:[a.BACKSLASH_ESCAPE],variants:[{begin:"'''", -end:"'''",relevance:10},{begin:'"""',end:'"""',relevance:10},{begin:'"',end:'"' -},{begin:"'",end:"'"}]},c={begin:/\[/,end:/\]/,contains:[i,r,t,l,s,"self"], -relevance:0 -},g="("+[/[A-Za-z0-9_-]+/,/"(\\"|[^"])*"/,/'[^']*'/].map((n=>e(n))).join("|")+")" -;return{name:"TOML, also INI",aliases:["toml"],case_insensitive:!0,illegal:/\S/, -contains:[i,{className:"section",begin:/\[+/,end:/\]+/},{ -begin:n(g,"(\\s*\\.\\s*",g,")*",n("(?=",/\s*=\s*[^#\s]/,")")),className:"attr", -starts:{end:/$/,contains:[i,c,r,t,l,s]}}]}}}()); -hljs.registerLanguage("java",function(){"use strict";function e(e){ -return e?"string"==typeof e?e:e.source:null}function n(e){return a("(",e,")?")} -function a(...n){return n.map((n=>e(n))).join("")}function s(...n){ -return"("+n.map((n=>e(n))).join("|")+")"}return function(e){ -var r="false synchronized int abstract float private char boolean var static null if const for true while long strictfp finally protected import native final void enum else break transient catch instanceof byte super volatile case assert short package default double public try this switch continue throws protected public private module requires exports do",i={ -className:"meta",begin:"@[\xc0-\u02b8a-zA-Z_$][\xc0-\u02b8a-zA-Z_$0-9]*", -contains:[{begin:/\(/,end:/\)/,contains:["self"]}] -},t=e=>a("[",e,"]+([",e,"_]*[",e,"]+)?"),c={className:"number",variants:[{ -begin:`\\b(0[bB]${t("01")})[lL]?`},{begin:`\\b(0${t("0-7")})[dDfFlL]?`},{ -begin:a(/\b0[xX]/,s(a(t("a-fA-F0-9"),/\./,t("a-fA-F0-9")),a(t("a-fA-F0-9"),/\.?/),a(/\./,t("a-fA-F0-9"))),/([pP][+-]?(\d+))?/,/[fFdDlL]?/) -},{begin:a(/\b/,s(a(/\d*\./,t("\\d")),t("\\d")),/[eE][+-]?[\d]+[dDfF]?/)},{ -begin:a(/\b/,t(/\d/),n(/\.?/),n(t(/\d/)),/[dDfFlL]?/)}],relevance:0};return{ -name:"Java",aliases:["jsp"],keywords:r,illegal:/<\/|#/, -contains:[e.COMMENT("/\\*\\*","\\*/",{relevance:0,contains:[{begin:/\w+@/, -relevance:0},{className:"doctag",begin:"@[A-Za-z]+"}] -}),e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,{ -className:"class",beginKeywords:"class interface enum",end:/[{;=]/, -excludeEnd:!0,keywords:"class interface enum",illegal:/[:"\[\]]/,contains:[{ -beginKeywords:"extends implements"},e.UNDERSCORE_TITLE_MODE]},{ -beginKeywords:"new throw return else",relevance:0},{className:"class", -begin:"record\\s+"+e.UNDERSCORE_IDENT_RE+"\\s*\\(",returnBegin:!0,excludeEnd:!0, -end:/[{;=]/,keywords:r,contains:[{beginKeywords:"record"},{ -begin:e.UNDERSCORE_IDENT_RE+"\\s*\\(",returnBegin:!0,relevance:0, -contains:[e.UNDERSCORE_TITLE_MODE]},{className:"params",begin:/\(/,end:/\)/, -keywords:r,relevance:0,contains:[e.C_BLOCK_COMMENT_MODE] -},e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},{className:"function", -begin:"([\xc0-\u02b8a-zA-Z_$][\xc0-\u02b8a-zA-Z_$0-9]*(<[\xc0-\u02b8a-zA-Z_$][\xc0-\u02b8a-zA-Z_$0-9]*(\\s*,\\s*[\xc0-\u02b8a-zA-Z_$][\xc0-\u02b8a-zA-Z_$0-9]*)*>)?\\s+)+"+e.UNDERSCORE_IDENT_RE+"\\s*\\(", -returnBegin:!0,end:/[{;=]/,excludeEnd:!0,keywords:r,contains:[{ -begin:e.UNDERSCORE_IDENT_RE+"\\s*\\(",returnBegin:!0,relevance:0, -contains:[e.UNDERSCORE_TITLE_MODE]},{className:"params",begin:/\(/,end:/\)/, -keywords:r,relevance:0, -contains:[i,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,e.C_NUMBER_MODE,e.C_BLOCK_COMMENT_MODE] -},e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},c,i]}}}()); -hljs.registerLanguage("javascript",function(){"use strict" -;const e="[A-Za-z$_][0-9A-Za-z$_]*",n=["as","in","of","if","for","while","finally","var","new","function","do","return","void","else","break","catch","instanceof","with","throw","case","default","try","switch","continue","typeof","delete","let","yield","const","class","debugger","async","await","static","import","from","export","extends"],a=["true","false","null","undefined","NaN","Infinity"],s=[].concat(["setInterval","setTimeout","clearInterval","clearTimeout","require","exports","eval","isFinite","isNaN","parseFloat","parseInt","decodeURI","decodeURIComponent","encodeURI","encodeURIComponent","escape","unescape"],["arguments","this","super","console","window","document","localStorage","module","global"],["Intl","DataView","Number","Math","Date","String","RegExp","Object","Function","Boolean","Error","Symbol","Set","Map","WeakSet","WeakMap","Proxy","Reflect","JSON","Promise","Float64Array","Int16Array","Int32Array","Int8Array","Uint16Array","Uint32Array","Float32Array","Array","Uint8Array","Uint8ClampedArray","ArrayBuffer"],["EvalError","InternalError","RangeError","ReferenceError","SyntaxError","TypeError","URIError"]) -;function r(e){return i("(?=",e,")")}function t(e){return i("(",e,")?")} -function i(...e){return e.map((e=>{ -return(n=e)?"string"==typeof n?n:n.source:null;var n})).join("")} -return function(c){const o=e,l={begin:/<[A-Za-z0-9\\._:-]+/, -end:/\/[A-Za-z0-9\\._:-]+>|\/>/,isTrulyOpeningTag:(e,n)=>{ -const a=e[0].length+e.index,s=e.input[a];"<"!==s?">"===s&&(((e,{after:n})=>{ -const a=e[0].replace("<","`\\b0[${e}][${n}]([${n}_]*[${n}])?n?`,b=/[1-9]([0-9_]*\d)?/,E=/\d([0-9_]*\d)?/,u=i(/[eE][+-]?/,E),_={ -className:"number",variants:[{begin:d("bB","01")},{begin:d("oO","0-7")},{ -begin:d("xX","0-9a-fA-F")},{begin:i(/\b/,b,"n")},{begin:i(/(\b0)?\./,E,t(u))},{ -begin:i(/\b/,b,t(i(/\./,t(E))),t(u))},{begin:/\b0[\.n]?/}],relevance:0},m={ -className:"subst",begin:"\\$\\{",end:"\\}",keywords:g,contains:[]},N={ -begin:"html`",end:"",starts:{end:"`",returnEnd:!1, -contains:[c.BACKSLASH_ESCAPE,m],subLanguage:"xml"}},y={begin:"css`",end:"", -starts:{end:"`",returnEnd:!1,contains:[c.BACKSLASH_ESCAPE,m],subLanguage:"css"} -},f={className:"string",begin:"`",end:"`",contains:[c.BACKSLASH_ESCAPE,m]},A={ -className:"comment",variants:[c.COMMENT("/\\*\\*","\\*/",{relevance:0, -contains:[{className:"doctag",begin:"@[A-Za-z]+",contains:[{className:"type", -begin:"\\{",end:"\\}",relevance:0},{className:"variable", -begin:o+"(?=\\s*(-)|$)",endsParent:!0,relevance:0},{begin:/(?=[^\n])\s/, -relevance:0}]}]}),c.C_BLOCK_COMMENT_MODE,c.C_LINE_COMMENT_MODE] -},p=[c.APOS_STRING_MODE,c.QUOTE_STRING_MODE,N,y,f,_,c.REGEXP_MODE] -;m.contains=p.concat({begin:/{/,end:/}/,keywords:g,contains:["self"].concat(p)}) -;const O=[].concat(A,m.contains),T=O.concat([{begin:/\(/,end:/\)/,keywords:g, -contains:["self"].concat(O)}]),R={className:"params",begin:/\(/,end:/\)/, -excludeBegin:!0,excludeEnd:!0,keywords:g,contains:T};return{name:"Javascript", -aliases:["js","jsx","mjs","cjs"],keywords:g,exports:{PARAMS_CONTAINS:T}, -illegal:/#(?![$_A-z])/,contains:[c.SHEBANG({label:"shebang",binary:"node", -relevance:5}),{label:"use_strict",className:"meta",relevance:10, -begin:/^\s*['"]use (strict|asm)['"]/ -},c.APOS_STRING_MODE,c.QUOTE_STRING_MODE,N,y,f,A,_,{ -begin:i(/[{,\n]\s*/,r(i(/(\/\/.*$)*/,/(\/\*(.|\n)*\*\/)*/,/\s*/,o+"\\s*:"))), -relevance:0,contains:[{className:"attr",begin:o+r("\\s*:"),relevance:0}]},{ -begin:"("+c.RE_STARTERS_RE+"|\\b(case|return|throw)\\b)\\s*", -keywords:"return throw case",contains:[A,c.REGEXP_MODE,{className:"function", -begin:"(\\([^()]*(\\([^()]*(\\([^()]*\\))*[^()]*\\))*[^()]*\\)|"+c.UNDERSCORE_IDENT_RE+")\\s*=>", -returnBegin:!0,end:"\\s*=>",contains:[{className:"params",variants:[{ -begin:c.UNDERSCORE_IDENT_RE},{className:null,begin:/\(\s*\)/,skip:!0},{ -begin:/\(/,end:/\)/,excludeBegin:!0,excludeEnd:!0,keywords:g,contains:T}]}]},{ -begin:/,/,relevance:0},{className:"",begin:/\s/,end:/\s*/,skip:!0},{variants:[{ -begin:"<>",end:""},{begin:l.begin,"on:begin":l.isTrulyOpeningTag,end:l.end}], -subLanguage:"xml",contains:[{begin:l.begin,end:l.end,skip:!0,contains:["self"]}] -}],relevance:0},{className:"function",beginKeywords:"function",end:/[{;]/, -excludeEnd:!0,keywords:g,contains:["self",c.inherit(c.TITLE_MODE,{begin:o}),R], -illegal:/%/},{className:"function", -begin:c.UNDERSCORE_IDENT_RE+"\\([^()]*(\\([^()]*(\\([^()]*\\))*[^()]*\\))*[^()]*\\)\\s*{", -returnBegin:!0,contains:[R,c.inherit(c.TITLE_MODE,{begin:o})]},{variants:[{ -begin:"\\."+o},{begin:"\\$"+o}],relevance:0},{className:"class", -beginKeywords:"class",end:/[{;=]/,excludeEnd:!0,illegal:/[:"\[\]]/,contains:[{ -beginKeywords:"extends"},c.UNDERSCORE_TITLE_MODE]},{begin:/\b(?=constructor)/, -end:/[\{;]/,excludeEnd:!0,contains:[c.inherit(c.TITLE_MODE,{begin:o}),"self",R] -},{begin:"(get|set)\\s+(?="+o+"\\()",end:/{/,keywords:"get set", -contains:[c.inherit(c.TITLE_MODE,{begin:o}),{begin:/\(\)/},R]},{begin:/\$[(.]/}] -}}}()); -hljs.registerLanguage("json",function(){"use strict";return function(n){var e={ -literal:"true false null" -},i=[n.C_LINE_COMMENT_MODE,n.C_BLOCK_COMMENT_MODE],t=[n.QUOTE_STRING_MODE,n.C_NUMBER_MODE],a={ -end:",",endsWithParent:!0,excludeEnd:!0,contains:t,keywords:e},l={begin:"{", -end:"}",contains:[{className:"attr",begin:/"/,end:/"/, -contains:[n.BACKSLASH_ESCAPE],illegal:"\\n"},n.inherit(a,{begin:/:/ -})].concat(i),illegal:"\\S"},s={begin:"\\[",end:"\\]",contains:[n.inherit(a)], -illegal:"\\S"};return t.push(l,s),i.forEach((function(n){t.push(n)})),{ -name:"JSON",contains:t,keywords:e,illegal:"\\S"}}}()); -hljs.registerLanguage("kotlin",function(){"use strict";return function(e){ -var n={ -keyword:"abstract as val var vararg get set class object open private protected public noinline crossinline dynamic final enum if else do while for when throw try catch finally import package is in fun override companion reified inline lateinit init interface annotation data sealed internal infix operator out by constructor super tailrec where const inner suspend typealias external expect actual", -built_in:"Byte Short Char Int Long Boolean Float Double Void Unit Nothing", -literal:"true false null"},a={className:"symbol",begin:e.UNDERSCORE_IDENT_RE+"@" -},i={className:"subst",begin:"\\${",end:"}",contains:[e.C_NUMBER_MODE]},s={ -className:"variable",begin:"\\$"+e.UNDERSCORE_IDENT_RE},t={className:"string", -variants:[{begin:'"""',end:'"""(?=[^"])',contains:[s,i]},{begin:"'",end:"'", -illegal:/\n/,contains:[e.BACKSLASH_ESCAPE]},{begin:'"',end:'"',illegal:/\n/, -contains:[e.BACKSLASH_ESCAPE,s,i]}]};i.contains.push(t);var r={className:"meta", -begin:"@(?:file|property|field|get|set|receiver|param|setparam|delegate)\\s*:(?:\\s*"+e.UNDERSCORE_IDENT_RE+")?" -},l={className:"meta",begin:"@"+e.UNDERSCORE_IDENT_RE,contains:[{begin:/\(/, -end:/\)/,contains:[e.inherit(t,{className:"meta-string"})]}] -},c=e.COMMENT("/\\*","\\*/",{contains:[e.C_BLOCK_COMMENT_MODE]}),o={variants:[{ -className:"type",begin:e.UNDERSCORE_IDENT_RE},{begin:/\(/,end:/\)/,contains:[]}] -},d=o;return d.variants[1].contains=[o],o.variants[1].contains=[d],{ -name:"Kotlin",aliases:["kt"],keywords:n,contains:[e.COMMENT("/\\*\\*","\\*/",{ -relevance:0,contains:[{className:"doctag",begin:"@[A-Za-z]+"}] -}),e.C_LINE_COMMENT_MODE,c,{className:"keyword", -begin:/\b(break|continue|return|this)\b/,starts:{contains:[{className:"symbol", -begin:/@\w+/}]}},a,r,l,{className:"function",beginKeywords:"fun",end:"[(]|$", -returnBegin:!0,excludeEnd:!0,keywords:n, -illegal:/fun\s+(<.*>)?[^\s\(]+(\s+[^\s\(]+)\s*=/,relevance:5,contains:[{ -begin:e.UNDERSCORE_IDENT_RE+"\\s*\\(",returnBegin:!0,relevance:0, -contains:[e.UNDERSCORE_TITLE_MODE]},{className:"type",begin://, -keywords:"reified",relevance:0},{className:"params",begin:/\(/,end:/\)/, -endsParent:!0,keywords:n,relevance:0,contains:[{begin:/:/,end:/[=,\/]/, -endsWithParent:!0,contains:[o,e.C_LINE_COMMENT_MODE,c],relevance:0 -},e.C_LINE_COMMENT_MODE,c,r,l,t,e.C_NUMBER_MODE]},c]},{className:"class", -beginKeywords:"class interface trait",end:/[:\{(]|$/,excludeEnd:!0, -illegal:"extends implements",contains:[{ -beginKeywords:"public protected internal private constructor" -},e.UNDERSCORE_TITLE_MODE,{className:"type",begin://,excludeBegin:!0, -excludeEnd:!0,relevance:0},{className:"type",begin:/[,:]\s*/,end:/[<\(,]|$/, -excludeBegin:!0,returnEnd:!0},r,l]},t,{className:"meta",begin:"^#!/usr/bin/env", -end:"$",illegal:"\n"},{className:"number", -begin:"\\b(0[bB]([01]+[01_]+[01]+|[01]+)|0[xX]([a-fA-F0-9]+[a-fA-F0-9_]+[a-fA-F0-9]+|[a-fA-F0-9]+)|(([\\d]+[\\d_]+[\\d]+|[\\d]+)(\\.([\\d]+[\\d_]+[\\d]+|[\\d]+))?|\\.([\\d]+[\\d_]+[\\d]+|[\\d]+))([eE][-+]?\\d+)?)[lLfF]?", -relevance:0}]}}}()); -hljs.registerLanguage("less",function(){"use strict";return function(e){ -var n="([\\w-]+|@{[\\w-]+})",a=[],s=[],t=function(e){return{className:"string", -begin:"~?"+e+".*?"+e}},r=function(e,n,a){return{className:e,begin:n,relevance:a} -},i={begin:"\\(",end:"\\)",contains:s,relevance:0} -;s.push(e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,t("'"),t('"'),e.CSS_NUMBER_MODE,{ -begin:"(url|data-uri)\\(",starts:{className:"string",end:"[\\)\\n]", -excludeEnd:!0} -},r("number","#[0-9A-Fa-f]+\\b"),i,r("variable","@@?[\\w-]+",10),r("variable","@{[\\w-]+}"),r("built_in","~?`[^`]*?`"),{ -className:"attribute",begin:"[\\w-]+\\s*:",end:":",returnBegin:!0,excludeEnd:!0 -},{className:"meta",begin:"!important"});var c=s.concat({begin:"{",end:"}", -contains:a}),l={beginKeywords:"when",endsWithParent:!0,contains:[{ -beginKeywords:"and not"}].concat(s)},o={begin:n+"\\s*:",returnBegin:!0, -end:"[;}]",relevance:0,contains:[{className:"attribute",begin:n,end:":", -excludeEnd:!0,starts:{endsWithParent:!0,illegal:"[<=$]",relevance:0,contains:s} -}]},g={className:"keyword", -begin:"@(import|media|charset|font-face|(-[a-z]+-)?keyframes|supports|document|namespace|page|viewport|host)\\b", -starts:{end:"[;{}]",returnEnd:!0,contains:s,relevance:0}},d={ -className:"variable",variants:[{begin:"@[\\w-]+\\s*:",relevance:15},{ -begin:"@[\\w-]+"}],starts:{end:"[;}]",returnEnd:!0,contains:c}},b={variants:[{ -begin:"[\\.#:&\\[>]",end:"[;{}]"},{begin:n,end:"{"}],returnBegin:!0, -returnEnd:!0,illegal:"[<='$\"]",relevance:0, -contains:[e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,l,r("keyword","all\\b"),r("variable","@{[\\w-]+}"),r("selector-tag",n+"%?",0),r("selector-id","#"+n),r("selector-class","\\."+n,0),r("selector-tag","&",0),{ -className:"selector-attr",begin:"\\[",end:"\\]"},{className:"selector-pseudo", -begin:/:(:)?[a-zA-Z0-9\_\-\+\(\)"'.]+/},{begin:"\\(",end:"\\)",contains:c},{ -begin:"!important"}]} -;return a.push(e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,g,d,o,b),{ -name:"Less",case_insensitive:!0,illegal:"[=>'/<($\"]",contains:a}}}()); -hljs.registerLanguage("lua",function(){"use strict";return function(e){ -var t="\\[=*\\[",a="\\]=*\\]",n={begin:t,end:a,contains:["self"] -},o=[e.COMMENT("--(?!\\[=*\\[)","$"),e.COMMENT("--\\[=*\\[",a,{contains:[n], -relevance:10})];return{name:"Lua",keywords:{$pattern:e.UNDERSCORE_IDENT_RE, -literal:"true false nil", -keyword:"and break do else elseif end for goto if in local not or repeat return then until while", -built_in:"_G _ENV _VERSION __index __newindex __mode __call __metatable __tostring __len __gc __add __sub __mul __div __mod __pow __concat __unm __eq __lt __le assert collectgarbage dofile error getfenv getmetatable ipairs load loadfile loadstring module next pairs pcall print rawequal rawget rawset require select setfenv setmetatable tonumber tostring type unpack xpcall arg self coroutine resume yield status wrap create running debug getupvalue debug sethook getmetatable gethook setmetatable setlocal traceback setfenv getinfo setupvalue getlocal getregistry getfenv io lines write close flush open output type read stderr stdin input stdout popen tmpfile math log max acos huge ldexp pi cos tanh pow deg tan cosh sinh random randomseed frexp ceil floor rad abs sqrt modf asin min mod fmod log10 atan2 exp sin atan os exit setlocale date getenv difftime remove time clock tmpname rename execute package preload loadlib loaded loaders cpath config path seeall string sub upper len gfind rep find match char dump gmatch reverse byte format gsub lower table setn insert getn foreachi maxn foreach concat sort remove" -},contains:o.concat([{className:"function",beginKeywords:"function",end:"\\)", -contains:[e.inherit(e.TITLE_MODE,{ -begin:"([_a-zA-Z]\\w*\\.)*([_a-zA-Z]\\w*:)?[_a-zA-Z]\\w*"}),{className:"params", -begin:"\\(",endsWithParent:!0,contains:o}].concat(o) -},e.C_NUMBER_MODE,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,{className:"string", -begin:t,end:a,contains:[n],relevance:5}])}}}()); -hljs.registerLanguage("makefile",function(){"use strict";return function(e){ -var i={className:"variable",variants:[{ -begin:"\\$\\("+e.UNDERSCORE_IDENT_RE+"\\)",contains:[e.BACKSLASH_ESCAPE]},{ -begin:/\$[@%`]+/}]}]}]};return{name:"HTML, XML", -aliases:["html","xhtml","rss","atom","xjb","xsd","xsl","plist","wsf","svg"], -case_insensitive:!0,contains:[{className:"meta",begin:"", -relevance:10,contains:[a,i,t,s,{begin:"\\[",end:"\\]",contains:[{ -className:"meta",begin:"",contains:[a,s,i,t]}]}] -},e.COMMENT("\x3c!--","--\x3e",{relevance:10}),{begin:"<\\!\\[CDATA\\[", -end:"\\]\\]>",relevance:10},n,{className:"meta",begin:/<\?xml/,end:/\?>/, -relevance:10},{className:"tag",begin:")",end:">",keywords:{ -name:"style"},contains:[c],starts:{end:"",returnEnd:!0, -subLanguage:["css","xml"]}},{className:"tag",begin:")",end:">", -keywords:{name:"script"},contains:[c],starts:{end:"<\/script>",returnEnd:!0, -subLanguage:["javascript","handlebars","xml"]}},{className:"tag",begin:"",contains:[{className:"name",begin:/[^\/><\s]+/,relevance:0},c]}]}} -}()); -hljs.registerLanguage("markdown",function(){"use strict";return function(n){ -const e={begin:"<",end:">",subLanguage:"xml",relevance:0},a={ -begin:"\\[.+?\\][\\(\\[].*?[\\)\\]]",returnBegin:!0,contains:[{ -className:"string",begin:"\\[",end:"\\]",excludeBegin:!0,returnEnd:!0, -relevance:0},{className:"link",begin:"\\]\\(",end:"\\)",excludeBegin:!0, -excludeEnd:!0},{className:"symbol",begin:"\\]\\[",end:"\\]",excludeBegin:!0, -excludeEnd:!0}],relevance:10},i={className:"strong",contains:[],variants:[{ -begin:/_{2}/,end:/_{2}/},{begin:/\*{2}/,end:/\*{2}/}]},s={className:"emphasis", -contains:[],variants:[{begin:/\*(?!\*)/,end:/\*/},{begin:/_(?!_)/,end:/_/, -relevance:0}]};i.contains.push(s),s.contains.push(i);var c=[e,a] -;return i.contains=i.contains.concat(c),s.contains=s.contains.concat(c),{ -name:"Markdown",aliases:["md","mkdown","mkd"],contains:[{className:"section", -variants:[{begin:"^#{1,6}",end:"$",contains:c=c.concat(i,s)},{ -begin:"(?=^.+?\\n[=-]{2,}$)",contains:[{begin:"^[=-]*$"},{begin:"^",end:"\\n", -contains:c}]}]},e,{className:"bullet",begin:"^[ \t]*([*+-]|(\\d+\\.))(?=\\s+)", -end:"\\s+",excludeEnd:!0},i,s,{className:"quote",begin:"^>\\s+",contains:c, -end:"$"},{className:"code",variants:[{begin:"(`{3,})(.|\\n)*?\\1`*[ ]*"},{ -begin:"(~{3,})(.|\\n)*?\\1~*[ ]*"},{begin:"```",end:"```+[ ]*$"},{begin:"~~~", -end:"~~~+[ ]*$"},{begin:"`.+?`"},{begin:"(?=^( {4}|\\t))",contains:[{ -begin:"^( {4}|\\t)",end:"(\\n)$"}],relevance:0}]},{begin:"^[-\\*]{3,}",end:"$" -},a,{begin:/^\[[^\n]+\]:/,returnBegin:!0,contains:[{className:"symbol", -begin:/\[/,end:/\]/,excludeBegin:!0,excludeEnd:!0},{className:"link", -begin:/:\s*/,end:/$/,excludeBegin:!0}]}]}}}()); -hljs.registerLanguage("nginx",function(){"use strict";return function(e){var n={ -className:"variable",variants:[{begin:/\$\d+/},{begin:/\$\{/,end:/}/},{ -begin:"[\\$\\@]"+e.UNDERSCORE_IDENT_RE}]},a={endsWithParent:!0,keywords:{ -$pattern:"[a-z/_]+", -literal:"on off yes no true false none blocked debug info notice warn error crit select break last permanent redirect kqueue rtsig epoll poll /dev/poll" -},relevance:0,illegal:"=>",contains:[e.HASH_COMMENT_MODE,{className:"string", -contains:[e.BACKSLASH_ESCAPE,n],variants:[{begin:/"/,end:/"/},{begin:/'/,end:/'/ -}]},{begin:"([a-z]+):/",end:"\\s",endsWithParent:!0,excludeEnd:!0,contains:[n] -},{className:"regexp",contains:[e.BACKSLASH_ESCAPE,n],variants:[{begin:"\\s\\^", -end:"\\s|{|;",returnEnd:!0},{begin:"~\\*?\\s+",end:"\\s|{|;",returnEnd:!0},{ -begin:"\\*(\\.[a-z\\-]+)+"},{begin:"([a-z\\-]+\\.)+\\*"}]},{className:"number", -begin:"\\b\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}(:\\d{1,5})?\\b"},{ -className:"number",begin:"\\b\\d+[kKmMgGdshdwy]*\\b",relevance:0},n]};return{ -name:"Nginx config",aliases:["nginxconf"],contains:[e.HASH_COMMENT_MODE,{ -begin:e.UNDERSCORE_IDENT_RE+"\\s+{",returnBegin:!0,end:"{",contains:[{ -className:"section",begin:e.UNDERSCORE_IDENT_RE}],relevance:0},{ -begin:e.UNDERSCORE_IDENT_RE+"\\s",end:";|{",returnBegin:!0,contains:[{ -className:"attribute",begin:e.UNDERSCORE_IDENT_RE,starts:a}],relevance:0}], -illegal:"[^\\s\\}]"}}}()); -hljs.registerLanguage("objectivec",function(){"use strict";return function(e){ -var n=/[a-zA-Z@][a-zA-Z0-9_]*/,_={$pattern:n, -keyword:"@interface @class @protocol @implementation"};return{ -name:"Objective-C",aliases:["mm","objc","obj-c","obj-c++","objective-c++"], -keywords:{$pattern:n, -keyword:"int float while char export sizeof typedef const struct for union unsigned long volatile static bool mutable if do return goto void enum else break extern asm case short default double register explicit signed typename this switch continue wchar_t inline readonly assign readwrite self @synchronized id typeof nonatomic super unichar IBOutlet IBAction strong weak copy in out inout bycopy byref oneway __strong __weak __block __autoreleasing @private @protected @public @try @property @end @throw @catch @finally @autoreleasepool @synthesize @dynamic @selector @optional @required @encode @package @import @defs @compatibility_alias __bridge __bridge_transfer __bridge_retained __bridge_retain __covariant __contravariant __kindof _Nonnull _Nullable _Null_unspecified __FUNCTION__ __PRETTY_FUNCTION__ __attribute__ getter setter retain unsafe_unretained nonnull nullable null_unspecified null_resettable class instancetype NS_DESIGNATED_INITIALIZER NS_UNAVAILABLE NS_REQUIRES_SUPER NS_RETURNS_INNER_POINTER NS_INLINE NS_AVAILABLE NS_DEPRECATED NS_ENUM NS_OPTIONS NS_SWIFT_UNAVAILABLE NS_ASSUME_NONNULL_BEGIN NS_ASSUME_NONNULL_END NS_REFINED_FOR_SWIFT NS_SWIFT_NAME NS_SWIFT_NOTHROW NS_DURING NS_HANDLER NS_ENDHANDLER NS_VALUERETURN NS_VOIDRETURN", -literal:"false true FALSE TRUE nil YES NO NULL", -built_in:"BOOL dispatch_once_t dispatch_queue_t dispatch_sync dispatch_async dispatch_once" -},illegal:"/,end:/$/, -illegal:"\\n"},e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},{ -className:"class",begin:"("+_.keyword.split(" ").join("|")+")\\b",end:"({|$)", -excludeEnd:!0,keywords:_,contains:[e.UNDERSCORE_TITLE_MODE]},{ -begin:"\\."+e.UNDERSCORE_IDENT_RE,relevance:0}]}}}()); -hljs.registerLanguage("perl",function(){"use strict";return function(e){var n={ -$pattern:/[\w.]+/, -keyword:"getpwent getservent quotemeta msgrcv scalar kill dbmclose undef lc ma syswrite tr send umask sysopen shmwrite vec qx utime local oct semctl localtime readpipe do return format read sprintf dbmopen pop getpgrp not getpwnam rewinddir qq fileno qw endprotoent wait sethostent bless s|0 opendir continue each sleep endgrent shutdown dump chomp connect getsockname die socketpair close flock exists index shmget sub for endpwent redo lstat msgctl setpgrp abs exit select print ref gethostbyaddr unshift fcntl syscall goto getnetbyaddr join gmtime symlink semget splice x|0 getpeername recv log setsockopt cos last reverse gethostbyname getgrnam study formline endhostent times chop length gethostent getnetent pack getprotoent getservbyname rand mkdir pos chmod y|0 substr endnetent printf next open msgsnd readdir use unlink getsockopt getpriority rindex wantarray hex system getservbyport endservent int chr untie rmdir prototype tell listen fork shmread ucfirst setprotoent else sysseek link getgrgid shmctl waitpid unpack getnetbyname reset chdir grep split require caller lcfirst until warn while values shift telldir getpwuid my getprotobynumber delete and sort uc defined srand accept package seekdir getprotobyname semop our rename seek if q|0 chroot sysread setpwent no crypt getc chown sqrt write setnetent setpriority foreach tie sin msgget map stat getlogin unless elsif truncate exec keys glob tied closedir ioctl socket readlink eval xor readline binmode setservent eof ord bind alarm pipe atan2 getgrent exp time push setgrent gt lt or ne m|0 break given say state when" -},t={className:"subst",begin:"[$@]\\{",end:"\\}",keywords:n},s={begin:"->{", -end:"}"},r={variants:[{begin:/\$\d/},{ -begin:/[\$%@](\^\w\b|#\w+(::\w+)*|{\w+}|\w+(::\w*)*)/},{begin:/[\$%@][^\s\w{]/, -relevance:0}] -},i=[e.BACKSLASH_ESCAPE,t,r],a=[r,e.HASH_COMMENT_MODE,e.COMMENT("^\\=\\w","\\=cut",{ -endsWithParent:!0}),s,{className:"string",contains:i,variants:[{ -begin:"q[qwxr]?\\s*\\(",end:"\\)",relevance:5},{begin:"q[qwxr]?\\s*\\[", -end:"\\]",relevance:5},{begin:"q[qwxr]?\\s*\\{",end:"\\}",relevance:5},{ -begin:"q[qwxr]?\\s*\\|",end:"\\|",relevance:5},{begin:"q[qwxr]?\\s*\\<", -end:"\\>",relevance:5},{begin:"qw\\s+q",end:"q",relevance:5},{begin:"'",end:"'", -contains:[e.BACKSLASH_ESCAPE]},{begin:'"',end:'"'},{begin:"`",end:"`", -contains:[e.BACKSLASH_ESCAPE]},{begin:"{\\w+}",contains:[],relevance:0},{ -begin:"-?\\w+\\s*\\=\\>",contains:[],relevance:0}]},{className:"number", -begin:"(\\b0[0-7_]+)|(\\b0x[0-9a-fA-F_]+)|(\\b[1-9][0-9_]*(\\.[0-9_]+)?)|[0_]\\b", -relevance:0},{ -begin:"(\\/\\/|"+e.RE_STARTERS_RE+"|\\b(split|return|print|reverse|grep)\\b)\\s*", -keywords:"split return print reverse grep",relevance:0, -contains:[e.HASH_COMMENT_MODE,{className:"regexp", -begin:"(s|tr|y)/(\\\\.|[^/])*/(\\\\.|[^/])*/[a-z]*",relevance:10},{ -className:"regexp",begin:"(m|qr)?/",end:"/[a-z]*",contains:[e.BACKSLASH_ESCAPE], -relevance:0}]},{className:"function",beginKeywords:"sub", -end:"(\\s*\\(.*?\\))?[;{]",excludeEnd:!0,relevance:5,contains:[e.TITLE_MODE]},{ -begin:"-\\w\\b",relevance:0},{begin:"^__DATA__$",end:"^__END__$", -subLanguage:"mojolicious",contains:[{begin:"^@@.*",end:"$",className:"comment"}] -}];return t.contains=a,s.contains=a,{name:"Perl",aliases:["pl","pm"],keywords:n, -contains:a}}}()); -hljs.registerLanguage("php",function(){"use strict";return function(e){var r={ -begin:"\\$+[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*"},t={className:"meta", -variants:[{begin:/<\?php/,relevance:10},{begin:/<\?[=]?/},{begin:/\?>/}]},a={ -className:"subst",variants:[{begin:/\$\w+/},{begin:/\{\$/,end:/\}/}] -},n=e.inherit(e.APOS_STRING_MODE,{illegal:null -}),i=e.inherit(e.QUOTE_STRING_MODE,{illegal:null, -contains:e.QUOTE_STRING_MODE.contains.concat(a)}),o=e.END_SAME_AS_BEGIN({ -begin:/<<<[ \t]*(\w+)\n/,end:/[ \t]*(\w+)\b/, -contains:e.QUOTE_STRING_MODE.contains.concat(a)}),l={className:"string", -contains:[e.BACKSLASH_ESCAPE,t],variants:[e.inherit(n,{begin:"b'",end:"'" -}),e.inherit(i,{begin:'b"',end:'"'}),i,n,o]},s={ -variants:[e.BINARY_NUMBER_MODE,e.C_NUMBER_MODE]},c={ -keyword:"__CLASS__ __DIR__ __FILE__ __FUNCTION__ __LINE__ __METHOD__ __NAMESPACE__ __TRAIT__ die echo exit include include_once print require require_once array abstract and as binary bool boolean break callable case catch class clone const continue declare default do double else elseif empty enddeclare endfor endforeach endif endswitch endwhile eval extends final finally float for foreach from global goto if implements instanceof insteadof int integer interface isset iterable list match new object or private protected public real return string switch throw trait try unset use var void while xor yield", -literal:"false null true", -built_in:"Error|0 AppendIterator ArgumentCountError ArithmeticError ArrayIterator ArrayObject AssertionError BadFunctionCallException BadMethodCallException CachingIterator CallbackFilterIterator CompileError Countable DirectoryIterator DivisionByZeroError DomainException EmptyIterator ErrorException Exception FilesystemIterator FilterIterator GlobIterator InfiniteIterator InvalidArgumentException IteratorIterator LengthException LimitIterator LogicException MultipleIterator NoRewindIterator OutOfBoundsException OutOfRangeException OuterIterator OverflowException ParentIterator ParseError RangeException RecursiveArrayIterator RecursiveCachingIterator RecursiveCallbackFilterIterator RecursiveDirectoryIterator RecursiveFilterIterator RecursiveIterator RecursiveIteratorIterator RecursiveRegexIterator RecursiveTreeIterator RegexIterator RuntimeException SeekableIterator SplDoublyLinkedList SplFileInfo SplFileObject SplFixedArray SplHeap SplMaxHeap SplMinHeap SplObjectStorage SplObserver SplObserver SplPriorityQueue SplQueue SplStack SplSubject SplSubject SplTempFileObject TypeError UnderflowException UnexpectedValueException ArrayAccess Closure Generator Iterator IteratorAggregate Serializable Throwable Traversable WeakReference Directory __PHP_Incomplete_Class parent php_user_filter self static stdClass" -};return{aliases:["php","php3","php4","php5","php6","php7","php8"], -case_insensitive:!0,keywords:c, -contains:[e.HASH_COMMENT_MODE,e.COMMENT("//","$",{contains:[t] -}),e.COMMENT("/\\*","\\*/",{contains:[{className:"doctag",begin:"@[A-Za-z]+"}] -}),e.COMMENT("__halt_compiler.+?;",!1,{endsWithParent:!0, -keywords:"__halt_compiler"}),t,{className:"keyword",begin:/\$this\b/},r,{ -begin:/(::|->)+[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*/},{className:"function", -beginKeywords:"fn function",end:/[;{]/,excludeEnd:!0,illegal:"[$%\\[]", -contains:[e.UNDERSCORE_TITLE_MODE,{className:"params",begin:"\\(",end:"\\)", -excludeBegin:!0,excludeEnd:!0,keywords:c, -contains:["self",r,e.C_BLOCK_COMMENT_MODE,l,s]}]},{className:"class", -beginKeywords:"class interface",end:"{",excludeEnd:!0,illegal:/[:\(\$"]/, -contains:[{beginKeywords:"extends implements"},e.UNDERSCORE_TITLE_MODE]},{ -beginKeywords:"namespace",end:";",illegal:/[\.']/, -contains:[e.UNDERSCORE_TITLE_MODE]},{beginKeywords:"use",end:";", -contains:[e.UNDERSCORE_TITLE_MODE]},{begin:"=>"},l,s]}}}()); -hljs.registerLanguage("php-template",function(){"use strict";return function(n){ -return{name:"PHP template",subLanguage:"xml",contains:[{begin:/<\?(php|=)?/, -end:/\?>/,subLanguage:"php",contains:[{begin:"/\\*",end:"\\*/",skip:!0},{ -begin:'b"',end:'"',skip:!0},{begin:"b'",end:"'",skip:!0 -},n.inherit(n.APOS_STRING_MODE,{illegal:null,className:null,contains:null, -skip:!0}),n.inherit(n.QUOTE_STRING_MODE,{illegal:null,className:null, -contains:null,skip:!0})]}]}}}()); -hljs.registerLanguage("plaintext",function(){"use strict";return function(t){ -return{name:"Plain text",aliases:["text","txt"],disableAutodetect:!0}}}()); -hljs.registerLanguage("properties",function(){"use strict";return function(e){ -var n="[ \\t\\f]*",t="("+n+"[:=]"+n+"|[ \\t\\f]+)",a="([^\\\\\\W:= \\t\\f\\n]|\\\\.)+",s="([^\\\\:= \\t\\f\\n]|\\\\.)+",r={ -end:t,relevance:0,starts:{className:"string",end:/$/,relevance:0,contains:[{ -begin:"\\\\\\n"}]}};return{name:".properties",case_insensitive:!0,illegal:/\S/, -contains:[e.COMMENT("^\\s*[!#]","$"),{begin:a+t,returnBegin:!0,contains:[{ -className:"attr",begin:a,endsParent:!0,relevance:0}],starts:r},{begin:s+t, -returnBegin:!0,relevance:0,contains:[{className:"meta",begin:s,endsParent:!0, -relevance:0}],starts:r},{className:"attr",relevance:0,begin:s+n+"$"}]}}}()); -hljs.registerLanguage("python",function(){"use strict";return function(e){ -const n={ -keyword:"and as assert async await break class continue def del elif else except finally for from global if import in is lambda nonlocal|10 not or pass raise return try while with yield", -built_in:"__import__ abs all any ascii bin bool breakpoint bytearray bytes callable chr classmethod compile complex delattr dict dir divmod enumerate eval exec filter float format frozenset getattr globals hasattr hash help hex id input int isinstance issubclass iter len list locals map max memoryview min next object oct open ord pow print property range repr reversed round set setattr slice sorted staticmethod str sum super tuple type vars zip", -literal:"__debug__ Ellipsis False None NotImplemented True"},a={ -className:"meta",begin:/^(>>>|\.\.\.) /},s={className:"subst",begin:/\{/, -end:/\}/,keywords:n,illegal:/#/},i={begin:/\{\{/,relevance:0},r={ -className:"string",contains:[e.BACKSLASH_ESCAPE],variants:[{ -begin:/([uU]|[bB]|[rR]|[bB][rR]|[rR][bB])?'''/,end:/'''/, -contains:[e.BACKSLASH_ESCAPE,a],relevance:10},{ -begin:/([uU]|[bB]|[rR]|[bB][rR]|[rR][bB])?"""/,end:/"""/, -contains:[e.BACKSLASH_ESCAPE,a],relevance:10},{ -begin:/([fF][rR]|[rR][fF]|[fF])'''/,end:/'''/, -contains:[e.BACKSLASH_ESCAPE,a,i,s]},{begin:/([fF][rR]|[rR][fF]|[fF])"""/, -end:/"""/,contains:[e.BACKSLASH_ESCAPE,a,i,s]},{begin:/([uU]|[rR])'/,end:/'/, -relevance:10},{begin:/([uU]|[rR])"/,end:/"/,relevance:10},{ -begin:/([bB]|[bB][rR]|[rR][bB])'/,end:/'/},{begin:/([bB]|[bB][rR]|[rR][bB])"/, -end:/"/},{begin:/([fF][rR]|[rR][fF]|[fF])'/,end:/'/, -contains:[e.BACKSLASH_ESCAPE,i,s]},{begin:/([fF][rR]|[rR][fF]|[fF])"/,end:/"/, -contains:[e.BACKSLASH_ESCAPE,i,s]},e.APOS_STRING_MODE,e.QUOTE_STRING_MODE]},t={ -className:"number",relevance:0,variants:[{begin:e.BINARY_NUMBER_RE+"[lLjJ]?"},{ -begin:"\\b(0o[0-7]+)[lLjJ]?"},{begin:e.C_NUMBER_RE+"[lLjJ]?"}]},l={ -className:"params",variants:[{begin:/\(\s*\)/,skip:!0,className:null},{ -begin:/\(/,end:/\)/,excludeBegin:!0,excludeEnd:!0,keywords:n, -contains:["self",a,t,r,e.HASH_COMMENT_MODE]}]};return s.contains=[r,t,a],{ -name:"Python",aliases:["py","gyp","ipython"],keywords:n, -illegal:/(<\/|->|\?)|=>/,contains:[a,t,{beginKeywords:"if",relevance:0 -},r,e.HASH_COMMENT_MODE,{variants:[{className:"function",beginKeywords:"def"},{ -className:"class",beginKeywords:"class"}],end:/:/,illegal:/[${=;\n,]/, -contains:[e.UNDERSCORE_TITLE_MODE,l,{begin:/->/,endsWithParent:!0, -keywords:"None"}]},{className:"meta",begin:/^[\t ]*@/,end:/$/},{ -begin:/\b(print|exec)\(/}]}}}()); -hljs.registerLanguage("python-repl",function(){"use strict";return function(n){ -return{aliases:["pycon"],contains:[{className:"meta",starts:{end:/ |$/,starts:{ -end:"$",subLanguage:"python"}},variants:[{begin:/^>>>(?=[ ]|$)/},{ -begin:/^\.\.\.(?=[ ]|$)/}]}]}}}()); -hljs.registerLanguage("ruby",function(){"use strict";return function(e){ -var n="[a-zA-Z_]\\w*[!?=]?|[-+~]\\@|<<|>>|=~|===?|<=>|[<>]=?|\\*\\*|[-/+%^&*~`|]|\\[\\]=?",a={ -keyword:"and then defined module in return redo if BEGIN retry end for self when next until do begin unless END rescue else break undef not super class case require yield alias while ensure elsif or include attr_reader attr_writer attr_accessor", -literal:"true false nil"},s={className:"doctag",begin:"@[A-Za-z]+"},i={ -begin:"#<",end:">"},r=[e.COMMENT("#","$",{contains:[s] -}),e.COMMENT("^\\=begin","^\\=end",{contains:[s],relevance:10 -}),e.COMMENT("^__END__","\\n$")],c={className:"subst",begin:"#\\{",end:"}", -keywords:a},t={className:"string",contains:[e.BACKSLASH_ESCAPE,c],variants:[{ -begin:/'/,end:/'/},{begin:/"/,end:/"/},{begin:/`/,end:/`/},{ -begin:"%[qQwWx]?\\(",end:"\\)"},{begin:"%[qQwWx]?\\[",end:"\\]"},{ -begin:"%[qQwWx]?{",end:"}"},{begin:"%[qQwWx]?<",end:">"},{begin:"%[qQwWx]?/", -end:"/"},{begin:"%[qQwWx]?%",end:"%"},{begin:"%[qQwWx]?-",end:"-"},{ -begin:"%[qQwWx]?\\|",end:"\\|"},{ -begin:/\B\?(\\\d{1,3}|\\x[A-Fa-f0-9]{1,2}|\\u[A-Fa-f0-9]{4}|\\?\S)\b/},{ -begin:/<<[-~]?'?(\w+)(?:.|\n)*?\n\s*\1\b/,returnBegin:!0,contains:[{ -begin:/<<[-~]?'?/},e.END_SAME_AS_BEGIN({begin:/(\w+)/,end:/(\w+)/, -contains:[e.BACKSLASH_ESCAPE,c]})]}]},b={className:"params",begin:"\\(", -end:"\\)",endsParent:!0,keywords:a},d=[t,i,{className:"class", -beginKeywords:"class module",end:"$|;",illegal:/=/, -contains:[e.inherit(e.TITLE_MODE,{begin:"[A-Za-z_]\\w*(::\\w+)*(\\?|\\!)?"}),{ -begin:"<\\s*",contains:[{begin:"("+e.IDENT_RE+"::)?"+e.IDENT_RE}]}].concat(r)},{ -className:"function",beginKeywords:"def",end:"$|;", -contains:[e.inherit(e.TITLE_MODE,{begin:n}),b].concat(r)},{begin:e.IDENT_RE+"::" -},{className:"symbol",begin:e.UNDERSCORE_IDENT_RE+"(\\!|\\?)?:",relevance:0},{ -className:"symbol",begin:":(?!\\s)",contains:[t,{begin:n}],relevance:0},{ -className:"number", -begin:"(\\b0[0-7_]+)|(\\b0x[0-9a-fA-F_]+)|(\\b[1-9][0-9_]*(\\.[0-9_]+)?)|[0_]\\b", -relevance:0},{begin:"(\\$\\W)|((\\$|\\@\\@?)(\\w+))"},{className:"params", -begin:/\|/,end:/\|/,keywords:a},{begin:"("+e.RE_STARTERS_RE+"|unless)\\s*", -keywords:"unless",contains:[i,{className:"regexp", -contains:[e.BACKSLASH_ESCAPE,c],illegal:/\n/,variants:[{begin:"/",end:"/[a-z]*" -},{begin:"%r{",end:"}[a-z]*"},{begin:"%r\\(",end:"\\)[a-z]*"},{begin:"%r!", -end:"![a-z]*"},{begin:"%r\\[",end:"\\][a-z]*"}]}].concat(r),relevance:0 -}].concat(r);c.contains=d,b.contains=d;var g=[{begin:/^\s*=>/,starts:{end:"$", -contains:d}},{className:"meta", -begin:"^([>?]>|[\\w#]+\\(\\w+\\):\\d+:\\d+>|(\\w+-)?\\d+\\.\\d+\\.\\d(p\\d+)?[^>]+>)", -starts:{end:"$",contains:d}}];return{name:"Ruby", -aliases:["rb","gemspec","podspec","thor","irb"],keywords:a,illegal:/\/\*/, -contains:r.concat(g).concat(d)}}}()); -hljs.registerLanguage("rust",function(){"use strict";return function(e){ -var n="([ui](8|16|32|64|128|size)|f(32|64))?",t="drop i8 i16 i32 i64 i128 isize u8 u16 u32 u64 u128 usize f32 f64 str char bool Box Option Result String Vec Copy Send Sized Sync Drop Fn FnMut FnOnce ToOwned Clone Debug PartialEq PartialOrd Eq Ord AsRef AsMut Into From Default Iterator Extend IntoIterator DoubleEndedIterator ExactSizeIterator SliceConcatExt ToString assert! assert_eq! bitflags! bytes! cfg! col! concat! concat_idents! debug_assert! debug_assert_eq! env! panic! file! format! format_args! include_bin! include_str! line! local_data_key! module_path! option_env! print! println! select! stringify! try! unimplemented! unreachable! vec! write! writeln! macro_rules! assert_ne! debug_assert_ne!" -;return{name:"Rust",aliases:["rs"],keywords:{$pattern:e.IDENT_RE+"!?", -keyword:"abstract as async await become box break const continue crate do dyn else enum extern false final fn for if impl in let loop macro match mod move mut override priv pub ref return self Self static struct super trait true try type typeof unsafe unsized use virtual where while yield", -literal:"true false Some None Ok Err",built_in:t},illegal:""}]}}}()); -hljs.registerLanguage("scss",function(){"use strict";return function(e){ -var t="@[a-z-]+",i={className:"variable",begin:"(\\$[a-zA-Z-][a-zA-Z0-9_-]*)\\b" -},r={className:"number",begin:"#[0-9A-Fa-f]+"} -;return e.CSS_NUMBER_MODE,e.QUOTE_STRING_MODE, -e.APOS_STRING_MODE,e.C_BLOCK_COMMENT_MODE,{name:"SCSS",case_insensitive:!0, -illegal:"[=/|']",contains:[e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,{ -className:"selector-id",begin:"\\#[A-Za-z0-9_-]+",relevance:0},{ -className:"selector-class",begin:"\\.[A-Za-z0-9_-]+",relevance:0},{ -className:"selector-attr",begin:"\\[",end:"\\]",illegal:"$"},{ -className:"selector-tag", -begin:"\\b(a|abbr|acronym|address|area|article|aside|audio|b|base|big|blockquote|body|br|button|canvas|caption|cite|code|col|colgroup|command|datalist|dd|del|details|dfn|div|dl|dt|em|embed|fieldset|figcaption|figure|footer|form|frame|frameset|(h[1-6])|head|header|hgroup|hr|html|i|iframe|img|input|ins|kbd|keygen|label|legend|li|link|map|mark|meta|meter|nav|noframes|noscript|object|ol|optgroup|option|output|p|param|pre|progress|q|rp|rt|ruby|samp|script|section|select|small|span|strike|strong|style|sub|sup|table|tbody|td|textarea|tfoot|th|thead|time|title|tr|tt|ul|var|video)\\b", -relevance:0},{className:"selector-pseudo", -begin:":(visited|valid|root|right|required|read-write|read-only|out-range|optional|only-of-type|only-child|nth-of-type|nth-last-of-type|nth-last-child|nth-child|not|link|left|last-of-type|last-child|lang|invalid|indeterminate|in-range|hover|focus|first-of-type|first-line|first-letter|first-child|first|enabled|empty|disabled|default|checked|before|after|active)" -},{className:"selector-pseudo", -begin:"::(after|before|choices|first-letter|first-line|repeat-index|repeat-item|selection|value)" -},i,{className:"attribute", -begin:"\\b(src|z-index|word-wrap|word-spacing|word-break|width|widows|white-space|visibility|vertical-align|unicode-bidi|transition-timing-function|transition-property|transition-duration|transition-delay|transition|transform-style|transform-origin|transform|top|text-underline-position|text-transform|text-shadow|text-rendering|text-overflow|text-indent|text-decoration-style|text-decoration-line|text-decoration-color|text-decoration|text-align-last|text-align|tab-size|table-layout|right|resize|quotes|position|pointer-events|perspective-origin|perspective|page-break-inside|page-break-before|page-break-after|padding-top|padding-right|padding-left|padding-bottom|padding|overflow-y|overflow-x|overflow-wrap|overflow|outline-width|outline-style|outline-offset|outline-color|outline|orphans|order|opacity|object-position|object-fit|normal|none|nav-up|nav-right|nav-left|nav-index|nav-down|min-width|min-height|max-width|max-height|mask|marks|margin-top|margin-right|margin-left|margin-bottom|margin|list-style-type|list-style-position|list-style-image|list-style|line-height|letter-spacing|left|justify-content|initial|inherit|ime-mode|image-orientation|image-resolution|image-rendering|icon|hyphens|height|font-weight|font-variant-ligatures|font-variant|font-style|font-stretch|font-size-adjust|font-size|font-language-override|font-kerning|font-feature-settings|font-family|font|float|flex-wrap|flex-shrink|flex-grow|flex-flow|flex-direction|flex-basis|flex|filter|empty-cells|display|direction|cursor|counter-reset|counter-increment|content|column-width|column-span|column-rule-width|column-rule-style|column-rule-color|column-rule|column-gap|column-fill|column-count|columns|color|clip-path|clip|clear|caption-side|break-inside|break-before|break-after|box-sizing|box-shadow|box-decoration-break|bottom|border-width|border-top-width|border-top-style|border-top-right-radius|border-top-left-radius|border-top-color|border-top|border-style|border-spacing|border-right-width|border-right-style|border-right-color|border-right|border-radius|border-left-width|border-left-style|border-left-color|border-left|border-image-width|border-image-source|border-image-slice|border-image-repeat|border-image-outset|border-image|border-color|border-collapse|border-bottom-width|border-bottom-style|border-bottom-right-radius|border-bottom-left-radius|border-bottom-color|border-bottom|border|background-size|background-repeat|background-position|background-origin|background-image|background-color|background-clip|background-attachment|background-blend-mode|background|backface-visibility|auto|animation-timing-function|animation-play-state|animation-name|animation-iteration-count|animation-fill-mode|animation-duration|animation-direction|animation-delay|animation|align-self|align-items|align-content)\\b", -illegal:"[^\\s]"},{ -begin:"\\b(whitespace|wait|w-resize|visible|vertical-text|vertical-ideographic|uppercase|upper-roman|upper-alpha|underline|transparent|top|thin|thick|text|text-top|text-bottom|tb-rl|table-header-group|table-footer-group|sw-resize|super|strict|static|square|solid|small-caps|separate|se-resize|scroll|s-resize|rtl|row-resize|ridge|right|repeat|repeat-y|repeat-x|relative|progress|pointer|overline|outside|outset|oblique|nowrap|not-allowed|normal|none|nw-resize|no-repeat|no-drop|newspaper|ne-resize|n-resize|move|middle|medium|ltr|lr-tb|lowercase|lower-roman|lower-alpha|loose|list-item|line|line-through|line-edge|lighter|left|keep-all|justify|italic|inter-word|inter-ideograph|inside|inset|inline|inline-block|inherit|inactive|ideograph-space|ideograph-parenthesis|ideograph-numeric|ideograph-alpha|horizontal|hidden|help|hand|groove|fixed|ellipsis|e-resize|double|dotted|distribute|distribute-space|distribute-letter|distribute-all-lines|disc|disabled|default|decimal|dashed|crosshair|collapse|col-resize|circle|char|center|capitalize|break-word|break-all|bottom|both|bolder|bold|block|bidi-override|below|baseline|auto|always|all-scroll|absolute|table|table-cell)\\b" -},{begin:":",end:";", -contains:[i,r,e.CSS_NUMBER_MODE,e.QUOTE_STRING_MODE,e.APOS_STRING_MODE,{ -className:"meta",begin:"!important"}]},{begin:"@(page|font-face)",lexemes:t, -keywords:"@page @font-face"},{begin:"@",end:"[{;]",returnBegin:!0, -keywords:"and or not only",contains:[{begin:t,className:"keyword" -},i,e.QUOTE_STRING_MODE,e.APOS_STRING_MODE,r,e.CSS_NUMBER_MODE]}]}}}()); -hljs.registerLanguage("shell",function(){"use strict";return function(s){return{ -name:"Shell Session",aliases:["console"],contains:[{className:"meta", -begin:"^\\s{0,3}[/\\w\\d\\[\\]()@-]*[>%$#]",starts:{end:"$",subLanguage:"bash"} -}]}}}()); -hljs.registerLanguage("sql",function(){"use strict";return function(e){ -var t=e.COMMENT("--","$");return{name:"SQL",case_insensitive:!0, -illegal:/[<>{}*]/,contains:[{ -beginKeywords:"begin end start commit rollback savepoint lock alter create drop rename call delete do handler insert load replace select truncate update set show pragma grant merge describe use explain help declare prepare execute deallocate release unlock purge reset change stop analyze cache flush optimize repair kill install uninstall checksum restore check backup revoke comment values with", -end:/;/,endsWithParent:!0,keywords:{$pattern:/[\w\.]+/, -keyword:"as abort abs absolute acc acce accep accept access accessed accessible account acos action activate add addtime admin administer advanced advise aes_decrypt aes_encrypt after agent aggregate ali alia alias all allocate allow alter always analyze ancillary and anti any anydata anydataset anyschema anytype apply archive archived archivelog are as asc ascii asin assembly assertion associate asynchronous at atan atn2 attr attri attrib attribu attribut attribute attributes audit authenticated authentication authid authors auto autoallocate autodblink autoextend automatic availability avg backup badfile basicfile before begin beginning benchmark between bfile bfile_base big bigfile bin binary_double binary_float binlog bit_and bit_count bit_length bit_or bit_xor bitmap blob_base block blocksize body both bound bucket buffer_cache buffer_pool build bulk by byte byteordermark bytes cache caching call calling cancel capacity cascade cascaded case cast catalog category ceil ceiling chain change changed char_base char_length character_length characters characterset charindex charset charsetform charsetid check checksum checksum_agg child choose chr chunk class cleanup clear client clob clob_base clone close cluster_id cluster_probability cluster_set clustering coalesce coercibility col collate collation collect colu colum column column_value columns columns_updated comment commit compact compatibility compiled complete composite_limit compound compress compute concat concat_ws concurrent confirm conn connec connect connect_by_iscycle connect_by_isleaf connect_by_root connect_time connection consider consistent constant constraint constraints constructor container content contents context contributors controlfile conv convert convert_tz corr corr_k corr_s corresponding corruption cos cost count count_big counted covar_pop covar_samp cpu_per_call cpu_per_session crc32 create creation critical cross cube cume_dist curdate current current_date current_time current_timestamp current_user cursor curtime customdatum cycle data database databases datafile datafiles datalength date_add date_cache date_format date_sub dateadd datediff datefromparts datename datepart datetime2fromparts day day_to_second dayname dayofmonth dayofweek dayofyear days db_role_change dbtimezone ddl deallocate declare decode decompose decrement decrypt deduplicate def defa defau defaul default defaults deferred defi defin define degrees delayed delegate delete delete_all delimited demand dense_rank depth dequeue des_decrypt des_encrypt des_key_file desc descr descri describ describe descriptor deterministic diagnostics difference dimension direct_load directory disable disable_all disallow disassociate discardfile disconnect diskgroup distinct distinctrow distribute distributed div do document domain dotnet double downgrade drop dumpfile duplicate duration each edition editionable editions element ellipsis else elsif elt empty enable enable_all enclosed encode encoding encrypt end end-exec endian enforced engine engines enqueue enterprise entityescaping eomonth error errors escaped evalname evaluate event eventdata events except exception exceptions exchange exclude excluding execu execut execute exempt exists exit exp expire explain explode export export_set extended extent external external_1 external_2 externally extract failed failed_login_attempts failover failure far fast feature_set feature_value fetch field fields file file_name_convert filesystem_like_logging final finish first first_value fixed flash_cache flashback floor flush following follows for forall force foreign form forma format found found_rows freelist freelists freepools fresh from from_base64 from_days ftp full function general generated get get_format get_lock getdate getutcdate global global_name globally go goto grant grants greatest group group_concat group_id grouping grouping_id groups gtid_subtract guarantee guard handler hash hashkeys having hea head headi headin heading heap help hex hierarchy high high_priority hosts hour hours http id ident_current ident_incr ident_seed identified identity idle_time if ifnull ignore iif ilike ilm immediate import in include including increment index indexes indexing indextype indicator indices inet6_aton inet6_ntoa inet_aton inet_ntoa infile initial initialized initially initrans inmemory inner innodb input insert install instance instantiable instr interface interleaved intersect into invalidate invisible is is_free_lock is_ipv4 is_ipv4_compat is_not is_not_null is_used_lock isdate isnull isolation iterate java join json json_exists keep keep_duplicates key keys kill language large last last_day last_insert_id last_value lateral lax lcase lead leading least leaves left len lenght length less level levels library like like2 like4 likec limit lines link list listagg little ln load load_file lob lobs local localtime localtimestamp locate locator lock locked log log10 log2 logfile logfiles logging logical logical_reads_per_call logoff logon logs long loop low low_priority lower lpad lrtrim ltrim main make_set makedate maketime managed management manual map mapping mask master master_pos_wait match matched materialized max maxextents maximize maxinstances maxlen maxlogfiles maxloghistory maxlogmembers maxsize maxtrans md5 measures median medium member memcompress memory merge microsecond mid migration min minextents minimum mining minus minute minutes minvalue missing mod mode model modification modify module monitoring month months mount move movement multiset mutex name name_const names nan national native natural nav nchar nclob nested never new newline next nextval no no_write_to_binlog noarchivelog noaudit nobadfile nocheck nocompress nocopy nocycle nodelay nodiscardfile noentityescaping noguarantee nokeep nologfile nomapping nomaxvalue nominimize nominvalue nomonitoring none noneditionable nonschema noorder nopr nopro noprom nopromp noprompt norely noresetlogs noreverse normal norowdependencies noschemacheck noswitch not nothing notice notnull notrim novalidate now nowait nth_value nullif nulls num numb numbe nvarchar nvarchar2 object ocicoll ocidate ocidatetime ociduration ociinterval ociloblocator ocinumber ociref ocirefcursor ocirowid ocistring ocitype oct octet_length of off offline offset oid oidindex old on online only opaque open operations operator optimal optimize option optionally or oracle oracle_date oradata ord ordaudio orddicom orddoc order ordimage ordinality ordvideo organization orlany orlvary out outer outfile outline output over overflow overriding package pad parallel parallel_enable parameters parent parse partial partition partitions pascal passing password password_grace_time password_lock_time password_reuse_max password_reuse_time password_verify_function patch path patindex pctincrease pctthreshold pctused pctversion percent percent_rank percentile_cont percentile_disc performance period period_add period_diff permanent physical pi pipe pipelined pivot pluggable plugin policy position post_transaction pow power pragma prebuilt precedes preceding precision prediction prediction_cost prediction_details prediction_probability prediction_set prepare present preserve prior priority private private_sga privileges procedural procedure procedure_analyze processlist profiles project prompt protection public publishingservername purge quarter query quick quiesce quota quotename radians raise rand range rank raw read reads readsize rebuild record records recover recovery recursive recycle redo reduced ref reference referenced references referencing refresh regexp_like register regr_avgx regr_avgy regr_count regr_intercept regr_r2 regr_slope regr_sxx regr_sxy reject rekey relational relative relaylog release release_lock relies_on relocate rely rem remainder rename repair repeat replace replicate replication required reset resetlogs resize resource respect restore restricted result result_cache resumable resume retention return returning returns reuse reverse revoke right rlike role roles rollback rolling rollup round row row_count rowdependencies rowid rownum rows rtrim rules safe salt sample save savepoint sb1 sb2 sb4 scan schema schemacheck scn scope scroll sdo_georaster sdo_topo_geometry search sec_to_time second seconds section securefile security seed segment select self semi sequence sequential serializable server servererror session session_user sessions_per_user set sets settings sha sha1 sha2 share shared shared_pool short show shrink shutdown si_averagecolor si_colorhistogram si_featurelist si_positionalcolor si_stillimage si_texture siblings sid sign sin size size_t sizes skip slave sleep smalldatetimefromparts smallfile snapshot some soname sort soundex source space sparse spfile split sql sql_big_result sql_buffer_result sql_cache sql_calc_found_rows sql_small_result sql_variant_property sqlcode sqldata sqlerror sqlname sqlstate sqrt square standalone standby start starting startup statement static statistics stats_binomial_test stats_crosstab stats_ks_test stats_mode stats_mw_test stats_one_way_anova stats_t_test_ stats_t_test_indep stats_t_test_one stats_t_test_paired stats_wsr_test status std stddev stddev_pop stddev_samp stdev stop storage store stored str str_to_date straight_join strcmp strict string struct stuff style subdate subpartition subpartitions substitutable substr substring subtime subtring_index subtype success sum suspend switch switchoffset switchover sync synchronous synonym sys sys_xmlagg sysasm sysaux sysdate sysdatetimeoffset sysdba sysoper system system_user sysutcdatetime table tables tablespace tablesample tan tdo template temporary terminated tertiary_weights test than then thread through tier ties time time_format time_zone timediff timefromparts timeout timestamp timestampadd timestampdiff timezone_abbr timezone_minute timezone_region to to_base64 to_date to_days to_seconds todatetimeoffset trace tracking transaction transactional translate translation treat trigger trigger_nestlevel triggers trim truncate try_cast try_convert try_parse type ub1 ub2 ub4 ucase unarchived unbounded uncompress under undo unhex unicode uniform uninstall union unique unix_timestamp unknown unlimited unlock unnest unpivot unrecoverable unsafe unsigned until untrusted unusable unused update updated upgrade upped upper upsert url urowid usable usage use use_stored_outlines user user_data user_resources users using utc_date utc_timestamp uuid uuid_short validate validate_password_strength validation valist value values var var_samp varcharc vari varia variab variabl variable variables variance varp varraw varrawc varray verify version versions view virtual visible void wait wallet warning warnings week weekday weekofyear wellformed when whene whenev wheneve whenever where while whitespace window with within without work wrapped xdb xml xmlagg xmlattributes xmlcast xmlcolattval xmlelement xmlexists xmlforest xmlindex xmlnamespaces xmlpi xmlquery xmlroot xmlschema xmlserialize xmltable xmltype xor year year_to_month years yearweek", -literal:"true false null unknown", -built_in:"array bigint binary bit blob bool boolean char character date dec decimal float int int8 integer interval number numeric real record serial serial8 smallint text time timestamp tinyint varchar varchar2 varying void" -},contains:[{className:"string",begin:"'",end:"'",contains:[{begin:"''"}]},{ -className:"string",begin:'"',end:'"',contains:[{begin:'""'}]},{ -className:"string",begin:"`",end:"`" -},e.C_NUMBER_MODE,e.C_BLOCK_COMMENT_MODE,t,e.HASH_COMMENT_MODE] -},e.C_BLOCK_COMMENT_MODE,t,e.HASH_COMMENT_MODE]}}}()); -hljs.registerLanguage("swift",function(){"use strict";return function(e){var i={ -keyword:"#available #colorLiteral #column #else #elseif #endif #file #fileLiteral #function #if #imageLiteral #line #selector #sourceLocation _ __COLUMN__ __FILE__ __FUNCTION__ __LINE__ Any as as! as? associatedtype associativity break case catch class continue convenience default defer deinit didSet do dynamic dynamicType else enum extension fallthrough false fileprivate final for func get guard if import in indirect infix init inout internal is lazy left let mutating nil none nonmutating open operator optional override postfix precedence prefix private protocol Protocol public repeat required rethrows return right self Self set static struct subscript super switch throw throws true try try! try? Type typealias unowned var weak where while willSet", -literal:"true false nil", -built_in:"abs advance alignof alignofValue anyGenerator assert assertionFailure bridgeFromObjectiveC bridgeFromObjectiveCUnconditional bridgeToObjectiveC bridgeToObjectiveCUnconditional c compactMap contains count countElements countLeadingZeros debugPrint debugPrintln distance dropFirst dropLast dump encodeBitsAsWords enumerate equal fatalError filter find getBridgedObjectiveCType getVaList indices insertionSort isBridgedToObjectiveC isBridgedVerbatimToObjectiveC isUniquelyReferenced isUniquelyReferencedNonObjC join lazy lexicographicalCompare map max maxElement min minElement numericCast overlaps partition posix precondition preconditionFailure print println quickSort readLine reduce reflect reinterpretCast reverse roundUpToAlignment sizeof sizeofValue sort split startsWith stride strideof strideofValue swap toString transcode underestimateCount unsafeAddressOf unsafeBitCast unsafeDowncast unsafeUnwrap unsafeReflect withExtendedLifetime withObjectAtPlusZero withUnsafePointer withUnsafePointerToObject withUnsafeMutablePointer withUnsafeMutablePointers withUnsafePointer withUnsafePointers withVaList zip" -},n=e.COMMENT("/\\*","\\*/",{contains:["self"]}),t={className:"subst", -begin:/\\\(/,end:"\\)",keywords:i,contains:[]},a={className:"string", -contains:[e.BACKSLASH_ESCAPE,t],variants:[{begin:/"""/,end:/"""/},{begin:/"/, -end:/"/}]},r={className:"number", -begin:"\\b([\\d_]+(\\.[\\deE_]+)?|0x[a-fA-F0-9_]+(\\.[a-fA-F0-9p_]+)?|0b[01_]+|0o[0-7_]+)\\b", -relevance:0};return t.contains=[r],{name:"Swift",keywords:i, -contains:[a,e.C_LINE_COMMENT_MODE,n,{className:"type", -begin:"\\b[A-Z][\\w\xc0-\u02b8']*[!?]"},{className:"type", -begin:"\\b[A-Z][\\w\xc0-\u02b8']*",relevance:0},r,{className:"function", -beginKeywords:"func",end:"{",excludeEnd:!0,contains:[e.inherit(e.TITLE_MODE,{ -begin:/[A-Za-z$_][0-9A-Za-z$_]*/}),{begin://},{className:"params", -begin:/\(/,end:/\)/,endsParent:!0,keywords:i, -contains:["self",r,a,e.C_BLOCK_COMMENT_MODE,{begin:":"}],illegal:/["']/}], -illegal:/\[|%/},{className:"class", -beginKeywords:"struct protocol class extension enum",keywords:i,end:"\\{", -excludeEnd:!0,contains:[e.inherit(e.TITLE_MODE,{ -begin:/[A-Za-z$_][\u00C0-\u02B80-9A-Za-z$_]*/})]},{className:"meta", -begin:"(@discardableResult|@warn_unused_result|@exported|@lazy|@noescape|@NSCopying|@NSManaged|@objc|@objcMembers|@convention|@required|@noreturn|@IBAction|@IBDesignable|@IBInspectable|@IBOutlet|@infix|@prefix|@postfix|@autoclosure|@testable|@available|@nonobjc|@NSApplicationMain|@UIApplicationMain|@dynamicMemberLookup|@propertyWrapper)\\b" -},{beginKeywords:"import",end:/$/,contains:[e.C_LINE_COMMENT_MODE,n]}]}}}()); -hljs.registerLanguage("typescript",function(){"use strict" -;const e="[A-Za-z$_][0-9A-Za-z$_]*",n=["as","in","of","if","for","while","finally","var","new","function","do","return","void","else","break","catch","instanceof","with","throw","case","default","try","switch","continue","typeof","delete","let","yield","const","class","debugger","async","await","static","import","from","export","extends"],a=["true","false","null","undefined","NaN","Infinity"],s=[].concat(["setInterval","setTimeout","clearInterval","clearTimeout","require","exports","eval","isFinite","isNaN","parseFloat","parseInt","decodeURI","decodeURIComponent","encodeURI","encodeURIComponent","escape","unescape"],["arguments","this","super","console","window","document","localStorage","module","global"],["Intl","DataView","Number","Math","Date","String","RegExp","Object","Function","Boolean","Error","Symbol","Set","Map","WeakSet","WeakMap","Proxy","Reflect","JSON","Promise","Float64Array","Int16Array","Int32Array","Int8Array","Uint16Array","Uint32Array","Float32Array","Array","Uint8Array","Uint8ClampedArray","ArrayBuffer"],["EvalError","InternalError","RangeError","ReferenceError","SyntaxError","TypeError","URIError"]) -;function t(e){return r("(?=",e,")")}function i(e){return r("(",e,")?")} -function r(...e){return e.map((e=>{ -return(n=e)?"string"==typeof n?n:n.source:null;var n})).join("")} -return function(c){const o={$pattern:e, -keyword:n.concat(["type","namespace","typedef","interface","public","private","protected","implements","declare","abstract","readonly"]).join(" "), -literal:a.join(" "), -built_in:s.concat(["any","void","number","boolean","string","object","never","enum"]).join(" ") -},l={className:"meta",begin:"@[A-Za-z$_][0-9A-Za-z$_]*"},d=(e,n,a)=>{ -const s=e.contains.findIndex((e=>e.label===n)) -;if(-1===s)throw Error("can not find mode to replace");e.contains.splice(s,1,a) -},g=function(c){const o=e,l={begin:/<[A-Za-z0-9\\._:-]+/, -end:/\/[A-Za-z0-9\\._:-]+>|\/>/,isTrulyOpeningTag:(e,n)=>{ -const a=e[0].length+e.index,s=e.input[a];"<"!==s?">"===s&&(((e,{after:n})=>{ -const a=e[0].replace("<","`\\b0[${e}][${n}]([${n}_]*[${n}])?n?`,b=/[1-9]([0-9_]*\d)?/,u=/\d([0-9_]*\d)?/,E=r(/[eE][+-]?/,u),m={ -className:"number",variants:[{begin:g("bB","01")},{begin:g("oO","0-7")},{ -begin:g("xX","0-9a-fA-F")},{begin:r(/\b/,b,"n")},{begin:r(/(\b0)?\./,u,i(E))},{ -begin:r(/\b/,b,i(r(/\./,i(u))),i(E))},{begin:/\b0[\.n]?/}],relevance:0},y={ -className:"subst",begin:"\\$\\{",end:"\\}",keywords:d,contains:[]},p={ -begin:"html`",end:"",starts:{end:"`",returnEnd:!1, -contains:[c.BACKSLASH_ESCAPE,y],subLanguage:"xml"}},_={begin:"css`",end:"", -starts:{end:"`",returnEnd:!1,contains:[c.BACKSLASH_ESCAPE,y],subLanguage:"css"} -},N={className:"string",begin:"`",end:"`",contains:[c.BACKSLASH_ESCAPE,y]},f={ -className:"comment",variants:[c.COMMENT("/\\*\\*","\\*/",{relevance:0, -contains:[{className:"doctag",begin:"@[A-Za-z]+",contains:[{className:"type", -begin:"\\{",end:"\\}",relevance:0},{className:"variable", -begin:o+"(?=\\s*(-)|$)",endsParent:!0,relevance:0},{begin:/(?=[^\n])\s/, -relevance:0}]}]}),c.C_BLOCK_COMMENT_MODE,c.C_LINE_COMMENT_MODE] -},A=[c.APOS_STRING_MODE,c.QUOTE_STRING_MODE,p,_,N,m,c.REGEXP_MODE] -;y.contains=A.concat({begin:/{/,end:/}/,keywords:d,contains:["self"].concat(A)}) -;const O=[].concat(f,y.contains),S=O.concat([{begin:/\(/,end:/\)/,keywords:d, -contains:["self"].concat(O)}]),T={className:"params",begin:/\(/,end:/\)/, -excludeBegin:!0,excludeEnd:!0,keywords:d,contains:S};return{name:"Javascript", -aliases:["js","jsx","mjs","cjs"],keywords:d,exports:{PARAMS_CONTAINS:S}, -illegal:/#(?![$_A-z])/,contains:[c.SHEBANG({label:"shebang",binary:"node", -relevance:5}),{label:"use_strict",className:"meta",relevance:10, -begin:/^\s*['"]use (strict|asm)['"]/ -},c.APOS_STRING_MODE,c.QUOTE_STRING_MODE,p,_,N,f,m,{ -begin:r(/[{,\n]\s*/,t(r(/(\/\/.*$)*/,/(\/\*(.|\n)*\*\/)*/,/\s*/,o+"\\s*:"))), -relevance:0,contains:[{className:"attr",begin:o+t("\\s*:"),relevance:0}]},{ -begin:"("+c.RE_STARTERS_RE+"|\\b(case|return|throw)\\b)\\s*", -keywords:"return throw case",contains:[f,c.REGEXP_MODE,{className:"function", -begin:"(\\([^()]*(\\([^()]*(\\([^()]*\\))*[^()]*\\))*[^()]*\\)|"+c.UNDERSCORE_IDENT_RE+")\\s*=>", -returnBegin:!0,end:"\\s*=>",contains:[{className:"params",variants:[{ -begin:c.UNDERSCORE_IDENT_RE},{className:null,begin:/\(\s*\)/,skip:!0},{ -begin:/\(/,end:/\)/,excludeBegin:!0,excludeEnd:!0,keywords:d,contains:S}]}]},{ -begin:/,/,relevance:0},{className:"",begin:/\s/,end:/\s*/,skip:!0},{variants:[{ -begin:"<>",end:""},{begin:l.begin,"on:begin":l.isTrulyOpeningTag,end:l.end}], -subLanguage:"xml",contains:[{begin:l.begin,end:l.end,skip:!0,contains:["self"]}] -}],relevance:0},{className:"function",beginKeywords:"function",end:/[{;]/, -excludeEnd:!0,keywords:d,contains:["self",c.inherit(c.TITLE_MODE,{begin:o}),T], -illegal:/%/},{className:"function", -begin:c.UNDERSCORE_IDENT_RE+"\\([^()]*(\\([^()]*(\\([^()]*\\))*[^()]*\\))*[^()]*\\)\\s*{", -returnBegin:!0,contains:[T,c.inherit(c.TITLE_MODE,{begin:o})]},{variants:[{ -begin:"\\."+o},{begin:"\\$"+o}],relevance:0},{className:"class", -beginKeywords:"class",end:/[{;=]/,excludeEnd:!0,illegal:/[:"\[\]]/,contains:[{ -beginKeywords:"extends"},c.UNDERSCORE_TITLE_MODE]},{begin:/\b(?=constructor)/, -end:/[\{;]/,excludeEnd:!0,contains:[c.inherit(c.TITLE_MODE,{begin:o}),"self",T] -},{begin:"(get|set)\\s+(?="+o+"\\()",end:/{/,keywords:"get set", -contains:[c.inherit(c.TITLE_MODE,{begin:o}),{begin:/\(\)/},T]},{begin:/\$[(.]/}] -}}(c) -;return Object.assign(g.keywords,o),g.exports.PARAMS_CONTAINS.push(l),g.contains=g.contains.concat([l,{ -beginKeywords:"namespace",end:/\{/,excludeEnd:!0},{beginKeywords:"interface", -end:/\{/,excludeEnd:!0,keywords:"interface extends" -}]),d(g,"shebang",c.SHEBANG()),d(g,"use_strict",{className:"meta",relevance:10, -begin:/^\s*['"]use strict['"]/ -}),g.contains.find((e=>"function"===e.className)).relevance=0,Object.assign(g,{ -name:"TypeScript",aliases:["ts"]}),g}}()); -hljs.registerLanguage("yaml",function(){"use strict";return function(e){ -var n="true false yes no null",a="[\\w#;/?:@&=+$,.~*\\'()[\\]]+",s={ -className:"string",relevance:0,variants:[{begin:/'/,end:/'/},{begin:/"/,end:/"/ -},{begin:/\S+/}],contains:[e.BACKSLASH_ESCAPE,{className:"template-variable", -variants:[{begin:"{{",end:"}}"},{begin:"%{",end:"}"}]}]},i=e.inherit(s,{ -variants:[{begin:/'/,end:/'/},{begin:/"/,end:/"/},{begin:/[^\s,{}[\]]+/}]}),l={ -end:",",endsWithParent:!0,excludeEnd:!0,contains:[],keywords:n,relevance:0},t={ -begin:"{",end:"}",contains:[l],illegal:"\\n",relevance:0},g={begin:"\\[", -end:"\\]",contains:[l],illegal:"\\n",relevance:0},b=[{className:"attr", -variants:[{begin:"\\w[\\w :\\/.-]*:(?=[ \t]|$)"},{ -begin:'"\\w[\\w :\\/.-]*":(?=[ \t]|$)'},{begin:"'\\w[\\w :\\/.-]*':(?=[ \t]|$)" -}]},{className:"meta",begin:"^---s*$",relevance:10},{className:"string", -begin:"[\\|>]([0-9]?[+-])?[ ]*\\n( *)[\\S ]+\\n(\\2[\\S ]+\\n?)*"},{ -begin:"<%[%=-]?",end:"[%-]?%>",subLanguage:"ruby",excludeBegin:!0,excludeEnd:!0, -relevance:0},{className:"type",begin:"!\\w+!"+a},{className:"type", -begin:"!<"+a+">"},{className:"type",begin:"!"+a},{className:"type",begin:"!!"+a -},{className:"meta",begin:"&"+e.UNDERSCORE_IDENT_RE+"$"},{className:"meta", -begin:"\\*"+e.UNDERSCORE_IDENT_RE+"$"},{className:"bullet",begin:"\\-(?=[ ]|$)", -relevance:0},e.HASH_COMMENT_MODE,{beginKeywords:n,keywords:{literal:n}},{ -className:"number", -begin:"\\b[0-9]{4}(-[0-9][0-9]){0,2}([Tt \\t][0-9][0-9]?(:[0-9][0-9]){2})?(\\.[0-9]*)?([ \\t])*(Z|[-+][0-9][0-9]?(:[0-9][0-9])?)?\\b" -},{className:"number",begin:e.C_NUMBER_RE+"\\b"},t,g,s],c=[...b];return c.pop(), -c.push(i),l.contains=c,{name:"YAML",case_insensitive:!0,aliases:["yml","YAML"], -contains:b}}}()); - -// original from https://github.com/leanprover-community/highlightjs-lean/blob/master/src/lean.js, BSD 3, (c) 2020 Patrick Massot -hljs.registerLanguage("lean", function(hljs) { - var LEAN_KEYWORDS = { - $pattern: /#?\w+/, - keyword: - 'theorem|10 def class structure instance set_option ' + - 'example inductive coinductive ' + - 'axiom constant ' + - 'partial unsafe private protected ' + - 'if then else ' + - 'universe variable ' + - 'import open export prelude renaming hiding ' + - 'calc match with do by let extends ' + - 'for in unless try catch finally mutual mut return continue break where rec ' + - 'syntax macro_rules macro deriving ' + - 'fun ' + - '#check #check_failure #eval #reduce #print ' + - 'section namespace end infix infixl infixr postfix prefix notation ', - built_in: - 'Type Prop|10 Sort rw|10 rewrite rwa erw subst substs ' + - 'simp dsimp simpa simp_intros finish using generalizing ' + - 'unfold unfold1 dunfold unfold_projs unfold_coes ' + - 'delta cc ac_rfl ' + - 'existsi|10 cases rcases intro intros introv by_cases ' + - 'refl rfl funext case focus propext exact exacts ' + - 'refine apply eapply fapply apply_with apply_instance ' + - 'induction rename assumption revert generalize specialize clear ' + - 'contradiction by_contradiction by_contra trivial exfalso ' + - 'symmetry transitivity destruct constructor econstructor ' + - 'left right split injection injections ' + - 'repeat skip swap solve1 abstract all_goals any_goals done ' + - 'fail_if_success success_if_fail guard_target guard_hyp ' + - 'have replace at suffices show from ' + - 'congr congr_n congr_arg norm_num ring ', - literal: - 'true false', - meta: - 'noncomputable|10 private protected mutual', - strong: - 'sorry admit', - }; - - var LEAN_IDENT_RE = /[A-Za-z_][\\w\u207F-\u209C\u1D62-\u1D6A\u2079\'0-9?]*/; - - var DASH_COMMENT = hljs.COMMENT('--', '$'); - var MULTI_LINE_COMMENT = hljs.COMMENT('/-[^-]', '-/'); - var DOC_COMMENT = { - className: 'doctag', - begin: '/-[-!]', - end: '-/' - }; - - var ATTRIBUTE_DECORATOR = { - className: 'meta', - begin: '@\\[', - end: '\\]' - }; - - var ATTRIBUTE_LINE = { - className: 'meta', - begin: '^attribute', - end: '$' - }; - - var LEAN_DEFINITION = { - className: 'theorem', - begin: '\\b(def|theorem|lemma|class|structure|(? f 0 - -#check foo -- (Nat → Nat) → Nat -#print foo -``` - -We can omit the type when Lean has enough information to infer it: - -```lean -def foo := - fun (f : Nat → Nat) => f 0 -``` - -The general form of a definition is ``def foo : α := bar``. Lean can usually infer the type ``α``, but it is often a good idea to write it explicitly. -This clarifies your intention, and Lean will flag an error if the right-hand side of the definition does not have the right type. - -Lean also allows us to use an alternative format that puts the abstracted variables before the colon and omits the lambda: -```lean -def double (x : Nat) : Nat := - x + x - -#print double -#check double 3 -#reduce double 3 -- 6 -#eval double 3 -- 6 - -def square (x : Nat) := - x * x - -#print square -#check square 3 -#reduce square 3 -- 9 -#eval square 3 -- 9 - -def doTwice (f : Nat → Nat) (x : Nat) : Nat := - f (f x) - -#eval doTwice double 2 -- 8 -``` - -These definitions are equivalent to the following: - -```lean -def double : Nat → Nat := - fun x => x + x - -def square : Nat → Nat := - fun x => x * x - -def doTwice : (Nat → Nat) → Nat → Nat := - fun f x => f (f x) -``` - -We can even use this approach to specify arguments that are types: - -```lean -def compose (α β γ : Type) (g : β → γ) (f : α → β) (x : α) : γ := - g (f x) -``` diff --git a/doc/lean3changes.md b/doc/lean3changes.md deleted file mode 100644 index aad3fd05d8..0000000000 --- a/doc/lean3changes.md +++ /dev/null @@ -1,369 +0,0 @@ -# Significant changes from Lean 3 - -Lean 4 is not backward compatible with Lean 3. -We have rewritten most of the system, and took the opportunity to cleanup the syntax, -metaprogramming framework, and elaborator. In this section, we go over the most significant -changes. - -## Lambda expressions - -We do not use `,` anymore to separate the binders from the lambda expression body. -The Lean 3 syntax for lambda expressions was unconventional, and `,` has been overused in Lean 3. -For example, we believe a list of lambda expressions is quite confusing in Lean 3, since `,` is used -to separate the elements of a list, and in the lambda expression itself. We now use `=>` as the separator, -as an example, `fun x => x` is the identity function. One may still use the symbol `λ` as a shorthand for `fun`. -The lambda expression notation has many new features that are not supported in Lean 3. - -## Pattern matching - -In Lean 4, one can easily create new notation that abbreviates commonly used idioms. One of them is a -`fun` followed by a `match`. In the following examples, we define a few functions using `fun`+`match` notation. - -```lean -# namespace ex1 -def Prod.str : Nat × Nat → String := - fun (a, b) => "(" ++ toString a ++ ", " ++ toString b ++ ")" - -structure Point where - x : Nat - y : Nat - z : Nat - -def Point.addX : Point → Point → Nat := - fun { x := a, .. } { x := b, .. } => a+b - -def Sum.str : Option Nat → String := - fun - | some a => "some " ++ toString a - | none => "none" -# end ex1 -``` - -## Implicit lambdas - -In Lean 3 stdlib, we find many [instances](https://github.com/leanprover/lean/blob/master/library/init/category/reader.lean#L39) of the dreadful `@`+`_` idiom. -It is often used when the expected type is a function type with implicit arguments, -and we have a constant (`reader_t.pure` in the example) which also takes implicit arguments. In Lean 4, the elaborator automatically introduces lambdas -for consuming implicit arguments. We are still exploring this feature and analyzing its impact, but the experience so far has been very positive. As an example, -here is the example in the link above using Lean 4 implicit lambdas. - -```lean -# variable (ρ : Type) (m : Type → Type) [Monad m] -instance : Monad (ReaderT ρ m) where - pure := ReaderT.pure - bind := ReaderT.bind -``` - -Users can disable the implicit lambda feature by using `@` or writing a lambda expression with `{}` or `[]` binder annotations. -Here are few examples - -```lean -# namespace ex2 -def id1 : {α : Type} → α → α := - fun x => x - -def listId : List ({α : Type} → α → α) := - (fun x => x) :: [] - --- In this example, implicit lambda introduction has been disabled because --- we use `@` before `fun` -def id2 : {α : Type} → α → α := - @fun α (x : α) => id1 x - -def id3 : {α : Type} → α → α := - @fun α x => id1 x - -def id4 : {α : Type} → α → α := - fun x => id1 x - --- In this example, implicit lambda introduction has been disabled --- because we used the binder annotation `{...}` -def id5 : {α : Type} → α → α := - fun {α} x => id1 x -# end ex2 -``` - -## Sugar for simple functions - -In Lean 3, we can create simple functions from infix operators by using parentheses. For example, `(+1)` is sugar for `fun x, x + 1`. In Lean 4, we generalize this notation using `·` as a placeholder. Here are a few examples: - -```lean -# namespace ex3 -#check (· + 1) --- fun a => a + 1 -#check (2 - ·) --- fun a => 2 - a -#eval [1, 2, 3, 4, 5].foldl (·*·) 1 --- 120 - -def f (x y z : Nat) := - x + y + z - -#check (f · 1 ·) --- fun a b => f a 1 b - -#eval [(1, 2), (3, 4), (5, 6)].map (·.1) --- [1, 3, 5] -# end ex3 -``` - -As in Lean 3, the notation is activated using parentheses, and the lambda abstraction is created by collecting the nested `·`s. -The collection is interrupted by nested parentheses. In the following example, two different lambda expressions are created. - -```lean -#check (Prod.mk · (· + 1)) --- fun a => (a, fun b => b + 1) -``` - -## Function applications - -In Lean 4, we have support for named arguments. -Named arguments enable you to specify an argument for a parameter by matching the argument with -its name rather than with its position in the parameter list. -If you don't remember the order of the parameters but know their names, -you can send the arguments in any order. You may also provide the value for an implicit parameter when -Lean failed to infer it. Named arguments also improve the readability of your code by identifying what -each argument represents. - -```lean -def sum (xs : List Nat) := - xs.foldl (init := 0) (·+·) - -#eval sum [1, 2, 3, 4] --- 10 - -example {a b : Nat} {p : Nat → Nat → Nat → Prop} (h₁ : p a b b) (h₂ : b = a) - : p a a b := - Eq.subst (motive := fun x => p a x b) h₂ h₁ -``` -In the following examples, we illustrate the interaction between named and default arguments. - -```lean -def f (x : Nat) (y : Nat := 1) (w : Nat := 2) (z : Nat) := - x + y + w - z - -example (x z : Nat) : f (z := z) x = x + 1 + 2 - z := rfl - -example (x z : Nat) : f x (z := z) = x + 1 + 2 - z := rfl - -example (x y : Nat) : f x y = fun z => x + y + 2 - z := rfl - -example : f = (fun x z => x + 1 + 2 - z) := rfl - -example (x : Nat) : f x = fun z => x + 1 + 2 - z := rfl - -example (y : Nat) : f (y := 5) = fun x z => x + 5 + 2 - z := rfl - -def g {α} [Add α] (a : α) (b? : Option α := none) (c : α) : α := - match b? with - | none => a + c - | some b => a + b + c - -variable {α} [Add α] - -example : g = fun (a c : α) => a + c := rfl - -example (x : α) : g (c := x) = fun (a : α) => a + x := rfl - -example (x : α) : g (b? := some x) = fun (a c : α) => a + x + c := rfl - -example (x : α) : g x = fun (c : α) => x + c := rfl - -example (x y : α) : g x y = fun (c : α) => x + y + c := rfl -``` - -In Lean 4, we can use `..` to provide missing explicit arguments as `_`. -This feature combined with named arguments is useful for writing patterns. Here is an example: -```lean -inductive Term where - | var (name : String) - | num (val : Nat) - | add (fn : Term) (arg : Term) - | lambda (name : String) (type : Term) (body : Term) - -def getBinderName : Term → Option String - | Term.lambda (name := n) .. => some n - | _ => none - -def getBinderType : Term → Option Term - | Term.lambda (type := t) .. => some t - | _ => none -``` -Ellipsis are also useful when explicit argument can be automatically inferred by Lean, and we want -to avoid a sequence of `_`s. -```lean -example (f : Nat → Nat) (a b c : Nat) : f (a + b + c) = f (a + (b + c)) := - congrArg f (Nat.add_assoc ..) -``` - -In Lean 4, writing `f(x)` in place of `f x` is no longer allowed, you must use whitespace between the function and its arguments (e.g., `f (x)`). - -## Dependent function types - -Given `α : Type` and `β : α → Type`, `(x : α) → β x` denotes the type of functions `f` with the property that, -for each `a : α`, `f a` is an element of `β a`. In other words, the type of the value returned by `f` depends on its input. -We say `(x : α) → β x` is a dependent function type. In Lean 3, we write the dependent function type `(x : α) → β x` using -one of the following three equivalent notations: -`forall x : α, β x` or `∀ x : α, β x` or `Π x : α, β x`. -The first two were intended to be used for writing propositions, and the latter for writing code. -Although the notation `Π x : α, β x` has historical significance, we have removed it from Lean 4 because -it is awkward to use and often confuses new users. We can still write `forall x : α, β x` and `∀ x : α, β x`. - -```lean -#check forall (α : Type), α → α -#check ∀ (α : Type), α → α -#check ∀ α : Type, α → α -#check ∀ α, α → α -#check (α : Type) → α → α -#check {α : Type} → (a : Array α) → (i : Nat) → i < a.size → α -#check {α : Type} → [ToString α] → α → String -#check forall {α : Type} (a : Array α) (i : Nat), i < a.size → α -#check {α β : Type} → α → β → α × β -``` - -## The `meta` keyword - -In Lean 3, the keyword `meta` is used to mark definitions that can use primitives implemented in C/C++. -These metadefinitions can also call themselves recursively, relaxing the termination -restriction imposed by ordinary type theory. Metadefinitions may also use unsafe primitives such as -`eval_expr (α : Type u) [reflected α] : expr → tactic α`, or primitives that break referential transparency -`tactic.unsafe_run_io`. - -The keyword `meta` has been currently removed from Lean 4. However, we may re-introduce it in the future, -but with a much more limited purpose: marking meta code that should not be included in the executables produced by Lean. - -The keyword `constant` has been deleted in Lean 4, and `axiom` should be used instead. In Lean 4, the new command `opaque` is used to define an opaque definition. Here are two simple examples: -```lean -# namespace meta1 -opaque x : Nat := 1 --- The following example will not type check since `x` is opaque --- example : x = 1 := rfl - --- We can evaluate `x` -#eval x --- 1 - --- When no value is provided, the elaborator tries to build one automatically for us --- using the `Inhabited` type class -opaque y : Nat -# end meta1 -``` - -We can instruct Lean to use a foreign function as the implementation for any definition -using the attribute `@[extern "foreign_function"]`. It is the user's responsibility to ensure the -foreign implementation is correct. -However, a user mistake here will only impact the code generated by Lean, and -it will **not** compromise the logical soundness of the system. -That is, you cannot prove `False` using the `@[extern]` attribute. -We use `@[extern]` with definitions when we want to provide a reference implementation in Lean -that can be used for reasoning. When we write a definition such as -```lean -@[extern "lean_nat_add"] -def add : Nat → Nat → Nat - | a, Nat.zero => a - | a, Nat.succ b => Nat.succ (add a b) -``` -Lean assumes that the foreign function `lean_nat_add` implements the reference implementation above. - -The `unsafe` keyword allows us to define functions using unsafe features such as general recursion, -and arbitrary type casting. Regular (safe) functions cannot directly use `unsafe` ones since it would -compromise the logical soundness of the system. As in regular programming languages, programs written -using unsafe features may crash at runtime. Here are a few unsafe examples: -```lean -unsafe def unsound : False := - unsound - -#check @unsafeCast --- {α : Type _} → {β : Type _} → α → β - -unsafe def nat2String (x : Nat) : String := - unsafeCast x - --- The following definition doesn't type check because it is not marked as `unsafe` --- def nat2StringSafe (x : Nat) : String := --- unsafeCast x -``` - -The `unsafe` keyword is particularly useful when we want to take advantage of an implementation detail of the -Lean execution runtime. For example, we cannot prove in Lean that arrays have a maximum size, but -the runtime used to execute Lean programs guarantees that an array cannot have more than 2^64 (2^32) elements -in a 64-bit (32-bit) machine. We can take advantage of this fact to provide a more efficient implementation for -array functions. However, the efficient version would not be very useful if it can only be used in -unsafe code. Thus, Lean 4 provides the attribute `@[implemented_by functionName]`. The idea is to provide -an unsafe (and potentially more efficient) version of a safe definition or constant. The function `f` -at the attribute `@[implemented_by f]` is very similar to an extern/foreign function, -the key difference is that it is implemented in Lean itself. Again, the logical soundness of the system -cannot be compromised by using the attribute `implemented_by`, but if the implementation is incorrect your -program may crash at runtime. In the following example, we define `withPtrUnsafe a k h` which -executes `k` using the memory address where `a` is stored in memory. The argument `h` is proof -that `k` is a constant function. Then, we "seal" this unsafe implementation at `withPtr`. The proof `h` -ensures the reference implementation `k 0` is correct. For more information, see the article -"Sealing Pointer-Based Optimizations Behind Pure Functions". -```lean -unsafe -def withPtrUnsafe {α β : Type} (a : α) (k : USize → β) (h : ∀ u, k u = k 0) : β := - k (ptrAddrUnsafe a) - -@[implemented_by withPtrUnsafe] -def withPtr {α β : Type} (a : α) (k : USize → β) (h : ∀ u, k u = k 0) : β := - k 0 -``` - -General recursion is very useful in practice, and it would be impossible to implement Lean 4 without it. -The keyword `partial` implements a very simple and efficient approach for supporting general recursion. -Simplicity was key here because of the bootstrapping problem. That is, we had to implement Lean in Lean before -many of its features were implemented (e.g., the tactic framework or support for wellfounded recursion). -Another requirement for us was performance. Functions tagged with `partial` should be as efficient as the ones implemented in mainstream functional programming -languages such as OCaml. When the `partial` keyword is used, Lean generates an auxiliary `unsafe` definition that -uses general recursion, and then defines an opaque constant that is implemented by this auxiliary definition. -This is very simple, efficient, and is sufficient for users that want to use Lean as a regular programming language. -A `partial` definition cannot use unsafe features such as `unsafeCast` and `ptrAddrUnsafe`, and it can only be used to -implement types we already known to be inhabited. Finally, since we "seal" the auxiliary definition using an opaque -constant, we cannot reason about `partial` definitions. - -We are aware that proof assistants such as Isabelle provide a framework for defining partial functions that does not -prevent users from proving properties about them. This kind of framework can be implemented in Lean 4. Actually, -it can be implemented by users since Lean 4 is an extensible system. The developers current have no plans to implement -this kind of support for Lean 4. However, we remark that users can implement it using a function that traverses -the auxiliary unsafe definition generated by Lean, and produces a safe one using an approach similar to the one used in Isabelle. - -```lean -# namespace partial1 -partial def f (x : Nat) : IO Unit := do - IO.println x - if x < 100 then - f (x+1) - -#eval f 98 -# end partial1 -``` - -## Library changes - -These are changes to the library which may trip up Lean 3 users: - -- `List` is no longer a monad. - -## Style changes - -Coding style changes have also been made: - -- Term constants and variables are now `lowerCamelCase` rather than `snake_case` -- Type constants are now `UpperCamelCase`, eg `Nat`, `List`. Type variables are still lower case greek letters. Functors are still lower case latin `(m : Type → Type) [Monad m]`. -- When defining typeclasses, prefer not to use "has". Eg `ToString` or `Add` instead of `HasToString` or `HasAdd`. -- Prefer `return` to `pure` in monad expressions. -- Pipes `<|` are preferred to dollars `$` for function application. -- Declaration bodies should always be indented: - ```lean - inductive Hello where - | foo - | bar - - structure Point where - x : Nat - y : Nat - - def Point.addX : Point → Point → Nat := - fun { x := a, .. } { x := b, .. } => a + b - ``` -- In structures and typeclass definitions, prefer `where` to `:=` and don't surround fields with parentheses. (Shown in `Point` above) diff --git a/doc/lexical_structure.md b/doc/lexical_structure.md deleted file mode 100644 index 27857005ef..0000000000 --- a/doc/lexical_structure.md +++ /dev/null @@ -1,180 +0,0 @@ -Lexical Structure -================= - -This section describes the detailed lexical structure of the Lean -language. - -A Lean program consists of a stream of UTF-8 tokens where each token -is one of the following: - -``` - token: symbol | command | ident | string | raw_string | char | numeral | - : decimal | doc_comment | mod_doc_comment | field_notation -``` - -Tokens can be separated by the whitespace characters space, tab, line -feed, and carriage return, as well as comments. Single-line comments -start with ``--``, whereas multi-line comments are enclosed by ``/-`` -and ``-/`` and can be nested. - -Symbols and Commands -==================== - -.. *(TODO: list built-in symbols and command tokens?)* - -Symbols are static tokens that are used in term notations and -commands. They can be both keyword-like (e.g. the `have -` keyword) or use arbitrary Unicode characters. - -Command tokens are static tokens that prefix any top-level declaration -or action. They are usually keyword-like, with transitory commands -like `#print ` prefixed by the ``#`` character. The set -of built-in commands is listed in [Other Commands](./other_commands.md). - -Users can dynamically extend the sets of both symbols (via the -commands listed in [Quoted Symbols](#quoted-symbols) and command -tokens (via the `[user_command] ` attribute). - -.. _identifiers: - -Identifiers -=========== - -An *atomic identifier*, or *atomic name*, is (roughly) an alphanumeric -string that does not begin with a numeral. A (hierarchical) -*identifier*, or *name*, consists of one or more atomic names -separated by periods. - -Parts of atomic names can be escaped by enclosing them in pairs of French double quotes ``«»``. - -```lean - def Foo.«bar.baz» := 0 -- name parts ["Foo", "bar.baz"] -``` - -``` - ident: atomic_ident | ident "." atomic_ident - atomic_ident: atomic_ident_start atomic_ident_rest* - atomic_ident_start: letterlike | "_" | escaped_ident_part - letterlike: [a-zA-Z] | greek | coptic | letterlike_symbols - greek: <[α-ωΑ-Ωἀ-῾] except for [λΠΣ]> - coptic: [ϊ-ϻ] - letterlike_symbols: [℀-⅏] - escaped_ident_part: "«" [^«»\r\n\t]* "»" - atomic_ident_rest: atomic_ident_start | [0-9'ⁿ] | subscript - subscript: [₀-₉ₐ-ₜᵢ-ᵪⱼ] -``` - -String Literals -=============== - -String literals are enclosed by double quotes (``"``). They may contain line breaks, which are conserved in the string value. Backslash (`\`) is a special escape character which can be used to the following -special characters: -- `\\` represents an escaped backslash, so this escape causes one backslash to be included in the string. -- `\"` puts a double quote in the string. -- `\'` puts an apostrophe in the string. -- `\n` puts a new line character in the string. -- `\t` puts a tab character in the string. -- `\xHH` puts the character represented by the 2 digit hexadecimal into the string. For example -"this \x26 that" which become "this & that". Values above 0x80 will be interpreted according to the -[Unicode table](https://unicode-table.com/en/) so "\xA9 Copyright 2021" is "© Copyright 2021". -- `\uHHHH` puts the character represented by the 4 digit hexadecimal into the string, so the following -string "\u65e5\u672c" will become "日本" which means "Japan". -- `\` followed by a newline and then any amount of whitespace is a "gap" that is equivalent to the empty string, -useful for letting a string literal span across multiple lines. Gaps spanning multiple lines can be confusing, -so the parser raises an error if the trailing whitespace contains any newlines. - -So the complete syntax is: - -``` - string : '"' string_item '"' - string_item : string_char | char_escape | string_gap - string_char : [^"\\] - char_escape : "\" ("\" | '"' | "'" | "n" | "t" | "x" hex_char{2} | "u" hex_char{4}) - hex_char : [0-9a-fA-F] - string_gap : "\" newline whitespace* -``` - -Raw String Literals -=================== - -Raw string literals are string literals without any escape character processing. -They begin with `r##...#"` (with zero or more `#` characters) and end with `"#...##` (with the same number of `#` characters). -The contents of a raw string literal may contain `"##..#` so long as the number of `#` characters -is less than the number of `#` characters used to begin the raw string literal. - -``` - raw_string : raw_string_aux(0) | raw_string_aux(1) | raw_string_aux(2) | ... - raw_string_aux(n) : 'r' '#'{n} '"' raw_string_item '"' '#'{n} - raw_string_item(n) : raw_string_char | raw_string_quote(n) - raw_string_char : [^"] - raw_string_quote(n) : '"' '#'{0..n-1} -``` - -Char Literals -============= - -Char literals are enclosed by single quotes (``'``). - -``` - char : "'" char_item "'" - char_item : char_char | char_escape - char_char : [^'\\] -``` - -Numeric Literals -================ - -Numeric literals can be specified in various bases. - -``` - numeral : numeral10 | numeral2 | numeral8 | numeral16 - numeral10 : [0-9]+ ("_"+ [0-9]+)* - numeral2 : "0" [bB] ("_"* [0-1]+)+ - numeral8 : "0" [oO] ("_"* [0-7]+)+ - numeral16 : "0" [xX] ("_"* hex_char+)+ -``` - -Floating point literals are also possible with optional exponent: - -``` - float : numeral10 "." numeral10? [eE[+-]numeral10] -``` - -For example: - -``` -constant w : Int := 55 -constant x : Nat := 26085 -constant y : Nat := 0x65E5 -constant z : Float := 2.548123e-05 -constant b : Bool := 0b_11_01_10_00 -``` - -Note: that negative numbers are created by applying the "-" negation prefix operator to the number, for example: - -``` -constant w : Int := -55 -``` - -Doc Comments -============ - -A special form of comments, doc comments are used to document modules -and declarations. - -``` - doc_comment: "/--" ([^-] | "-" [^/])* "-/" - mod_doc_comment: "/-!" ([^-] | "-" [^/])* "-/" -``` - -Field Notation -============== - -Trailing field notation tokens are used in expressions such as -``(1+1).to_string``. Note that ``a.toString`` is a single -[Identifier](#identifiers), but may be interpreted as a field -notation expression by the parser. - -``` - field_notation: "." ([0-9]+ | atomic_ident) -``` diff --git a/doc/metaprogramming-arith.md b/doc/metaprogramming-arith.md deleted file mode 100644 index 0308e07b4f..0000000000 --- a/doc/metaprogramming-arith.md +++ /dev/null @@ -1,134 +0,0 @@ -# Arithmetic as an embedded domain-specific language - -Let's parse another classic grammar, the grammar of arithmetic expressions with -addition, multiplication, integers, and variables. In the process, we'll learn -how to: - -- Convert identifiers such as `x` into strings within a macro. -- add the ability to "escape" the macro context from within the macro. This is useful to interpret identifiers with their _original_ meaning (predefined values) - instead of their new meaning within a macro (treat as a symbol). - -Let's begin with the simplest thing possible. We'll define an AST, and use operators `+` and `*` to denote -building an arithmetic AST. - - -Here's the AST that we will be parsing: - -```lean,ignore -{{#include metaprogramming-arith.lean:1:5}} -``` - -We declare a syntax category to describe the grammar that we will be parsing. -See that we control the precedence of `+` and `*` by writing `syntax:50` for addition and `syntax:60` for multiplication, -indicating that multiplication binds tighter than addition (higher the number, tighter the binding). -This allows us to declare _precedence_ when defining new syntax. - -```lean,ignore -{{#include metaprogramming-arith.lean:7:13}} -``` - -Further, if we look at `syntax:60 arith:60 "+" arith:61 : arith`, the -precedence declarations at `arith:60 "+" arith:61` conveys that the left -argument must have precedence at least `60` or greater, and the right argument -must have precedence at least`61` or greater. Note that this forces left -associativity. To understand this, let's compare two hypothetical parses: - -``` --- syntax:60 arith:60 "+" arith:61 : arith -- Arith.add --- a + b + c -(a:60 + b:61):60 + c -a + (b:60 + c:61):60 -``` - -In the parse tree of `a + (b:60 + c:61):60`, we see that the right argument `(b + c)` is given the precedence `60`. However, -the rule for addition expects the right argument to have a precedence of **at least** 61, as witnessed by the `arith:61` at -the right-hand-side of `syntax:60 arith:60 "+" arith:61 : arith`. Thus, the rule `syntax:60 arith:60 "+" arith:61 : arith` -ensures that addition is left associative. - -Since addition is declared arguments of precedence `60/61` and multiplication with `70/71`, this causes multiplication to bind -tighter than addition. Once again, let's compare two hypothetical parses: - -``` --- syntax:60 arith:60 "+" arith:61 : arith -- Arith.add --- syntax:70 arith:70 "*" arith:71 : arith -- Arith.mul --- a * b + c -a * (b:60 + c:61):60 -(a:70 * b:71):70 + c -``` - -While parsing `a * (b + c)`, `(b + c)` is assigned a precedence `60` by the addition rule. However, multiplication expects -the right argument to have precedence **at least** 71. Thus, this parse is invalid. In contrast, `(a * b) + c` assigns -a precedence of `70` to `(a * b)`. This is compatible with addition which expects the left argument to have precedence -**at least `60` ** (`70` is greater than `60`). Thus, the string `a * b + c` is parsed as `(a * b) + c`. -For more details, please look at the [Lean manual on syntax extensions](./notation.md#notations-and-precedence). - -To go from strings into `Arith`, we define a macro to -translate the syntax category `arith` into an `Arith` inductive value that -lives in `term`: - - -```lean,ignore -{{#include metaprogramming-arith.lean:15:16}} -``` - -Our macro rules perform the "obvious" translation: - -```lean,ignore -{{#include metaprogramming-arith.lean:18:23}} -``` - -And some examples: - -```lean,ignore -{{#include metaprogramming-arith.lean:25:41}} -``` - -Writing variables as strings, such as `"x"` gets old; wouldn't it be so much -prettier if we could write `x * y`, and have the macro translate this into `Arith.mul (Arith.Symbol "x") (Arith.mul "y")`? -We can do this, and this will be our first taste of manipulating macro variables --- we'll use `x.getId` instead of directly evaluating `$x`. -We also write a macro rule for `Arith|` that translates an identifier into -a string, using `$(Lean.quote (toString x.getId))`: - -```lean,ignore -{{#include metaprogramming-arith.lean:43:46}} -``` - -Let's test and see that we can now write expressions such as `x * y` directly instead of having to write `"x" * "y"`: - -```lean,ignore -{{#include metaprogramming-arith.lean:48:51}} -``` - -We now show an unfortunate consequence of the above definitions. Suppose we want to build `(x + y) + z`. -Since we already have defined `xPlusY` as `x + y`, perhaps we should reuse it! Let's try: - -```lean,ignore -#check `[Arith| xPlusY + z] -- Arith.add (Arith.symbol "xPlusY") (Arith.symbol "z") -``` - -Whoops, that didn't work! What happened? Lean treats `xPlusY` _itself_ as an identifier! So we need to add some syntax -to be able to "escape" the `Arith|` context. Let's use the syntax `<[ $e:term ]>` to mean: evaluate `$e` as a real term, -not an identifier. The macro looks like follows: - -```lean,ignore -{{#include metaprogramming-arith.lean:53:56}} -``` - -Let's try our previous example: - -```lean,ignore -{{#include metaprogramming-arith.lean:58:58}} -``` - -Perfect! - -In this tutorial, we expanded on the previous tutorial to parse a more -realistic grammar with multiple levels of precedence, how to parse identifiers directly -within a macro, and how to provide an escape from within the macro context. - -#### Full code listing - -```lean -{{#include metaprogramming-arith.lean}} -``` - diff --git a/doc/mission.md b/doc/mission.md deleted file mode 100644 index 0cc211aabd..0000000000 --- a/doc/mission.md +++ /dev/null @@ -1,12 +0,0 @@ -Mission -======= - -Empower software developers to design, develop, and reason about programs. -Empower mathematicians and scientists to design, develop, and reason about formal models. - -How ---- - -Lean is an efficient functional programming language based on dependent type theory. -It is under heavy development, but it already generates very efficient code. -It also has a powerful meta-programming framework, extensible parser, and IDE support based on LSP. diff --git a/doc/other_commands.md b/doc/other_commands.md deleted file mode 100644 index 09f25de218..0000000000 --- a/doc/other_commands.md +++ /dev/null @@ -1 +0,0 @@ -# Other Commands \ No newline at end of file diff --git a/doc/pygments.css b/doc/pygments.css deleted file mode 100644 index 9bdcad69c3..0000000000 --- a/doc/pygments.css +++ /dev/null @@ -1,83 +0,0 @@ -/* Pygments stylesheet generated by Alectryon (style=None) */ -td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } -span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } -td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } -span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } -.highlight .hll, .code .hll { background-color: #ffffcc } -.highlight .c, .code .c { color: #555753; font-style: italic } /* Comment */ -.highlight .err, .code .err { color: #a40000; border: 1px solid #cc0000 } /* Error */ -.highlight .g, .code .g { color: #000000 } /* Generic */ -.highlight .k, .code .k { color: #8f5902 } /* Keyword */ -.highlight .l, .code .l { color: #2e3436 } /* Literal */ -.highlight .n, .code .n { color: #000000 } /* Name */ -.highlight .o, .code .o { color: #000000 } /* Operator */ -.highlight .x, .code .x { color: #2e3436 } /* Other */ -.highlight .p, .code .p { color: #000000 } /* Punctuation */ -.highlight .ch, .code .ch { color: #555753; font-weight: bold; font-style: italic } /* Comment.Hashbang */ -.highlight .cm, .code .cm { color: #555753; font-style: italic } /* Comment.Multiline */ -.highlight .cp, .code .cp { color: #3465a4; font-style: italic } /* Comment.Preproc */ -.highlight .cpf, .code .cpf { color: #555753; font-style: italic } /* Comment.PreprocFile */ -.highlight .c1, .code .c1 { color: #555753; font-style: italic } /* Comment.Single */ -.highlight .cs, .code .cs { color: #3465a4; font-weight: bold; font-style: italic } /* Comment.Special */ -.highlight .gd, .code .gd { color: #a40000 } /* Generic.Deleted */ -.highlight .ge, .code .ge { color: #000000; font-style: italic } /* Generic.Emph */ -.highlight .gr, .code .gr { color: #a40000 } /* Generic.Error */ -.highlight .gh, .code .gh { color: #a40000; font-weight: bold } /* Generic.Heading */ -.highlight .gi, .code .gi { color: #4e9a06 } /* Generic.Inserted */ -.highlight .go, .code .go { color: #000000; font-style: italic } /* Generic.Output */ -.highlight .gp, .code .gp { color: #8f5902 } /* Generic.Prompt */ -.highlight .gs, .code .gs { color: #000000; font-weight: bold } /* Generic.Strong */ -.highlight .gu, .code .gu { color: #000000; font-weight: bold } /* Generic.Subheading */ -.highlight .gt, .code .gt { color: #000000; font-style: italic } /* Generic.Traceback */ -.highlight .kc, .code .kc { color: #204a87; font-weight: bold } /* Keyword.Constant */ -.highlight .kd, .code .kd { color: #4e9a06; font-weight: bold } /* Keyword.Declaration */ -.highlight .kn, .code .kn { color: #4e9a06; font-weight: bold } /* Keyword.Namespace */ -.highlight .kp, .code .kp { color: #204a87 } /* Keyword.Pseudo */ -.highlight .kr, .code .kr { color: #8f5902 } /* Keyword.Reserved */ -.highlight .kt, .code .kt { color: #204a87 } /* Keyword.Type */ -.highlight .ld, .code .ld { color: #2e3436 } /* Literal.Date */ -.highlight .m, .code .m { color: #2e3436 } /* Literal.Number */ -.highlight .s, .code .s { color: #ad7fa8 } /* Literal.String */ -.highlight .na, .code .na { color: #c4a000 } /* Name.Attribute */ -.highlight .nb, .code .nb { color: #75507b } /* Name.Builtin */ -.highlight .nc, .code .nc { color: #204a87 } /* Name.Class */ -.highlight .no, .code .no { color: #ce5c00 } /* Name.Constant */ -.highlight .nd, .code .nd { color: #3465a4; font-weight: bold } /* Name.Decorator */ -.highlight .ni, .code .ni { color: #c4a000; text-decoration: underline } /* Name.Entity */ -.highlight .ne, .code .ne { color: #cc0000 } /* Name.Exception */ -.highlight .nf, .code .nf { color: #a40000 } /* Name.Function */ -.highlight .nl, .code .nl { color: #3465a4; font-weight: bold } /* Name.Label */ -.highlight .nn, .code .nn { color: #000000 } /* Name.Namespace */ -.highlight .nx, .code .nx { color: #000000 } /* Name.Other */ -.highlight .py, .code .py { color: #000000 } /* Name.Property */ -.highlight .nt, .code .nt { color: #a40000 } /* Name.Tag */ -.highlight .nv, .code .nv { color: #ce5c00 } /* Name.Variable */ -.highlight .ow, .code .ow { color: #8f5902 } /* Operator.Word */ -.highlight .w, .code .w { color: #d3d7cf; text-decoration: underline } /* Text.Whitespace */ -.highlight .mb, .code .mb { color: #2e3436 } /* Literal.Number.Bin */ -.highlight .mf, .code .mf { color: #2e3436 } /* Literal.Number.Float */ -.highlight .mh, .code .mh { color: #2e3436 } /* Literal.Number.Hex */ -.highlight .mi, .code .mi { color: #2e3436 } /* Literal.Number.Integer */ -.highlight .mo, .code .mo { color: #2e3436 } /* Literal.Number.Oct */ -.highlight .sa, .code .sa { color: #ad7fa8 } /* Literal.String.Affix */ -.highlight .sb, .code .sb { color: #ad7fa8 } /* Literal.String.Backtick */ -.highlight .sc, .code .sc { color: #ad7fa8; font-weight: bold } /* Literal.String.Char */ -.highlight .dl, .code .dl { color: #ad7fa8 } /* Literal.String.Delimiter */ -.highlight .sd, .code .sd { color: #ad7fa8 } /* Literal.String.Doc */ -.highlight .s2, .code .s2 { color: #ad7fa8 } /* Literal.String.Double */ -.highlight .se, .code .se { color: #ad7fa8; font-weight: bold } /* Literal.String.Escape */ -.highlight .sh, .code .sh { color: #ad7fa8; text-decoration: underline } /* Literal.String.Heredoc */ -.highlight .si, .code .si { color: #ce5c00 } /* Literal.String.Interpol */ -.highlight .sx, .code .sx { color: #ad7fa8 } /* Literal.String.Other */ -.highlight .sr, .code .sr { color: #ad7fa8 } /* Literal.String.Regex */ -.highlight .s1, .code .s1 { color: #ad7fa8 } /* Literal.String.Single */ -.highlight .ss, .code .ss { color: #8f5902 } /* Literal.String.Symbol */ -.highlight .bp, .code .bp { color: #5c35cc } /* Name.Builtin.Pseudo */ -.highlight .fm, .code .fm { color: #a40000 } /* Name.Function.Magic */ -.highlight .vc, .code .vc { color: #ce5c00 } /* Name.Variable.Class */ -.highlight .vg, .code .vg { color: #ce5c00; text-decoration: underline } /* Name.Variable.Global */ -.highlight .vi, .code .vi { color: #ce5c00 } /* Name.Variable.Instance */ -.highlight .vm, .code .vm { color: #ce5c00 } /* Name.Variable.Magic */ -.highlight .il, .code .il { color: #2e3436 } /* Literal.Number.Integer.Long */ -.hljs-doctag { color: green } -.hljs-comment { color: green } \ No newline at end of file diff --git a/doc/quickstart.md b/doc/quickstart.md deleted file mode 100644 index afe06a296d..0000000000 --- a/doc/quickstart.md +++ /dev/null @@ -1,23 +0,0 @@ -# Quickstart - -These instructions will walk you through setting up Lean 4 together with VS Code as an editor for Lean 4. -See [Setup](./setup.md) for supported platforms and other ways to set up Lean 4. - -1. Install [VS Code](https://code.visualstudio.com/). - -1. Launch VS Code and install the `Lean 4` extension by clicking on the 'Extensions' sidebar entry and searching for 'Lean 4'. - - ![installing the vscode-lean4 extension](images/code-ext.png) - -1. Open the Lean 4 setup guide by creating a new text file using 'File > New Text File' (`Ctrl+N` / `Cmd+N`), clicking on the ∀-symbol in the top right and selecting 'Documentation… > Docs: Show Setup Guide'. - - ![show setup guide](images/show-setup-guide.png) - -1. Follow the Lean 4 setup guide. It will: - - - walk you through learning resources for Lean, - - teach you how to set up Lean's dependencies on your platform, - - install Lean 4 for you at the click of a button, - - help you set up your first project. - - ![setup guide](images/setup_guide.png) diff --git a/doc/reference.md b/doc/reference.md deleted file mode 100644 index dc6ada0f71..0000000000 --- a/doc/reference.md +++ /dev/null @@ -1,3 +0,0 @@ -# The Lean Reference Manual - -The latest version of the Lean reference manual is available [here](https://lean-lang.org/doc/reference/latest). diff --git a/doc/semantic_highlighting.md b/doc/semantic_highlighting.md deleted file mode 100644 index 10807630b9..0000000000 --- a/doc/semantic_highlighting.md +++ /dev/null @@ -1,23 +0,0 @@ -Semantic Highlighting ---------------------- - -The Lean language server provides semantic highlighting information to editors. In order to benefit from this in VSCode, you may need to activate the "Editor > Semantic Highlighting" option in the preferences (this is translates to `"editor.semanticHighlighting.enabled": true,` -in `settings.json`). The default option here is to let your color theme decides whether it activates semantic highlighting (the default themes Dark+ and Light+ do activate it for instance). - -However this may be insufficient if your color theme does not distinguish enough syntax categories or distinguishes them very subtly. For instance the default Light+ theme uses color `#001080` for variables. This is awfully close to `#000000` that is used as the default text color. This makes it very easy to miss an accidental use of [auto bound implicit arguments](https://lean-lang.org/lean4/doc/autobound.html). For instance in -```lean -def my_id (n : nat) := n -``` -maybe `nat` is a typo and `Nat` was intended. If your color theme is good enough then you should see that `n` and `nat` have the same color since they are both marked as variables by semantic highlighting. If you rather write `(n : Nat)` then `n` keeps its variable color but `Nat` gets the default text color. - -If you use such a bad theme, you can fix things by modifying the `Semantic Token Color Customizations` configuration. This cannot be done directly in the preferences dialog but you can click on "Edit in settings.json" to directly edit the settings file. Beware that you must save this file (in the same way you save any file opened in VSCode) before seeing any effect in other tabs or VSCode windows. - -In the main config object, you can add something like -``` -"editor.semanticTokenColorCustomizations": { - "[Default Light+]": {"rules": {"function": "#ff0000", "property": "#00ff00", "variable": "#ff00ff"}} - }, -``` -The colors in this example are not meant to be nice but to be easy to spot in your file when testing. Of course you need to replace `Default Light+` with the name of your theme, and you can customize several themes if you use several themes. VSCode will display small colored boxes next to the HTML color specifications. Hovering on top of a color specification opens a convenient color picker dialog. - -In order to understand what `function`, `property` and `variable` mean in the above example, the easiest path is to open a Lean file and ask VSCode about its classification of various bits of your file. Open the command palette with Ctrl-shift-p (or ⌘-shift-p on a Mac) and search for "Inspect Editor Tokens and Scopes" (typing the word "tokens" should be enough to see it). You can then click on any word in your file and look if there is a "semantic token type" line in the displayed information. diff --git a/doc/setup.md b/doc/setup.md deleted file mode 100644 index ee04953adf..0000000000 --- a/doc/setup.md +++ /dev/null @@ -1,65 +0,0 @@ -# Supported Platforms - -### Tier 1 - -Platforms built & tested by our CI, available as binary releases via elan (see below) - -* x86-64 Linux with glibc 2.26+ -* x86-64 macOS 10.15+ -* aarch64 (Apple Silicon) macOS 10.15+ -* x86-64 Windows 11 (any version), Windows 10 (version 1903 or higher), Windows Server 2022, Windows Server 2025 - -### Tier 2 - -Platforms cross-compiled but not tested by our CI, available as binary releases - -Releases may be silently broken due to the lack of automated testing. -Issue reports and fixes are welcome. - -* aarch64 Linux with glibc 2.27+ -* x86 (32-bit) Linux -* Emscripten Web Assembly - - - -# Setting Up Lean - -See also the [quickstart](./quickstart.md) instructions for a standard setup with VS Code as the editor. - -Release builds for all supported platforms are available at . -Instead of downloading these and setting up the paths manually, however, it is recommended to use the Lean version manager [`elan`](https://github.com/leanprover/elan) instead: -```sh -$ elan self update # in case you haven't updated elan in a while -# download & activate latest Lean 4 stable release (https://github.com/leanprover/lean4/releases) -$ elan default leanprover/lean4:stable -``` - -## `lake` - -Lean 4 comes with a package manager named `lake`. -Use `lake init foo` to initialize a Lean package `foo` in the current directory, and `lake build` to typecheck and build it as well as all its dependencies. Use `lake help` to learn about further commands. -The general directory structure of a package `foo` is -```sh -lakefile.lean # package configuration -lean-toolchain # specifies the lean version to use -Foo.lean # main file, import via `import Foo` -Foo/ - A.lean # further files, import via e.g. `import Foo.A` - A/... # further nesting -.lake/ # `lake` build output directory -``` - -After running `lake build` you will see a binary named `./.lake/build/bin/foo` and when you run it you should see the output: -``` -Hello, world! -``` - -## Editing - -Lean implements the [Language Server Protocol](https://microsoft.github.io/language-server-protocol/) that can be used for interactive development in [Emacs](https://github.com/leanprover/lean4-mode), [VS Code](https://github.com/leanprover-community/vscode-lean4), and possibly other editors. - -Changes must be saved to be visible in other files, which must then be invalidated using an editor command (see links above). diff --git a/doc/simptypes.md b/doc/simptypes.md deleted file mode 100644 index e73a3a2e8e..0000000000 --- a/doc/simptypes.md +++ /dev/null @@ -1,91 +0,0 @@ -## Simple Type Theory - -"Type theory" gets its name from the fact that every expression has an associated *type*. -For example, in a given context, ``x + 0`` may denote a natural number and ``f`` may denote a function on the natural numbers. -For those that don't like math, a Lean natural number is an arbitrary-precision unsigned integer. - -Here are some examples of how we can declare objects in Lean and check their types. - -```lean -/- Declare some constants. -/ - -constant m : Nat -- m is a natural number -constant n : Nat -constant b1 : Bool -- b1 is a Boolean -constant b2 : Bool - -/- Check their types. -/ - -#check m -- output: Nat -#check n -#check n + 0 -- Nat -#check m * (n + 0) -- Nat -#check b1 -- Bool -#check b1 && b2 -- "&&" is the Boolean and -#check b1 || b2 -- Boolean or -#check true -- Boolean "true" -``` - -Any text between ``/-`` and ``-/`` constitutes a comment block that is ignored by Lean. -Similarly, two dashes `--` indicate that the rest of the line contains a comment that is also ignored. -Comment blocks can be nested, making it possible to "comment out" chunks of code, just as in many programming languages. - -The ``constant`` command introduce new constant symbols into the working environment. -The ``#check`` command asks Lean to report their types; in Lean, auxiliary commands that query the system for -information typically begin with the hash symbol. You should try declaring some constants and type checking -some expressions on your own. Declaring new objects in this way is a good way to experiment with the system. - -What makes simple type theory powerful is that one can build new types out of others. -For example, if ``a`` and ``b`` are types, ``a -> b`` denotes the type of functions from ``a`` to ``b``, -and ``a × b`` denotes the type of pairs consisting of an element of ``a`` -paired with an element of ``b``, also known as the *Cartesian product*. -Note that `×` is a Unicode symbol. We believe that judicious use of Unicode improves legibility, -and all modern editors have great support for it. In the Lean standard library, we often use -Greek letters to denote types, and the Unicode symbol `→` as a more compact version of `->`. - -```lean -constant m : Nat -constant n : Nat - -constant f : Nat → Nat -- type the arrow as "\to" or "\r" -constant f' : Nat -> Nat -- alternative ASCII notation -constant p : Nat × Nat -- type the product as "\times" -constant q : Prod Nat Nat -- alternative notation -constant g : Nat → Nat → Nat -constant g' : Nat → (Nat → Nat) -- has the same type as g! -constant h : Nat × Nat → Nat -constant F : (Nat → Nat) → Nat -- a "functional" - -#check f -- Nat → Nat -#check f n -- Nat -#check g m n -- Nat -#check g m -- Nat → Nat -#check (m, n) -- Nat × Nat -#check p.1 -- Nat -#check p.2 -- Nat -#check (m, n).1 -- Nat -#check (p.1, n) -- Nat × Nat -#check F f -- Nat -``` - -Once again, you should try some examples on your own. - -Let us dispense with some basic syntax. You can enter the unicode arrow ``→`` by typing ``\to`` or ``\r``. -You can also use the ASCII alternative ``->``, so the expressions ``Nat -> Nat`` and ``Nat → Nat`` mean the same thing. -Both expressions denote the type of functions that take a natural number as input and return a natural number as output. -The unicode symbol ``×`` for the Cartesian product is entered as ``\times``. -We will generally use lower-case Greek letters like ``α``, ``β``, and ``γ`` to range over types. -You can enter these particular ones with ``\a``, ``\b``, and ``\g``. - -There are a few more things to notice here. First, the application of a function ``f`` to a value ``x`` is denoted ``f x``. -Second, when writing type expressions, arrows associate to the *right*; for example, the type of ``g`` is ``Nat → (Nat → Nat)``. -Thus we can view ``g`` as a function that takes natural numbers and returns another function that takes a natural number and -returns a natural number. -In type theory, this is generally more convenient than writing ``g`` as a function that takes a pair of natural numbers as input -and returns a natural number as output. For example, it allows us to "partially apply" the function ``g``. -The example above shows that ``g m`` has type ``Nat → Nat``, that is, the function that "waits" for a second argument, ``n``, -and then returns ``g m n``. Taking a function ``h`` of type ``Nat × Nat → Nat`` and "redefining" it to look like ``g`` is a process -known as *currying*, something we will come back to below. - -By now you may also have guessed that, in Lean, ``(m, n)`` denotes the ordered pair of ``m`` and ``n``, -and if ``p`` is a pair, ``p.1`` and ``p.2`` denote the two projections. diff --git a/doc/std/README.md b/doc/std/README.md deleted file mode 100644 index 32a9006197..0000000000 --- a/doc/std/README.md +++ /dev/null @@ -1,9 +0,0 @@ -# The Lean standard library - -This directory contains development information about the Lean standard library. The user-facing documentation of the standard library -is part of the [Lean Language Reference](https://lean-lang.org/doc/reference/latest/). - -Here you will find -* the [standard library vision document](./vision.md), including the call for contributions, -* the [standard library style guide](./style.md), and -* the [standard library naming conventions](./naming.md). diff --git a/doc/std/naming-tree.svg b/doc/std/naming-tree.svg deleted file mode 100644 index bbdce36fe9..0000000000 --- a/doc/std/naming-tree.svg +++ /dev/null @@ -1,3 +0,0 @@ -->=[]?Option.some[]'mahmamaαStd.HashMap α βInhabited βLawfulHashable αEquivBEq αHashable αBEq α \ No newline at end of file diff --git a/doc/std/naming.md b/doc/std/naming.md deleted file mode 100644 index 032400c938..0000000000 --- a/doc/std/naming.md +++ /dev/null @@ -1,260 +0,0 @@ -# Standard library naming conventions - -The easiest way to access a result in the standard library is to correctly guess the name of the declaration (possibly with the help of identifier autocompletion). This is faster and has lower friction than more sophisticated search tools, so easily guessable names (which are still reasonably short) make Lean users more productive. - -The guide that follows contains very few hard rules, many heuristics and a selection of examples. It cannot and does not present a deterministic algorithm for choosing good names in all situations. It is intended as a living document that gets clarified and expanded as situations arise during code reviews for the standard library. If applying one of the suggestions in this guide leads to nonsensical results in a certain situation, it is -probably safe to ignore the suggestion (or even better, suggest a way to improve the suggestion). - -## Prelude - -Identifiers use a mix of `UpperCamelCase`, `lowerCamelCase` and `snake_case`, used for types, data, and theorems, respectively. - -Structure fields should be named such that the projections have the correct names. - -## Naming convention for types - -When defining a type, i.e., a (possibly 0-ary) function whose codomain is Sort u for some u, it should be named in UpperCamelCase. Examples include `List`, and `List.IsPrefix`. - -When defining a predicate, prefix the name by `Is`, like in `List.IsPrefix`. The `Is` prefix may be omitted if -* the resulting name would be ungrammatical, or -* the predicate depends on additional data in a way where the `Is` prefix would be confusing (like `List.Pairwise`), or -* the name is an adjective (like `Std.Time.Month.Ordinal.Valid`) - -## Namespaces and generalized projection notation - -Almost always, definitions and theorems relating to a type should be placed in a namespace with the same name as the type. For example, operations and theorems about lists should be placed in the `List` namespace, and operations and theorems about `Std.Time.PlainDate` should be placed in the `Std.Time.PlainDate` namespace. - -Declarations in the root namespace will be relatively rare. The most common type of declaration in the root namespace are declarations about data and properties exported by notation type classes, as long as they are not about a specific type implementing that type class. For example, we have - -```lean -theorem beq_iff_eq [BEq α] [LawfulBEq α] {a b : α} : a == b ↔ a = b := sorry -``` - -in the root namespace, but - -```lean -theorem List.cons_beq_cons [BEq α] {a b : α} {l₁ l₂ : List α} : - (a :: l₁ == b :: l₂) = (a == b && l₁ == l₂) := rfl -``` - -belongs in the `List` namespace. - -Subtleties arise when multiple namespaces are in play. Generally, place your theorem in the most specific namespace that appears in one of the hypotheses of the theorem. The following names are both correct according to this convention: - -```lean -theorem List.Sublist.reverse : l₁ <+ l₂ → l₁.reverse <+ l₂.reverse := sorry -theorem List.reverse_sublist : l₁.reverse <+ l₂.reverse ↔ l₁ <+ l₂ := sorry -``` - -Notice that the second theorem does not have a hypothesis of type `List.Sublist l` for some `l`, so the name `List.Sublist.reverse_iff` would be incorrect. - -The advantage of placing results in a namespace like `List.Sublist` is that it enables generalized projection notation, i.e., given `h : l₁ <+ l₂`, -one can write `h.reverse` to obtain a proof of `l₁.reverse <+ l₂.reverse`. Thinking about which dot notations are convenient can act as a guideline -for deciding where to place a theorem, and is, on occasion, a good reason to duplicate a theorem into multiple namespaces. - -### The `Std` namespace - -New types that are added will usually be placed in the `Std` namespace and in the `Std/` source directory, unless there are good reasons to place -them elsewhere. - -Inside the `Std` namespace, all internal declarations should be `private` or else have a name component that clearly marks them as internal, preferably -`Internal`. - - -## Naming convention for data - -When defining data, i.e., a (possibly 0-ary) function whose codomain is not Sort u, but has type Type u for some u, it should be named in lowerCamelCase. Examples include `List.append` and `List.isPrefixOf`. -If your data is morally fully specified by its type, then use the naming procedure for theorems described below and convert the result to lower camel case. - -If your function returns an `Option`, consider adding `?` as a suffix. If your function may panic, consider adding `!` as a suffix. In many cases, there will be multiple variants of a function; one returning an option, one that may panic and possibly one that takes a proof argument. - -## Naming algorithm for theorems and some definitions - -There is, in principle, a general algorithm for naming a theorem. The problem with this algorithm is that it produces very long and unwieldy names which need to be shortened. So choosing a name for a declaration can be thought of as consisting of a mechanical part and a creative part. - -Usually the first part is to decide which namespace the result should live in, according to the guidelines described above. - -Next, consider the type of your declaration as a tree. Inner nodes of this tree are function types or function applications. Leaves of the tree are 0-ary functions or bound variables. - -As an example, consider the following result from the standard library: - -```lean -example {α : Type u} {β : Type v} [BEq α] [Hashable α] [EquivBEq α] [LawfulHashable α] - [Inhabited β] {m : Std.HashMap α β} {a : α} {h' : a ∈ m} : m[a]? = some (m[a]'h') := - sorry -``` - -The correct namespace is clearly `Std.HashMap`. The corresponding tree looks like this: - -![](naming-tree.svg) - -The preferred spelling of a notation can be looked up by hovering over the notation. - -Now traverse the tree and build a name according to the following rules: - -* When encountering a function type, first turn the result type into a name, then all of the argument types from left to right, and join the names using `_of_`. -* When encountering a function that is neither an infix notation nor a structure projection, first put the function name and then the arguments, joined by an underscore. -* When encountering an infix notation, join the arguments using the name of the notation, separated by underscores. -* When encountering a structure projection, proceed as for normal functions, but put the name of the projection last. -* When encountering a name, put it in lower camel case. -* Skip bound variables and proofs. -* Type class arguments are also generally skipped. - -When encountering namespaces names, concatenate them in lower camel case. - -Applying this algorithm to our example yields the name `Std.HashMap.getElem?_eq_optionSome_getElem_of_mem`. - -From there, the name should be shortened, using the following heuristics: - -* The namespace of functions can be omitted if it is clear from context or if the namespace is the current one. This is almost always the case. -* For infix operators, it is possible to leave out the RHS or the name of the notation and the RHS if they are clear from context. -* Hypotheses can be left out if it is clear that they are required or if they appear in the conclusion. - -Based on this, here are some possible names for our example: - -1. `Std.HashMap.getElem?_eq` -2. `Std.HashMap.getElem?_eq_of_mem` -3. `Std.HashMap.getElem?_eq_some` -4. `Std.HashMap.getElem?_eq_some_of_mem` -5. `Std.HashMap.getElem?_eq_some_getElem` -6. `Std.Hashmap.getElem?_eq_some_getElem_of_mem` - -Choosing a good name among these then requires considering the context of the lemma. In this case it turns out that the first four options are underspecified as there is also a lemma relating `m[a]?` and `m[a]!` which could have the same name. This leaves the last two options, the first of which is shorter, and this is how the lemma is called in the Lean standard library. - -Here are some additional examples: - -```lean -example {x y : List α} (h : x <+: y) (hx : x ≠ []) : - x.head hx = y.head (h.ne_nil hx) := sorry -``` - -Since we have an `IsPrefix` parameter, this should live in the `List.IsPrefix` namespace, and the algorithm suggests `List.IsPrefix.head_eq_head_of_ne_nil`, which is shortened to `List.IsPrefix.head`. Note here the difference between the namespace name (`IsPrefix`) and the recommended spelling of the corresponding notation (`prefix`). - -```lean -example : l₁ <+: l₂ → reverse l₁ <:+ reverse l₂ := sorry -``` - -Again, this result should be in the `List.IsPrefix` namespace; the algorithm suggests `List.IsPrefix.reverse_prefix_reverse`, which becomes `List.IsPrefix.reverse`. - -The following examples show how the traversal order often matters. - -```lean -theorem Nat.mul_zero (n : Nat) : n * 0 = 0 := sorry -theorem Nat.zero_mul (n : Nat) : 0 * n = 0 := sorry -``` - -Here we see that one name may be a prefix of another name: - -```lean -theorem Int.mul_ne_zero {a b : Int} (a0 : a ≠ 0) (b0 : b ≠ 0) : a * b ≠ 0 := sorry -theorem Int.mul_ne_zero_iff {a b : Int} : a * b ≠ 0 ↔ a ≠ 0 ∧ b ≠ 0 := sorry -``` - -It is usually a good idea to include the `iff` in a theorem name even if the name would still be unique without the name. For example, - -```lean -theorem List.head?_eq_none_iff : l.head? = none ↔ l = [] := sorry -``` - -is a good name: if the lemma was simply called `List.head?_eq_none`, users might try to `apply` it when the goal is `l.head? = none`, leading -to confusion. - -The more common you expect (or want) a theorem to be, the shorter you should try to make the name. For example, we have both - -```lean -theorem Std.HashMap.getElem?_eq_none_of_contains_eq_false {a : α} : m.contains a = false → m[a]? = none := sorry -theorem Std.HashMap.getElem?_eq_none {a : α} : ¬a ∈ m → m[a]? = none := sorry -``` - -As users of the hash map are encouraged to use ∈ rather than contains, the second lemma gets the shorter name. - -## Special cases - -There are certain special “keywords” that may appear in identifiers. - -| Keyword | Meaning | Example | -| :---- | :---- | :---- | -| `def` | Unfold a definition. Avoid this for public APIs. | `Nat.max_def` | -| `refl` | Theorems of the form `a R a`, where R is a reflexive relation and `a` is an explicit parameter | `Nat.le_refl` | -| `rfl` | Like `refl`, but with `a` implicit | `Nat.le_rfl` | -| `irrefl` | Theorems of the form `¬a R a`, where R is an irreflexive relation | `Nat.lt_irrefl` | -| `symm` | Theorems of the form `a R b → b R a`, where R is a symmetric relation (compare `comm` below) | `Eq.symm` | -| `trans` | Theorems of the form `a R b → b R c → a R c`, where R is a transitive relation (R may carry data) | `Eq.trans` | -| `antisymmm` | Theorems of the form `a R b → b R a → a = b`, where R is an antisymmetric relation | `Nat.le_antisymm` | -| `congr` | Theorems of the form `a R b → f a S f b`, where R and S are usually equivalence relations | `Std.HashMap.mem_congr` | -| `comm` | Theorems of the form `f a b = f b a` (compare `symm` above) | `Eq.comm`, `Nat.add_comm` | -| `assoc` | Theorems of the form `g (f a b) c = f a (g b c)` (note the order! In most cases, we have f = g) | `Nat.add_sub_assoc` | -| `distrib` | Theorems of the form `f (g a b) = g (f a) (f b)` | `Nat.add_left_distrib` | -| `self` | May be used if a variable appears multiple times in the conclusion | `List.mem_cons_self` | -| `inj` | Theorems of the form `f a = f b ↔ a = b`. | `Int.neg_inj`, `Nat.add_left_inj` | -| `cancel` | Theorems which have one of the forms `f a = f b → a = b` or `g (f a) = a`, where `f` and `g` usually involve a binary operator | `Nat.add_sub_cancel` | -| `cancel_iff` | Same as `inj`, but with different conventions for left and right (see below) | `Nat.add_right_cancel_iff` | -| `ext` | Theorems of the form `f a = f b → a = b`, where `f` usually involves some kind of projection | `List.ext_getElem` -| `mono` | Theorems of the form `a R b → f a R f b`, where `R` is a transitive relation | `List.countP_mono_left` - -### Left and right - -The keywords left and right are useful to disambiguate symmetric variants of theorems. - -```lean -theorem imp_congr_left (h : a ↔ b) : (a → c) ↔ (b → c) := sorry -theorem imp_congr_right (h : a → (b ↔ c)) : (a → b) ↔ (a → c) := sorry -``` - -It is not always obvious which version of a theorem should be “left” and which should be “right”. -Heuristically, the theorem should name the side which is “more variable”, but there are exceptions. For some of the special keywords discussed in this section, there are conventions which should be followed, as laid out in the following examples: - -```lean -theorem Nat.left_distrib (n m k : Nat) : n * (m + k) = n * m + n * k := sorry -theorem Nat.right_distrib (n m k : Nat) : (n + m) * k = n * k + m * k := sorry -theorem Nat.add_left_cancel {n m k : Nat} : n + m = n + k → m = k := sorry -theorem Nat.add_right_cancel {n m k : Nat} : n + m = k + m → n = k := sorry -theorem Nat.add_left_cancel_iff {m k n : Nat} : n + m = n + k ↔ m = k := sorry -theorem Nat.add_right_cancel_iff {m k n : Nat} : m + n = k + n ↔ m = k := sorry -theorem Nat.add_left_inj {m k n : Nat} : m + n = k + n ↔ m = k := sorry -theorem Nat.add_right_inj {m k n : Nat} : n + m = n + k ↔ m = k := sorry -``` - -Note in particular that the convention is opposite for `cancel_iff` and `inj`. - -```lean -theorem Nat.add_sub_self_left (a b : Nat) : (a + b) - a = b := sorry -theorem Nat.add_sub_self_right (a b : Nat) : (a + b) - b = a := sorry -theorem Nat.add_sub_cancel (n m : Nat) : (n + m) - m = n := sorry -``` - -## Primed names - -Avoid disambiguating variants of a concept by appending the `'` character (e.g., introducing both `BitVec.sshiftRight` and `BitVec.sshiftRight'`), as it is impossible to tell the difference without looking at the type signature, the documentation or even the code, and even if you know what the two variants are there is no way to tell which is which. Prefer descriptive pairs `BitVec.sshiftRightNat`/`BitVec.sshiftRight`. - -## Acronyms - -For acronyms which are three letters or shorter, all letters should use the same case as dictated by the convention. For example, `IO` is a correct name for a type and the name `IO.Ref` may become `IORef` when used as part of a definition name and `ioRef` when used as part of a theorem name. - -For acronyms which are at least four letters long, switch to lower case starting from the second letter. For example, `Json` is a correct name for a type, as is `JsonRPC`. - -If an acronym is typically spelled using mixed case, this mixed spelling may be used in identifiers (for example `Std.Net.IPv4Addr`). - -## Simp sets - -Simp sets centered around a conversion function should be called `source_to_target`. For example, a simp set for the `BitVec.toNat` function, which goes from `BitVec` to -`Nat`, should be called `bitvec_to_nat`. - -## Variable names - -We make the following recommendations for variable names, but without insisting on them: -* Simple hypotheses should be named `h`, `h'`, or using a numerical sequence `h₁`, `h₂`, etc. -* Another common name for a simple hypothesis is `w` (for "witness"). -* `List`s should be named `l`, `l'`, `l₁`, etc, or `as`, `bs`, etc. - (Use of `as`, `bs` is encouraged when the lists are of different types, e.g. `as : List α` and `bs : List β`.) - `xs`, `ys`, `zs` are allowed, but it is better if these are reserved for `Array` and `Vector`. - A list of lists may be named `L`. -* `Array`s should be named `xs`, `ys`, `zs`, although `as`, `bs` are encouraged when the arrays are of different types, e.g. `as : Array α` and `bs : Array β`. - An array of arrays may be named `xss`. -* `Vector`s should be named `xs`, `ys`, `zs`, although `as`, `bs` are encouraged when the vectors are of different types, e.g. `as : Vector α n` and `bs : Vector β n`. - A vector of vectors may be named `xss`. -* A common exception for `List` / `Array` / `Vector` is to use `acc` for an accumulator in a recursive function. -* `i`, `j`, `k` are preferred for numerical indices. - Descriptive names such as `start`, `stop`, `lo`, and `hi` are encouraged when they increase readability. -* `n`, `m` are preferred for sizes, e.g. in `Vector α n` or `xs.size = n`. -* `w` is preferred for the width of a `BitVec`. \ No newline at end of file diff --git a/doc/std/style.md b/doc/std/style.md deleted file mode 100644 index 334c9f1373..0000000000 --- a/doc/std/style.md +++ /dev/null @@ -1,522 +0,0 @@ -# Standard library style - -Please take some time to familiarize yourself with the stylistic conventions of -the project and the specific part of the library you are planning to contribute -to. While the Lean compiler may not enforce strict formatting rules, -consistently formatted code is much easier for others to read and maintain. -Attention to formatting is more than a cosmetic concern—it reflects the same -level of precision and care required to meet the deeper standards of the Lean 4 -standard library. - -Below we will give specific formatting prescriptions for various language constructs. Note that this style guide only applies to the Lean standard library, even though some examples in the guide are taken from other parts of the Lean code base. - -## Basic whitespace rules - -Syntactic elements (like `:`, `:=`, `|`, `::`) are surrounded by single spaces, with the exception of `,` and `;`, which are followed by a space but not preceded by one. Delimiters (like `()`, `{}`) do not have spaces on the inside, with the exceptions of subtype notation and structure instance notation. - -Examples of correctly formatted function parameters: - -* `{α : Type u}` -* `[BEq α]` -* `(cmp : α → α → Ordering)` -* `(hab : a = b)` -* `{d : { l : List ((n : Nat) × Vector Nat n) // l.length % 2 = 0 }}` - -Examples of correctly formatted terms: - -* `1 :: [2, 3]` -* `letI : Ord α := ⟨cmp⟩; True` -* `(⟨2, 3⟩ : Nat × Nat)` -* `((2, 3) : Nat × Nat)` -* `{ x with fst := f (4 + f 0), snd := 4, .. }` -* `match 1 with | 0 => 0 | _ => 0` -* `fun ⟨a, b⟩ _ _ => by cases hab <;> apply id; rw [hbc]` - -Configure your editor to remove trailing whitespace. If you have set up Visual Studio Code for Lean development in the recommended way then the correct setting is applied automatically. - -## Splitting terms across multiple lines - -When splitting a term across multiple lines, increase indentation by two spaces starting from the second line. When splitting a function application, try to split at argument boundaries. If an argument itself needs to be split, increase indentation further as appropriate. - -When splitting at an infix operator, the operator goes at the end of the first line, not at the beginning of the second line. When splitting at an infix operator, you may or may not increase indentation depth, depending on what is more readable. - -When splitting an `if`-`then`-`else` expression, the `then` keyword wants to stay with the condition and the `else` keyword wants to stay with the alternative term. Otherwise, indent as if the `if` and `else` keywords were arguments to the same function. - -When splitting a comma-separated bracketed sequence (i.e., anonymous constructor application, list/array/vector literal, tuple) it is allowed to indent subsequent lines for alignment, but indenting by two spaces is also allowed. - -Do not orphan parentheses. - -Correct: -```lean -def MacroScopesView.isPrefixOf (v₁ v₂ : MacroScopesView) : Bool := - v₁.name.isPrefixOf v₂.name && - v₁.scopes == v₂.scopes && - v₁.mainModule == v₂.mainModule && - v₁.imported == v₂.imported -``` - -Correct: -```lean -theorem eraseP_eq_iff {p} {l : List α} : - l.eraseP p = l' ↔ - ((∀ a ∈ l, ¬ p a) ∧ l = l') ∨ - ∃ a l₁ l₂, (∀ b ∈ l₁, ¬ p b) ∧ p a ∧ - l = l₁ ++ a :: l₂ ∧ l' = l₁ ++ l₂ := - sorry -``` - -Correct: -```lean -example : Nat := - functionWithAVeryLongNameSoThatSomeArgumentsWillNotFit firstArgument secondArgument - (firstArgumentWithAnEquallyLongNameAndThatFunctionDoesHaveMoreArguments firstArgument - secondArgument) - secondArgument -``` - -Correct: -```lean -theorem size_alter [LawfulBEq α] {k : α} {f : Option (β k) → Option (β k)} (h : m.WF) : - (m.alter k f).size = - if m.contains k && (f (m.get? k)).isNone then - m.size - 1 - else if !m.contains k && (f (m.get? k)).isSome then - m.size + 1 - else - m.size := by - simp_to_raw using Raw₀.size_alter -``` - -Correct: -```lean -theorem get?_alter [LawfulBEq α] {k k' : α} {f : Option (β k) → Option (β k)} (h : m.WF) : - (m.alter k f).get? k' = - if h : k == k' then - cast (congrArg (Option ∘ β) (eq_of_beq h)) (f (m.get? k)) - else m.get? k' := by - simp_to_raw using Raw₀.get?_alter -``` - -Correct: -```lean -example : Nat × Nat := - ⟨imagineThisWasALongTerm, - imagineThisWasAnotherLongTerm⟩ -``` - -Correct: -```lean -example : Nat × Nat := - ⟨imagineThisWasALongTerm, - imagineThisWasAnotherLongTerm⟩ -``` - -Correct: -```lean -example : Vector Nat := - #v[imagineThisWasALongTerm, - imagineThisWasAnotherLongTerm] -``` - -## Basic file structure - -Every file should start with a copyright header, imports (in the standard library, this always includes a `prelude` declaration) and a module documentation string. There should not be a blank line between the copyright header and the imports. There should be a blank line between the imports and the module documentation string. - -If you explicitly declare universe variables, do so at the top of the file, after the module documentation. - -Correct: -```lean -/- -Copyright (c) 2014 Parikshit Khanna. All rights reserved. -Released under Apache 2.0 license as described in the file LICENSE. -Authors: Parikshit Khanna, Jeremy Avigad, Leonardo de Moura, Floris van Doorn, Mario Carneiro, - Yury Kudryashov --/ -prelude -import Init.Data.List.Pairwise -import Init.Data.List.Find - -/-! -**# Lemmas about `List.eraseP` and `List.erase`.** --/ - -universe u u' -``` - -Syntax that is not supposed to be user-facing must be scoped. New public syntax must always be discussed explicitly in an RFC. - -## Top-level commands and declarations - -All top-level commands are unindented. Sectioning commands like `section` and `namespace` do not increase the indentation level. - -Attributes may be placed on the same line as the rest of the command or on a separate line. - -Multi-line declaration headers are indented by four spaces starting from the second line. The colon that indicates the type of a declaration may not be placed at the start of a line or on its own line. - -Declaration bodies are indented by two spaces. Short declaration bodies may be placed on the same line as the declaration type. - -Correct: -```lean -theorem eraseP_eq_iff {p} {l : List α} : - l.eraseP p = l' ↔ - ((∀ a ∈ l, ¬ p a) ∧ l = l') ∨ - ∃ a l₁ l₂, (∀ b ∈ l₁, ¬ p b) ∧ p a ∧ - l = l₁ ++ a :: l₂ ∧ l' = l₁ ++ l₂ := - sorry -``` - -Correct: -```lean -@[simp] theorem eraseP_nil : [].eraseP p = [] := rfl -``` - -Correct: -```lean -@[simp] -theorem eraseP_nil : [].eraseP p = [] := rfl -``` - -### Documentation comments - -Note to external contributors: this is a section where the Lean style and the mathlib style are different. - -Declarations should be documented as required by the `docBlame` linter, which may be activated in a file using -`set_option linter.missingDocs true` (we allow these to stay in the file). - -Single-line documentation comments should go on the same line as `/--`/`-/`, while multi-line documentation strings -should have these delimiters on their own line, with the documentation comment itself unindented. - -Documentation comments must be written in the indicative mood. Use American orthography. - -Correct: -```lean -/-- Carries out a monadic action on each mapping in the hash map in some order. -/ -@[inline] def forM (f : (a : α) → β a → m PUnit) (b : Raw α β) : m PUnit := - b.buckets.forM (AssocList.forM f) -``` - -Correct: -```lean -/-- -Monadically computes a value by folding the given function over the mappings in the hash -map in some order. --/ -@[inline] def foldM (f : δ → (a : α) → β a → m δ) (init : δ) (b : Raw α β) : m δ := - b.buckets.foldlM (fun acc l => l.foldlM f acc) init -``` - -### Where clauses - -The `where` keyword should be unindented, and all declarations bound by it should be indented with two spaces. - -Blank lines before and after `where` and between declarations bound by `where` are optional and should be chosen -to maximize readability. - -Correct: -```lean -@[simp] theorem partition_eq_filter_filter (p : α → Bool) (l : List α) : - partition p l = (filter p l, filter (not ∘ p) l) := by - simp [partition, aux] -where - aux (l) {as bs} : partition.loop p l (as, bs) = - (as.reverse ++ filter p l, bs.reverse ++ filter (not ∘ p) l) := - match l with - | [] => by simp [partition.loop, filter] - | a :: l => by cases pa : p a <;> simp [partition.loop, pa, aux, filter, append_assoc] -``` - -### Termination arguments - -The `termination_by`, `decreasing_by`, `partial_fixpoint` keywords should be unindented. The associated terms should be indented like declaration bodies. - -Correct: -```lean -@[inline] def multiShortOption (handle : Char → m PUnit) (opt : String) : m PUnit := do - let rec loop (p : String.Pos) := do - if h : opt.atEnd p then - return - else - handle (opt.get' p h) - loop (opt.next' p h) - termination_by opt.utf8ByteSize - p.byteIdx - decreasing_by - simp [String.atEnd] at h - apply Nat.sub_lt_sub_left h - simp [String.lt_next opt p] - loop ⟨1⟩ -``` - -Correct: -```lean -def substrEq (s1 : String) (off1 : String.Pos) (s2 : String) (off2 : String.Pos) (sz : Nat) : Bool := - off1.byteIdx + sz ≤ s1.endPos.byteIdx && off2.byteIdx + sz ≤ s2.endPos.byteIdx && loop off1 off2 { byteIdx := off1.byteIdx + sz } -where - loop (off1 off2 stop1 : Pos) := - if _h : off1.byteIdx < stop1.byteIdx then - let c₁ := s1.get off1 - let c₂ := s2.get off2 - c₁ == c₂ && loop (off1 + c₁) (off2 + c₂) stop1 - else true - termination_by stop1.1 - off1.1 - decreasing_by - have := Nat.sub_lt_sub_left _h (Nat.add_lt_add_left c₁.utf8Size_pos off1.1) - decreasing_tactic -``` - -Correct: -```lean -theorem div_add_mod (m n : Nat) : n * (m / n) + m % n = m := by - rw [div_eq, mod_eq] - have h : Decidable (0 < n ∧ n ≤ m) := inferInstance - cases h with - | isFalse h => simp [h] - | isTrue h => - simp [h] - have ih := div_add_mod (m - n) n - rw [Nat.left_distrib, Nat.mul_one, Nat.add_assoc, Nat.add_left_comm, ih, Nat.add_comm, Nat.sub_add_cancel h.2] -decreasing_by apply div_rec_lemma; assumption -``` - -### Deriving - -The `deriving` clause should be unindented. - -Correct: -```lean -structure Iterator where - array : ByteArray - idx : Nat -deriving Inhabited -``` - -## Notation and Unicode - -We generally prefer to use notation as available. We usually prefer the Unicode versions of notations over non-Unicode alternatives. - -There are some rules and exceptions regarding specific notations which are listed below: - -* Sigma types: use `(a : α) × β a` instead of `Σ a, β a` or `Sigma β`. -* Function arrows: use `fun a => f x` instead of `fun x ↦ f x` or `λ x => f x` or any other variant. - -## Language constructs - -### Pattern matching, induction etc. - -Match arms are indented at the indentation level that the match statement would have if it was on its own line. If the match is implicit, then the arms should be indented as if the match was explicitly given. The content of match arms is indented two spaces, so that it appears on the same level as the match pattern. - -Correct: -```lean -def alter [BEq α] {β : Type v} (a : α) (f : Option β → Option β) : - AssocList α (fun _ => β) → AssocList α (fun _ => β) - | nil => match f none with - | none => nil - | some b => AssocList.cons a b nil - | cons k v l => - if k == a then - match f v with - | none => l - | some b => cons a b l - else - cons k v (alter a f l) -``` - -Correct: -```lean -theorem eq_append_cons_of_mem {a : α} {xs : List α} (h : a ∈ xs) : - ∃ as bs, xs = as ++ a :: bs ∧ a ∉ as := by - induction xs with - | nil => cases h - | cons x xs ih => - simp at h - cases h with - | inl h => exact ⟨[], xs, by simp_all⟩ - | inr h => - by_cases h' : a = x - · subst h' - exact ⟨[], xs, by simp⟩ - · obtain ⟨as, bs, rfl, h⟩ := ih h - exact ⟨x :: as, bs, rfl, by simp_all⟩ -``` - -Aligning match arms is allowed, but not required. - -Correct: -```lean -def mkEqTrans? (h₁? h₂? : Option Expr) : MetaM (Option Expr) := - match h₁?, h₂? with - | none, none => return none - | none, some h => return h - | some h, none => return h - | some h₁, some h₂ => mkEqTrans h₁ h₂ -``` - -Correct: -```lean -def mkEqTrans? (h₁? h₂? : Option Expr) : MetaM (Option Expr) := - match h₁?, h₂? with - | none, none => return none - | none, some h => return h - | some h, none => return h - | some h₁, some h₂ => mkEqTrans h₁ h₂ -``` - -Correct: -```lean -def mkEqTrans? (h₁? h₂? : Option Expr) : MetaM (Option Expr) := - match h₁?, h₂? with - | none, none => return none - | none, some h => return h - | some h, none => return h - | some h₁, some h₂ => mkEqTrans h₁ h₂ -``` - -### Structures - -Note to external contributors: this is a section where the Lean style and the mathlib style are different. - -When using structure instance syntax over multiple lines, the opening brace should go on the preceding line, while the closing brace should go on its own line. The rest of the syntax should be indented by one level. During structure updates, the `with` clause goes on the same line as the opening brace. Aligning at the assignment symbol is allowed but not required. - -Correct: -```lean -def addConstAsync (env : Environment) (constName : Name) (kind : ConstantKind) (reportExts := true) : - IO AddConstAsyncResult := do - let sigPromise ← IO.Promise.new - let infoPromise ← IO.Promise.new - let extensionsPromise ← IO.Promise.new - let checkedEnvPromise ← IO.Promise.new - let asyncConst := { - constInfo := { - name := constName - kind - sig := sigPromise.result - constInfo := infoPromise.result - } - exts? := guard reportExts *> some extensionsPromise.result - } - return { - constName, kind - mainEnv := { env with - asyncConsts := env.asyncConsts.add asyncConst - checked := checkedEnvPromise.result } - asyncEnv := { env with - asyncCtx? := some { declPrefix := privateToUserName constName.eraseMacroScopes } - } - sigPromise, infoPromise, extensionsPromise, checkedEnvPromise - } -``` - -Correct: -```lean -instance [Inhabited α] : Inhabited (Descr α β σ) where - default := { - name := default - mkInitial := default - ofOLeanEntry := default - toOLeanEntry := default - addEntry := fun s _ => s - } -``` - -### Declaring structures - -When defining structure types, do not parenthesize structure fields. - -When declaring a structure type with a custom constructor name, put the custom name on its own line, indented like the -structure fields, and add a documentation comment. - -Correct: - -```lean -/-- -A bitvector of the specified width. - -This is represented as the underlying `Nat` number in both the runtime -and the kernel, inheriting all the special support for `Nat`. --/ -structure BitVec (w : Nat) where - /-- - Constructs a `BitVec w` from a number less than `2^w`. - O(1), because we use `Fin` as the internal representation of a bitvector. - -/ - ofFin :: - /-- - Interprets a bitvector as a number less than `2^w`. - O(1), because we use `Fin` as the internal representation of a bitvector. - -/ - toFin : Fin (2 ^ w) -``` - -## Tactic proofs - -Tactic proofs are the most common thing to break during any kind of upgrade, so it is important to write them in a way that minimizes the likelihood of proofs breaking and that makes it easy to debug breakages if they do occur. - -If there are multiple goals, either use a tactic combinator (like `all_goals`) to operate on all of them or a clearly specified subset, or use focus dots to work on goals one at a time. Using structured proofs (e.g., `induction … with`) is encouraged but not mandatory. - -Squeeze non-terminal `simp`s (i.e., calls to `simp` which do not close the goal). Squeezing terminal `simp`s is generally discouraged, although there are exceptions (for example if squeezing yields a noticeable performance improvement). - -Do not over-golf proofs in ways that are likely to lead to hard-to-debug breakage. Examples of things to avoid include complex multi-goal manipulation using lots of tactic combinators, complex uses of the substitution operator (`▸`) and clever point-free expressions (possibly involving anonymous function notation for multiple arguments). - -Do not under-golf proofs: for routine tasks, use the most powerful tactics available. - -Do not use `erw`. Avoid using `rfl` after `simp` or `rw`, as this usually indicates a missing lemma that should be used instead of `rfl`. - -Use `(d)simp` or `rw` instead of `delta` or `unfold`. Use `refine` instead of `refine’`. Use `haveI` and `letI` only if they are actually required. - -Prefer highly automated tactics (like `grind` and `omega`) over low-level proofs, unless the automated tactic requires unacceptable additional imports or has bad performance. If you decide against using a highly automated tactic, leave a comment explaining the decision. - -## `do` notation - -The `do` keyword goes on the same line as the corresponding `:=` (or `=>`, or similar). `Id.run do` should be treated as if it was a bare `do`. - -Use early `return` statements to reduce nesting depth and make the non-exceptional control flow of a function easier to see. - -Alternatives for `let` matches may be placed in the same line or in the next line, indented by two spaces. If the term that is -being matched on is itself more than one line and there is an alternative present, consider breaking immediately after `←` and indent -as far as necessary to ensure readability. - -Correct: -```lean -def getFunDecl (fvarId : FVarId) : CompilerM FunDecl := do - let some decl ← findFunDecl? fvarId | throwError "unknown local function {fvarId.name}" - return decl -``` - -Correct: -```lean -def getFunDecl (fvarId : FVarId) : CompilerM FunDecl := do - let some decl ← - findFunDecl? fvarId - | throwError "unknown local function {fvarId.name}" - return decl -``` - -Correct: -```lean -def getFunDecl (fvarId : FVarId) : CompilerM FunDecl := do - let some decl ← findFunDecl? - fvarId - | throwError "unknown local function {fvarId.name}" - return decl -``` - -Correct: -```lean -def tagUntaggedGoals (parentTag : Name) (newSuffix : Name) (newGoals : List MVarId) : TacticM Unit := do - let mctx ← getMCtx - let mut numAnonymous := 0 - for g in newGoals do - if mctx.isAnonymousMVar g then - numAnonymous := numAnonymous + 1 - modifyMCtx fun mctx => Id.run do - let mut mctx := mctx - let mut idx := 1 - for g in newGoals do - if mctx.isAnonymousMVar g then - if numAnonymous == 1 then - mctx := mctx.setMVarUserName g parentTag - else - mctx := mctx.setMVarUserName g (parentTag ++ newSuffix.appendIndexAfter idx) - idx := idx + 1 - pure mctx -``` - diff --git a/doc/std/vision.md b/doc/std/vision.md deleted file mode 100644 index f749b5693a..0000000000 --- a/doc/std/vision.md +++ /dev/null @@ -1,98 +0,0 @@ -# The Lean 4 standard library - -Maintainer team (in alphabetical order): Henrik Böving, Markus Himmel -(community contact & external contribution coordinator), Kim Morrison, Paul -Reichert, Sofia Rodrigues. - -The Lean 4 standard library is a core part of the Lean distribution, providing -essential building blocks for functional programming, verified software -development, and software verification. Unlike the standard libraries of most -other languages, many of its components are formally verified and can be used -as part of verified applications. - -The standard library is a public API that contains the components listed in the -standard library outline below. Not all public APIs in the Lean distribution -are part of the standard library, and the standard library does not correspond -to a certain directory within the Lean source repository (like `Std`). For -example, the metaprogramming framework is not part of the standard library, but -basic types like `True` and `Nat` are. - -The standard library is under active development. Our guiding principles are: - -* Provide comprehensive, verified building blocks for real-world software. -* Build a public API of the highest quality with excellent internal consistency. -* Carefully optimize components that may be used in performance-critical software. -* Ensure smooth adoption and maintenance for users. -* Offer excellent documentation, example projects, and guides. -* Provide a reliable and extensible basis that libraries for software - development, software verification and mathematics can build on. - -The standard library is principally developed by the Lean FRO. Community -contributions are welcome. If you would like to contribute, please refer to the -call for contributions below. - -### Standard library outline - -1. Core types and operations - 1. Basic types - 2. Numeric types, including floating point numbers - 3. Containers - 4. Strings and formatting -2. Language constructs - 1. Ranges and iterators - 2. Comparison, ordering, hashing and related type classes - 3. Basic monad infrastructure -3. Libraries - 1. Random numbers - 2. Dates and times -4. Operating system abstractions - 1. Concurrency and parallelism primitives - 2. Asynchronous I/O - 3. FFI helpers - 4. Environment, file system, processes - 5. Locales - -The material covered in the first three sections (core types and operations, -language constructs and libraries) will be verified, with the exception of -floating point numbers and the parts of the libraries that interface with the -operating system (e.g., sources of operating system randomness or time zone -database access). - -### Call for contributions - -Thank you for taking interest in contributing to the Lean standard library\! -There are two main ways for community members to contribute to the Lean -standard library: by contributing experience reports or by contributing code -and lemmas. - -**If you are using Lean for software verification or verified software -development:** hearing about your experiences using Lean and its standard -library for software verification is extremely valuable to us. We are committed -to building a standard library suitable for real-world applications and your -input will directly influence the continued evolution of the Lean standard -library. Please reach out to the standard library maintainer team via Zulip -(either in a public thread in the \#lean4 channel or via direct message). Even -just a link to your code helps. Thanks\! - -**If you have code that you believe could enhance the Lean 4 standard -library:** we encourage you to initiate a discussion in the \#lean4 channel on -Zulip. This is the most effective way to receive preliminary feedback on your -contribution. The Lean standard library has a very precise scope and it has -very high quality standards, so at the moment we are mostly interested in -contributions that expand upon existing material rather than introducing novel -concepts. - -**If you would like to contribute code to the standard library but don’t know -what to work on:** we are always excited to meet motivated community members -who would like to contribute, and there is always impactful work that is -suitable for new contributors. Please reach out to Markus Himmel on Zulip to -discuss possible contributions. - -As laid out in the [project-wide External Contribution -Guidelines](../../CONTRIBUTING.md), -PRs are much more likely to be merged if they are preceded by an RFC or if you -discussed your planned contribution with a member of the standard library -maintainer team. When in doubt, introducing yourself is always a good idea. - -All code in the standard library is expected to strictly adhere to the -[standard library coding conventions](./style.md). diff --git a/doc/syntax_example.md b/doc/syntax_example.md deleted file mode 100644 index 57c4935194..0000000000 --- a/doc/syntax_example.md +++ /dev/null @@ -1,80 +0,0 @@ -# Balanced Parentheses as an Embedded Domain Specific Language - -Let's look at how to use macros to extend the Lean 4 parser and embed a language for building _balanced parentheses_. -This language accepts strings given by the [BNF grammar](https://en.wikipedia.org/wiki/Backus%E2%80%93Naur_form) - -``` -Dyck ::= - "(" Dyck ")" - | "{" Dyck "}" - | end -``` - -We begin by defining an inductive data type of the grammar we wish to parse: - -```lean,ignore -inductive Dyck : Type where - | round : Dyck → Dyck -- ( ) - | curly : Dyck → Dyck -- { } - | leaf : Dyck -``` - -We begin by declaring a _syntax category_ using the `declare_syntax_cat ` command. -This names our grammar and allows us to specify parsing rules associated with our grammar. - -```lean,ignore -declare_syntax_cat brack -``` - -Next, we specify the grammar using the `syntax ` command: - -```lean,ignore -syntax "end" : brack -``` - -The above means that the token "end" lives in syntax category `brack`. - -Similarly, we declare the rules `"(" Dyck ")"` and `"{" Dyck "}"` using the rules: - -```lean,ignore -syntax "(" brack ")" : brack -syntax "{" brack "}" : brack -``` - -Finally, we need a way to build _Lean 4 terms_ from this grammar -- that is, we must translate out of this -grammar into a `Dyck` value, which is a Lean 4 term. For this, we create a new kind of "quotation" that -consumes syntax in `brack` and produces a `term`. - -```lean,ignore -syntax "`[Dyck| " brack "]" : term -``` - -To specify the transformation rules, we use `macro_rules` to declare how the syntax `` `[Dyck| ] `` -produces terms. This is written using a pattern-matching style syntax, where the left-hand side -declares the syntax pattern to be matched, and the right-hand side declares the production. Syntax placeholders (antiquotations) -are introduced via the `$` syntax. The right-hand side is -an arbitrary Lean term that we are producing. - -```lean,ignore -macro_rules - | `(`[Dyck| end]) => `(Dyck.leaf) - | `(`[Dyck| ($b)]) => `(Dyck.round `[Dyck| $b]) -- recurse - | `(`[Dyck| {$b}]) => `(Dyck.curly `[Dyck| $b]) -- recurse -``` - - -```lean,ignore -#check `[Dyck| end] -- Dyck.leaf -#check `[Dyck| {(end)}] -- Dyck.curl (Dyck.round Dyck.leaf) -``` - -In summary, we've seen: -- How to declare a syntax category for the Dyck grammar. -- How to specify parse trees of this grammar using `syntax` -- How to translate out of this grammar into Lean 4 terms using `macro_rules`. - -The full program listing is given below: - -```lean -{{#include syntax_example.lean}} -``` diff --git a/doc/syntax_examples.md b/doc/syntax_examples.md deleted file mode 100644 index f82b1b7970..0000000000 --- a/doc/syntax_examples.md +++ /dev/null @@ -1,4 +0,0 @@ -# Syntax Metaprogramming Examples - -- [Balanced Parentheses](./syntax_example.md) -- [Arithmetic DSL](./metaprogramming-arith.md) diff --git a/doc/syntax_highlight_in_latex.md b/doc/syntax_highlight_in_latex.md deleted file mode 100644 index 07155e9449..0000000000 --- a/doc/syntax_highlight_in_latex.md +++ /dev/null @@ -1,91 +0,0 @@ -You can copy highlighted code [straight from VS Code](https://code.visualstudio.com/updates/v1_10#_copy-with-syntax-highlighting) to any rich text editor supporting HTML input. For highlighting code in LaTeX, there are two options: -* [listings](https://ctan.org/pkg/listings), which is a common package and simple to set up, but you may run into some restrictions of it and LaTeX around Unicode -* [`minted`](https://ctan.org/pkg/minted), a LaTeX package wrapping the [Pygments](https://pygments.org/) syntax highlighting library. It needs a few more steps to set up, but provides unrestricted support for Unicode when combined with XeLaTeX or LuaLaTex. - -## Example with `listings` - -Save [`lstlean.tex`](https://raw.githubusercontent.com/leanprover/lean4/master/doc/latex/lstlean.tex) into the same directory, or anywhere in your `TEXINPUTS` path, as the following test file: -```latex -\documentclass{article} -\usepackage[T1]{fontenc} -\usepackage[utf8]{inputenc} -\usepackage{listings} -\usepackage{amssymb} - -\usepackage{color} -\definecolor{keywordcolor}{rgb}{0.7, 0.1, 0.1} % red -\definecolor{tacticcolor}{rgb}{0.0, 0.1, 0.6} % blue -\definecolor{commentcolor}{rgb}{0.4, 0.4, 0.4} % grey -\definecolor{symbolcolor}{rgb}{0.0, 0.1, 0.6} % blue -\definecolor{sortcolor}{rgb}{0.1, 0.5, 0.1} % green -\definecolor{attributecolor}{rgb}{0.7, 0.1, 0.1} % red - -\def\lstlanguagefiles{lstlean.tex} -% set default language -\lstset{language=lean} - -\begin{document} -\begin{lstlisting} -theorem funext {f₁ f₂ : ∀ (x : α), β x} (h : ∀ x, f₁ x = f₂ x) : f₁ = f₂ := by - show extfunApp (Quotient.mk f₁) = extfunApp (Quotient.mk f₂) - apply congrArg - apply Quotient.sound - exact h -\end{lstlisting} -\end{document} -``` -Compile the file via -```bash -$ pdflatex test.tex -``` - -* for older LaTeX versions, you might need to use `[utf8x]` instead of `[utf8]` with `inputenc` - -## Example with `minted` - -First [install Pygments](https://pygments.org/download/) (version 2.18 or newer). -Then save the following sample LaTeX file `test.tex` into the same directory: - -```latex -\documentclass{article} -\usepackage{fontspec} -% switch to a monospace font supporting more Unicode characters -\setmonofont{FreeMono} -\usepackage{minted} -\newmintinline[lean]{lean4}{bgcolor=white} -\newminted[leancode]{lean4}{fontsize=\footnotesize} -\usemintedstyle{tango} % a nice, colorful theme - -\begin{document} -\begin{leancode} -theorem funext {f₁ f₂ : ∀ (x : α), β x} (h : ∀ x, f₁ x = f₂ x) : f₁ = f₂ := by - show extfunApp (Quotient.mk' f₁) = extfunApp (Quotient.mk' f₂) - apply congrArg - apply Quotient.sound - exact h -\end{leancode} -\end{document} -``` - -You can then compile `test.tex` by executing the following command: - -```bash -xelatex --shell-escape test.tex -``` - -Some remarks: - - - either `xelatex` or `lualatex` is required to handle Unicode characters in the code. - - `--shell-escape` is needed to allow `xelatex` to execute `pygmentize` in a shell. - - If the chosen monospace font is missing some Unicode symbols, you can direct them to be displayed using a fallback font or other replacement LaTeX code. - ``` latex - \usepackage{newunicodechar} - \newfontfamily{\freeserif}{DejaVu Sans} - \newunicodechar{✝}{\freeserif{✝}} - \newunicodechar{𝓞}{\ensuremath{\mathcal{O}}} - ``` - - If you are using an old version of Pygments, you can copy - [`lean.py`](https://raw.githubusercontent.com/pygments/pygments/master/pygments/lexers/lean.py) into your working directory, - and use `lean4.py:Lean4Lexer -x` instead of `lean4` above. - If your version of `minted` is v2.7 or newer, but before v3.0, - you will additionally need to follow the workaround described in https://github.com/gpoore/minted/issues/360. diff --git a/doc/tactics.md b/doc/tactics.md deleted file mode 100644 index 2b76a26167..0000000000 --- a/doc/tactics.md +++ /dev/null @@ -1,393 +0,0 @@ -# Tactics - -Tactics are metaprograms, that is, programs that create programs. -Lean is implemented in Lean, you can import its implementation using `import Lean`. -The `Lean` package is part of the Lean distribution. -You can use the functions in the `Lean` package to write your own metaprograms -that automate repetitive tasks when writing programs and proofs. - -We provide the **tactic** domain specific language (DSL) for using the tactic framework. -The tactic DSL provides commands for creating terms (and proofs). You -don't need to import the `Lean` package for using the tactic DSL. -Simple extensions can be implemented using macros. More complex extensions require -the `Lean` package. Notation used to write Lean terms can be easily lifted to the tactic DSL. - -Tactics are instructions that tell Lean how to construct a term or proof. -Tactics operate on holes also known as goals. Each hole represents a missing -part of the term you are trying to build. Internally these holes are represented -as metavariables. They have a type and a local context. The local context contains -all local variables in scope. - -In the following example, we prove the same simple theorem using different tactics. -The keyword `by` instructs Lean to use the tactic DSL to construct a term. -Our initial goal is a hole with type `p ∨ q → q ∨ p`. The tactic `intro h` -fills this hole using the term `fun h => ?m` where `?m` is a new hole we need to solve. -This hole has type `q ∨ p`, and the local context contains `h : p ∨ q`. -The tactic `cases` fills the hole using `Or.casesOn h (fun h1 => ?m1) (fun h2 => ?m2)` -where `?m1` and `?m2` are new holes. The tactic `apply Or.inr` fills the hole `?m1` -with the application `Or.inr ?m3`, and `exact h1` fills `?m3` with `h1`. -The tactic `assumption` tries to fill a hole by searching the local context for a term with the same type. - -```lean -theorem ex1 : p ∨ q → q ∨ p := by - intro h - cases h with - | inl h1 => - apply Or.inr - exact h1 - | inr h2 => - apply Or.inl - assumption - -#print ex1 -/- -theorem ex1 : {p q : Prop} → p ∨ q → q ∨ p := -fun {p q : Prop} (h : p ∨ q) => - Or.casesOn h (fun (h1 : p) => Or.inr h1) fun (h2 : q) => Or.inl h2 --/ - --- You can use `match-with` in tactics. -theorem ex2 : p ∨ q → q ∨ p := by - intro h - match h with - | Or.inl _ => apply Or.inr; assumption - | Or.inr h2 => apply Or.inl; exact h2 - --- As we have the `fun+match` syntax sugar for terms, --- we have the `intro+match` syntax sugar -theorem ex3 : p ∨ q → q ∨ p := by - intro - | Or.inl h1 => - apply Or.inr - exact h1 - | Or.inr h2 => - apply Or.inl - assumption -``` - -The examples above are all structured, but Lean 4 still supports unstructured -proofs. Unstructured proofs are useful when creating reusable scripts that may -discharge different goals. -Here is an unstructured version of the example above. - -```lean -theorem ex1 : p ∨ q → q ∨ p := by - intro h - cases h - apply Or.inr - assumption - apply Or.inl - assumption - done -- fails with an error here if there are unsolvable goals - -theorem ex2 : p ∨ q → q ∨ p := by - intro h - cases h - focus -- instructs Lean to `focus` on the first goal, - apply Or.inr - assumption - -- it will fail if there are still unsolvable goals here - focus - apply Or.inl - assumption - -theorem ex3 : p ∨ q → q ∨ p := by - intro h - cases h - -- You can still use curly braces and semicolons instead of - -- whitespace sensitive notation as in the previous example - { apply Or.inr; - assumption - -- It will fail if there are unsolved goals - } - { apply Or.inl; - assumption - } - --- Many tactics tag subgoals. The tactic `cases` tag goals using constructor names. --- The tactic `case tag => tactics` instructs Lean to solve the goal --- with the matching tag. -theorem ex4 : p ∨ q → q ∨ p := by - intro h - cases h - case inr => - apply Or.inl - assumption - case inl => - apply Or.inr - assumption - --- Same example for curly braces and semicolons aficionados -theorem ex5 : p ∨ q → q ∨ p := by { - intro h; - cases h; - case inr => { - apply Or.inl; - assumption - } - case inl => { - apply Or.inr; - assumption - } -} -``` - -## Rewrite - -TODO - -## Pattern matching - -As a convenience, pattern-matching has been integrated into tactics such as `intro` and `funext`. - -```lean -theorem ex1 : s ∧ q ∧ r → p ∧ r → q ∧ p := by - intro ⟨_, ⟨hq, _⟩⟩ ⟨hp, _⟩ - exact ⟨hq, hp⟩ - -theorem ex2 : - (fun (x : Nat × Nat) (y : Nat × Nat) => x.1 + y.2) - = - (fun (x : Nat × Nat) (z : Nat × Nat) => z.2 + x.1) := by - funext (a, b) (c, d) - show a + d = d + a - rw [Nat.add_comm] -``` - -## Induction - -The `induction` tactic now supports user-defined induction principles with -multiple targets (aka major premises). - - -```lean -/- -theorem Nat.mod.inductionOn - {motive : Nat → Nat → Sort u} - (x y : Nat) - (ind : ∀ x y, 0 < y ∧ y ≤ x → motive (x - y) y → motive x y) - (base : ∀ x y, ¬(0 < y ∧ y ≤ x) → motive x y) - : motive x y := --/ - -theorem ex (x : Nat) {y : Nat} (h : y > 0) : x % y < y := by - induction x, y using Nat.mod.inductionOn with - | ind x y h₁ ih => - rw [Nat.mod_eq_sub_mod h₁.2] - exact ih h - | base x y h₁ => - have : ¬ 0 < y ∨ ¬ y ≤ x := Iff.mp (Decidable.not_and_iff_or_not ..) h₁ - match this with - | Or.inl h₁ => exact absurd h h₁ - | Or.inr h₁ => - have hgt : y > x := Nat.gt_of_not_le h₁ - rw [← Nat.mod_eq_of_lt hgt] at hgt - assumption -``` - -## Cases - -TODO - -## Injection - -TODO - -## Split - -The `split` tactic can be used to split the cases of an if-then-else or -match into new subgoals, which can then be discharged individually. - -```lean -def addMoreIfOdd (n : Nat) := if n % 2 = 0 then n + 1 else n + 2 - -/- Examine each branch of the conditional to show that the result - is always positive -/ -example (n : Nat) : 0 < addMoreIfOdd n := by - simp only [addMoreIfOdd] - split - next => exact Nat.zero_lt_succ _ - next => exact Nat.zero_lt_succ _ -``` - -```lean -def binToChar (n : Nat) : Option Char := - match n with - | 0 => some '0' - | 1 => some '1' - | _ => none - -example (n : Nat) : (binToChar n).isSome -> n = 0 ∨ n = 1 := by - simp only [binToChar] - split - next => exact fun _ => Or.inl rfl - next => exact fun _ => Or.inr rfl - next => intro h; cases h - -/- Hypotheses about previous cases can be accessed by assigning them a - name, like `ne_zero` below. Information about the matched term can also - be preserved using the `generalizing` tactic: -/ -example (n : Nat) : (n = 0) -> (binToChar n = some '0') := by - simp only [binToChar] - split - case h_1 => intro _; rfl - case h_2 => intro h; cases h - /- Here, we can introduce `n ≠ 0` and `n ≠ 1` this case assumes - neither of the previous cases matched. -/ - case h_3 ne_zero _ => intro eq_zero; exact absurd eq_zero ne_zero -``` - -## Dependent pattern matching - -The `match-with` expression implements dependent pattern matching. You can use it to create concise proofs. - -```lean -inductive Mem : α → List α → Prop where - | head (a : α) (as : List α) : Mem a (a::as) - | tail (a b : α) (bs : List α) : Mem a bs → Mem a (b::bs) - -infix:50 (priority := high) "∈" => Mem - -theorem mem_split {a : α} {as : List α} (h : a ∈ as) : ∃ s t, as = s ++ a :: t := - match a, as, h with - | _, _, Mem.head a bs => ⟨[], ⟨bs, rfl⟩⟩ - | _, _, Mem.tail a b bs h => - match bs, mem_split h with - | _, ⟨s, ⟨t, rfl⟩⟩ => ⟨b::s, ⟨t, List.cons_append .. ▸ rfl⟩⟩ -``` - -In the tactic DSL, the right-hand-side of each alternative in a `match-with` is a sequence of tactics instead of a term. -Here is a similar proof using the tactic DSL. - -```lean -# inductive Mem : α → List α → Prop where -# | head (a : α) (as : List α) : Mem a (a::as) -# | tail (a b : α) (bs : List α) : Mem a bs → Mem a (b::bs) -# infix:50 (priority := high) "∈" => Mem -theorem mem_split {a : α} {as : List α} (h : a ∈ as) : ∃ s t, as = s ++ a :: t := by - match a, as, h with - | _, _, Mem.head a bs => exists []; exists bs; rfl - | _, _, Mem.tail a b bs h => - match bs, mem_split h with - | _, ⟨s, ⟨t, rfl⟩⟩ => - exists b::s; exists t; - rw [List.cons_append] -``` - -We can use `match-with` nested in tactics. -Here is a similar proof that uses the `induction` tactic instead of recursion. - -```lean -# inductive Mem : α → List α → Prop where -# | head (a : α) (as : List α) : Mem a (a::as) -# | tail (a b : α) (bs : List α) : Mem a bs → Mem a (b::bs) -# infix:50 (priority := high) "∈" => Mem -theorem mem_split {a : α} {as : List α} (h : a ∈ as) : ∃ s t, as = s ++ a :: t := by - induction as with - | nil => cases h - | cons b bs ih => cases h with - | head a bs => exact ⟨[], ⟨bs, rfl⟩⟩ - | tail a b bs h => - match bs, ih h with - | _, ⟨s, ⟨t, rfl⟩⟩ => - exists b::s; exists t - rw [List.cons_append] -``` - -You can create your own notation using existing tactics. In the following example, -we define a simple `obtain` tactic using macros. We say it is simple because it takes only one -discriminant. Later, we show how to create more complex automation using macros. - -```lean -# inductive Mem : α → List α → Prop where -# | head (a : α) (as : List α) : Mem a (a::as) -# | tail (a b : α) (bs : List α) : Mem a bs → Mem a (b::bs) -# infix:50 (priority := high) "∈" => Mem -macro "obtain " p:term " from " d:term : tactic => - `(tactic| match $d:term with | $p:term => ?_) - -theorem mem_split {a : α} {as : List α} (h : a ∈ as) : ∃ s t, as = s ++ a :: t := by - induction as with - | cons b bs ih => cases h with - | tail a b bs h => - obtain ⟨s, ⟨t, h⟩⟩ from ih h - exists b::s; exists t - rw [h, List.cons_append] - | head a bs => exact ⟨[], ⟨bs, rfl⟩⟩ - | nil => cases h - -``` - -## Extensible tactics - -In the following example, we define the notation `triv` for the tactic DSL using -the command `syntax`. Then, we use the command `macro_rules` to specify what should -be done when `triv` is used. You can provide different expansions, and the tactic DSL -interpreter will try all of them until one succeeds. - -```lean --- Define a new notation for the tactic DSL -syntax "triv" : tactic - -macro_rules - | `(tactic| triv) => `(tactic| assumption) - -theorem ex1 (h : p) : p := by - triv - --- You cannot prove the following theorem using `triv` --- theorem ex2 (x : α) : x = x := by --- triv - --- Let's extend `triv`. The `by` DSL interpreter --- tries all possible macro extensions for `triv` until one succeeds -macro_rules - | `(tactic| triv) => `(tactic| rfl) - -theorem ex2 (x : α) : x = x := by - triv - -theorem ex3 (x : α) (h : p) : x = x ∧ p := by - apply And.intro <;> triv -``` - -# `let-rec` - -You can use `let rec` to write local recursive functions. We lifted it to the tactic DSL, -and you can use it to create proofs by induction. - -```lean -theorem length_replicateTR {α} (n : Nat) (a : α) : (List.replicateTR n a).length = n := by - let rec aux (n : Nat) (as : List α) - : (List.replicateTR.loop a n as).length = n + as.length := by - match n with - | 0 => rw [Nat.zero_add]; rfl - | n+1 => - show List.length (List.replicateTR.loop a n (a::as)) = Nat.succ n + as.length - rw [aux n, List.length_cons, Nat.add_succ, Nat.succ_add] - exact aux n [] -``` - -You can also introduce auxiliary recursive declarations using `where` clause after your definition. -Lean converts them into a `let rec`. - -```lean -theorem length_replicateTR {α} (n : Nat) (a : α) : (List.replicateTR n a).length = n := - loop n [] -where - loop n as : (List.replicateTR.loop a n as).length = n + as.length := by - match n with - | 0 => rw [Nat.zero_add]; rfl - | n+1 => - show List.length (List.replicateTR.loop a n (a::as)) = Nat.succ n + as.length - rw [loop n, List.length_cons, Nat.add_succ, Nat.succ_add] -``` - -# `begin-end` lovers - -If you love Lean 3 `begin ... end` tactic blocks and commas, you can define this notation -in Lean 4 using macros in a few lines of code. - -```lean -{{#include ../tests/lean/beginEndAsMacro.lean:doc}} -``` diff --git a/doc/tour.md b/doc/tour.md deleted file mode 100644 index 010bf4076f..0000000000 --- a/doc/tour.md +++ /dev/null @@ -1,200 +0,0 @@ -# Tour of Lean - -The best way to learn about Lean is to read and write Lean code. -This article will act as a tour through some of the key features of the Lean -language and give you some code snippets that you can execute on your machine. -To learn about setting up a development environment, check out [Setting Up Lean](./setup.md). - -There are two primary concepts in Lean: functions and types. -This tour will emphasize features of the language which fall into -these two concepts. - -# Functions and Namespaces - -The most fundamental pieces of any Lean program are functions organized into namespaces. -[Functions](./functions.md) perform work on inputs to produce outputs, -and they are organized under [namespaces](./namespaces.md), -which are the primary way you group things in Lean. -They are defined using the `def` command, -which give the function a name and define its arguments. - -```lean -namespace BasicFunctions - --- The `#eval` command evaluates an expression on the fly and prints the result. -#eval 2+2 - --- You use 'def' to define a function. This one accepts a natural number --- and returns a natural number. --- Parentheses are optional for function arguments, except for when --- you use an explicit type annotation. --- Lean can often infer the type of the function's arguments. -def sampleFunction1 x := x*x + 3 - --- Apply the function, naming the function return result using 'def'. --- The variable type is inferred from the function return type. -def result1 := sampleFunction1 4573 - --- This line uses an interpolated string to print the result. Expressions inside --- braces `{}` are converted into strings using the polymorphic method `toString` -#eval println! "The result of squaring the integer 4573 and adding 3 is {result1}" - --- When needed, annotate the type of a parameter name using '(argument : type)'. -def sampleFunction2 (x : Nat) := 2*x*x - x + 3 - -def result2 := sampleFunction2 (7 + 4) - -#eval println! "The result of applying the 2nd sample function to (7 + 4) is {result2}" - --- Conditionals use if/then/else -def sampleFunction3 (x : Int) := - if x > 100 then - 2*x*x - x + 3 - else - 2*x*x + x - 37 - -#eval println! "The result of applying sampleFunction3 to 2 is {sampleFunction3 2}" - -end BasicFunctions -``` - -```lean --- Lean has first-class functions. --- `twice` takes two arguments `f` and `a` where --- `f` is a function from natural numbers to natural numbers, and --- `a` is a natural number. -def twice (f : Nat → Nat) (a : Nat) := - f (f a) - --- `fun` is used to declare anonymous functions -#eval twice (fun x => x + 2) 10 - --- You can prove theorems about your functions. --- The following theorem states that for any natural number `a`, --- adding 2 twice produces a value equal to `a + 4`. -theorem twiceAdd2 (a : Nat) : twice (fun x => x + 2) a = a + 4 := - -- The proof is by reflexivity. Lean "symbolically" reduces both sides of the equality - -- until they are identical. - rfl - --- `(· + 2)` is syntax sugar for `(fun x => x + 2)`. The parentheses + `·` notation --- is useful for defining simple anonymous functions. -#eval twice (· + 2) 10 - --- Enumerated types are a special case of inductive types in Lean, --- which we will learn about later. --- The following command creates a new type `Weekday`. -inductive Weekday where - | sunday : Weekday - | monday : Weekday - | tuesday : Weekday - | wednesday : Weekday - | thursday : Weekday - | friday : Weekday - | saturday : Weekday - --- `Weekday` has 7 constructors/elements. --- The constructors live in the `Weekday` namespace. --- Think of `sunday`, `monday`, …, `saturday` as being distinct elements of `Weekday`, --- with no other distinguishing properties. --- The command `#check` prints the type of a term in Lean. -#check Weekday.sunday -#check Weekday.monday - --- The `open` command opens a namespace, making all declarations in it accessible without --- qualification. -open Weekday -#check sunday -#check tuesday - --- You can define functions by pattern matching. --- The following function converts a `Weekday` into a natural number. -def natOfWeekday (d : Weekday) : Nat := - match d with - | sunday => 1 - | monday => 2 - | tuesday => 3 - | wednesday => 4 - | thursday => 5 - | friday => 6 - | saturday => 7 - -#eval natOfWeekday tuesday - -def isMonday : Weekday → Bool := - -- `fun` + `match` is a common idiom. - -- The following expression is syntax sugar for - -- `fun d => match d with | monday => true | _ => false`. - fun - | monday => true - | _ => false - -#eval isMonday monday -#eval isMonday sunday - --- Lean has support for type classes and polymorphic methods. --- The `toString` method converts a value into a `String`. -#eval toString 10 -#eval toString (10, 20) - --- The method `toString` converts values of any type that implements --- the class `ToString`. --- You can implement instances of `ToString` for your own types. -instance : ToString Weekday where - toString (d : Weekday) : String := - match d with - | sunday => "Sunday" - | monday => "Monday" - | tuesday => "Tuesday" - | wednesday => "Wednesday" - | thursday => "Thursday" - | friday => "Friday" - | saturday => "Saturday" - -#eval toString (sunday, 10) - -def Weekday.next (d : Weekday) : Weekday := - match d with - | sunday => monday - | monday => tuesday - | tuesday => wednesday - | wednesday => thursday - | thursday => friday - | friday => saturday - | saturday => sunday - -#eval Weekday.next Weekday.wednesday --- Since the `Weekday` namespace has already been opened, you can also write -#eval next wednesday - --- Matching on a parameter like in the previous definition --- is so common that Lean provides syntax sugar for it. The following --- function uses it. -def Weekday.previous : Weekday -> Weekday - | sunday => saturday - | monday => sunday - | tuesday => monday - | wednesday => tuesday - | thursday => wednesday - | friday => thursday - | saturday => friday - -#eval next (previous wednesday) - --- We can prove that for any `Weekday` `d`, `next (previous d) = d` -theorem Weekday.nextOfPrevious (d : Weekday) : next (previous d) = d := - match d with - | sunday => rfl - | monday => rfl - | tuesday => rfl - | wednesday => rfl - | thursday => rfl - | friday => rfl - | saturday => rfl - --- You can automate definitions such as `Weekday.nextOfPrevious` --- using metaprogramming (or "tactics"). -theorem Weekday.nextOfPrevious' (d : Weekday) : next (previous d) = d := by - cases d -- A proof by case distinction - all_goals rfl -- Each case is solved using `rfl` -``` diff --git a/doc/tpil.md b/doc/tpil.md deleted file mode 100644 index fac1006719..0000000000 --- a/doc/tpil.md +++ /dev/null @@ -1,5 +0,0 @@ -Theorem Proving in Lean -======================= - -We strongly encourage you to read the book [Theorem Proving in Lean](https://lean-lang.org/theorem_proving_in_lean4/title_page.html). -Many Lean users consider it to be the Lean Bible. diff --git a/doc/typeobjs.md b/doc/typeobjs.md deleted file mode 100644 index f9ee7145bf..0000000000 --- a/doc/typeobjs.md +++ /dev/null @@ -1,129 +0,0 @@ -## Types as objects - -One way in which Lean's dependent type theory extends simple type theory is that types themselves --- entities like ``Nat`` and ``Bool`` --- -are first-class citizens, which is to say that they themselves are objects. For that to be the case, each of them also has to have a type. - -```lean -#check Nat -- Type -#check Bool -- Type -#check Nat → Bool -- Type -#check Nat × Bool -- Type -#check Nat → Nat -- ... -#check Nat × Nat → Nat -#check Nat → Nat → Nat -#check Nat → (Nat → Nat) -#check Nat → Nat → Bool -#check (Nat → Nat) → Nat -``` - -We see that each one of the expressions above is an object of type ``Type``. We can also declare new constants and constructors for types: - -```lean -constant α : Type -constant β : Type -constant F : Type → Type -constant G : Type → Type → Type - -#check α -- Type -#check F α -- Type -#check F Nat -- Type -#check G α -- Type → Type -#check G α β -- Type -#check G α Nat -- Type -``` - -Indeed, we have already seen an example of a function of type ``Type → Type → Type``, namely, the Cartesian product. - -```lean -constant α : Type -constant β : Type - -#check Prod α β -- Type -#check Prod Nat Nat -- Type -``` - -Here is another example: given any type ``α``, the type ``List α`` denotes the type of lists of elements of type ``α``. - -```lean -constant α : Type - -#check List α -- Type -#check List Nat -- Type -``` - -Given that every expression in Lean has a type, it is natural to ask: what type does ``Type`` itself have? - -```lean -#check Type -- Type 1 -``` - -We have actually come up against one of the most subtle aspects of Lean's typing system. -Lean's underlying foundation has an infinite hierarchy of types: - -```lean -#check Type -- Type 1 -#check Type 1 -- Type 2 -#check Type 2 -- Type 3 -#check Type 3 -- Type 4 -#check Type 4 -- Type 5 -``` - -Think of ``Type 0`` as a universe of "small" or "ordinary" types. -``Type 1`` is then a larger universe of types, which contains ``Type 0`` as an element, -and ``Type 2`` is an even larger universe of types, which contains ``Type 1`` as an element. -The list is indefinite, so that there is a ``Type n`` for every natural number ``n``. -``Type`` is an abbreviation for ``Type 0``: - -```lean -#check Type -#check Type 0 -``` - -There is also another type universe, ``Prop``, which has special properties. - -```lean -#check Prop -- Type -``` - -We will discuss ``Prop`` later. - -We want some operations, however, to be *polymorphic* over type universes. For example, ``List α`` should -make sense for any type ``α``, no matter which type universe ``α`` lives in. This explains the type annotation of the function ``List``: - -```lean -#check List -- Type u_1 → Type u_1 -``` - -Here ``u_1`` is a variable ranging over type levels. The output of the ``#check`` command means that whenever ``α`` has type ``Type n``, ``List α`` also has type ``Type n``. The function ``Prod`` is similarly polymorphic: - -```lean -#check Prod -- Type u_1 → Type u_2 → Type (max u_1 u_2) -``` - -To define polymorphic constants and variables, Lean allows us to declare universe variables explicitly using the `universe` command: - -```lean -universe u -constant α : Type u -#check α -``` -Equivalently, we can write ``Type _`` to avoid giving the arbitrary universe a name: - -```lean -constant α : Type _ -#check α -``` - -Several Lean 3 users use the shorthand `Type*` for `Type _`. The `Type*` notation is not builtin in Lean 4, but you can easily define it using a `macro`. -```lean -macro "Type*" : term => `(Type _) - -def f (α : Type*) (a : α) := a - -def g (α : Type _) (a : α) := a - -#check f -#check g -``` - -We explain later how the `macro` command works. diff --git a/doc/types.md b/doc/types.md deleted file mode 100644 index 2d8fd6763a..0000000000 --- a/doc/types.md +++ /dev/null @@ -1,56 +0,0 @@ -# Types - -Every programming language needs a type system and -Lean has a rich extensible inductive type system. - -## Basic Types - -Lean has built in support for the following basic types: - -- [Bool](bool.md) : a `true` or `false` value. -- [Int](integers.md) : multiple precision integers (with no overflows!). - -- [Nat](integers.md) : natural numbers, or non-negative integers (also with no overflows!). -- [Float](float.md): floating point numbers. -- [Char](char.md): a Unicode character. -- [String](string.md): a UTF-8 encoded string of characters. -- [Array](array.md): a dynamic (aka growable) array of typed objects. -- [List](list.md): a linked list of typed objects. -- TODO: what else? - -And Lean allows you to create your own custom types using: -- [Enumerated Types](enum.md): a special case of inductive types. -- [Type Classes](typeclasses.md): a way of creating custom polymorphism. -- [Types as objects](typeobjs.md): a way of manipulating types themselves. -- [Structures](struct.md): a collection of named and typed fields. A - structure is actually special case of inductive datatype. -- [Inductive Types](inductive.md): TODO: add one liner... - -## Universes - -Every type in Lean is, by definition, an expression of type `Sort u` -for some universe level `u`. A universe level is one of the -following: - -* a natural number, `n` -* a universe variable, `u` (declared with the command `universe` or `universes`) -* an expression `u + n`, where `u` is a universe level and `n` is a natural number -* an expression `max u v`, where `u` and `v` are universes -* an expression `imax u v`, where `u` and `v` are universe levels - -The last one denotes the universe level `0` if `v` is `0`, and `max u v` otherwise. - -```lean -universe u v - -#check Sort u -- Type u -#check Sort 5 -- Type 4 : Type 5 -#check Sort (u + 1) -- Type u : Type (u + 1) -#check Sort (u + 3) -- Type (u + 2) : Type (u + 3) -#check Sort (max u v) -- Sort (max u v) : Type (max u v) -#check Sort (max (u + 3) v) -- Sort (max (u + 3) v) : Type (max (u + 3) v) -#check Sort (imax (u + 3) v) -- Sort (imax (u + 3) v) : Type (imax (u + 3) v) -#check Prop -- Type -#check Type -- Type 1 -#check Type 1 -- Type 1 : Type 2 -``` diff --git a/doc/using_lean.md b/doc/using_lean.md deleted file mode 100644 index a9b4c8233b..0000000000 --- a/doc/using_lean.md +++ /dev/null @@ -1 +0,0 @@ -# Using Lean diff --git a/doc/whatIsLean.md b/doc/whatIsLean.md deleted file mode 100644 index ce14919978..0000000000 --- a/doc/whatIsLean.md +++ /dev/null @@ -1,42 +0,0 @@ -# What is Lean - -Lean is a functional programming language that makes it easy to -write correct and maintainable code. -You can also use Lean as an interactive theorem prover. - -Lean programming primarily involves defining types and functions. -This allows your focus to remain on the problem domain and manipulating its data, -rather than the details of programming. - -```lean --- Defines a function that takes a name and produces a greeting. -def getGreeting (name : String) := s!"Hello, {name}! Isn't Lean great?" - --- The `main` function is the entry point of your program. --- Its type is `IO Unit` because it can perform `IO` operations (side effects). -def main : IO Unit := - -- Define a list of names - let names := ["Sebastian", "Leo", "Daniel"] - - -- Map each name to a greeting - let greetings := names.map getGreeting - - -- Print the list of greetings - for greeting in greetings do - IO.println greeting -``` - -Lean has numerous features, including: - -- Type inference -- First-class functions -- Powerful data types -- Pattern matching -- [Type classes](./typeclass.md) -- [Monads](./monads/intro.md) -- [Extensible syntax](./syntax.md) -- Hygienic macros -- [Dependent types](https://lean-lang.org/theorem_proving_in_lean4/dependent_type_theory.html) -- [Metaprogramming](./macro_overview.md) -- Multithreading -- Verification: you can prove properties of your functions using Lean itself diff --git a/src/Lean/Parser/Extra.lean b/src/Lean/Parser/Extra.lean index 64c215cc4b..7c2f39b918 100644 --- a/src/Lean/Parser/Extra.lean +++ b/src/Lean/Parser/Extra.lean @@ -91,8 +91,8 @@ around an `.ident` which is `Name.anonymous` but with macro scopes like a regula This is used to implement `have := ...` syntax: the `hygieneInfo` between the `have` and `:=` substitutes for the identifier which would normally go there as in `have x :=`, so that we can expand `have :=` to `have this :=` while retaining the usual macro name resolution behavior. -See [doc/macro_overview.md](https://github.com/leanprover/lean4/blob/master/doc/macro_overview.md) -for more information about macro hygiene. +See [the language reference](lean-manual://section/macro-hygiene) for more information about +macro hygiene. This parser has arity 1: it produces a `Syntax.ident` node containing the parsed identifier. You can use `TSyntax.getHygieneInfo` to extract the name from the resulting syntax object. -/ diff --git a/src/Lean/Widget/Types.lean b/src/Lean/Widget/Types.lean index 8b9ca279a6..2f4097997d 100644 --- a/src/Lean/Widget/Types.lean +++ b/src/Lean/Widget/Types.lean @@ -13,7 +13,7 @@ namespace Lean.Widget the identifier of a widget module and the hash of its JS source code together with props. -See the [manual entry](https://lean-lang.org/lean4/doc/examples/widgets.lean.html) +See the [manual entry](https://lean-lang.org/documentation/widgets/) for more information about widgets. -/ structure WidgetInstance where /-- Name of the `@[widget_module]`. -/ diff --git a/src/lake/examples/reverse-ffi/main.c b/src/lake/examples/reverse-ffi/main.c index 24b19b6ebf..e30d757cb9 100644 --- a/src/lake/examples/reverse-ffi/main.c +++ b/src/lake/examples/reverse-ffi/main.c @@ -3,7 +3,7 @@ extern uint64_t my_length(lean_obj_arg); -// see https://leanprover.github.io/lean4/doc/dev/ffi.html#initialization +// see https://lean-lang.org/doc/reference/latest/find/?domain=Verso.Genre.Manual.section&name=ffi-initialization extern void lean_initialize_runtime_module(); extern void lean_initialize(); extern void lean_io_mark_end_initialization(); diff --git a/src/stdlib_flags.h b/src/stdlib_flags.h index b64fc2dae6..79a0e58edd 100644 --- a/src/stdlib_flags.h +++ b/src/stdlib_flags.h @@ -3,7 +3,7 @@ namespace lean { options get_default_options() { options opts; - // see https://lean-lang.org/lean4/doc/dev/bootstrap.html#further-bootstrapping-complications + // see https://github.com/leanprover/lean4/blob/master/doc/dev/bootstrap.md#further-bootstrapping-complications #if LEAN_IS_STAGE0 == 1 // set to true to generally avoid bootstrapping issues limited to proofs opts = opts.update({"debug", "proofAsSorry"}, false);