mirror of
https://github.com/leanprover/lean4.git
synced 2026-04-02 02:04:09 +00:00
Compare commits
224 Commits
grind_patt
...
sofia/asyn
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8810bbe140 | ||
|
|
349c860b8b | ||
|
|
6a424ee4e6 | ||
|
|
07c5465052 | ||
|
|
7ff00b14af | ||
|
|
debdf61d73 | ||
|
|
6d834b29fb | ||
|
|
ee8ad4e679 | ||
|
|
d3c70a6cc0 | ||
|
|
b796cd7714 | ||
|
|
12b646e538 | ||
|
|
ab292870fa | ||
|
|
60cf9f0cc4 | ||
|
|
c33dcf5c1e | ||
|
|
7da031df86 | ||
|
|
81a0c28828 | ||
|
|
1ead9eb8ac | ||
|
|
014b4c8a90 | ||
|
|
9b49b6b68d | ||
|
|
eb20c07b4a | ||
|
|
3fdde57e7b | ||
|
|
c79d74d9a1 | ||
|
|
082c65f226 | ||
|
|
6a0b0c8273 | ||
|
|
62b900e8ef | ||
|
|
429e09cd82 | ||
|
|
c4d67c22e6 | ||
|
|
923d7e1ed6 | ||
|
|
5db865ea2f | ||
|
|
0f2ac0b099 | ||
|
|
b7ff463358 | ||
|
|
799c6b5ff8 | ||
|
|
2d0c62c767 | ||
|
|
fb6c96e54b | ||
|
|
c20378682e | ||
|
|
b7e6862163 | ||
|
|
983d64395a | ||
|
|
6db52f0aa9 | ||
|
|
e489c342d7 | ||
|
|
0bfbb71796 | ||
|
|
38c401cf3b | ||
|
|
a2ceebe200 | ||
|
|
292b74b0a4 | ||
|
|
d76752ffb8 | ||
|
|
d4463ce549 | ||
|
|
074dc60bea | ||
|
|
6d8a16f137 | ||
|
|
f0e594d5db | ||
|
|
32d22075dc | ||
|
|
902226642f | ||
|
|
67ba4da71f | ||
|
|
0eed450b86 | ||
|
|
834886bca2 | ||
|
|
5339c47555 | ||
|
|
1f80b3ffbe | ||
|
|
de388a7e6d | ||
|
|
5fff9fb228 | ||
|
|
59045c6227 | ||
|
|
ac7b95da86 | ||
|
|
bb264e1ff0 | ||
|
|
28fca70cb7 | ||
|
|
5e4c90c3d1 | ||
|
|
9df8a80c7d | ||
|
|
9d7d15b276 | ||
|
|
7f5e28ac89 | ||
|
|
9be007ad70 | ||
|
|
0c7169efa9 | ||
|
|
73d389f358 | ||
|
|
0158172871 | ||
|
|
520cdb2038 | ||
|
|
9f74e71f10 | ||
|
|
ad02aa159c | ||
|
|
07645775e6 | ||
|
|
a984e17913 | ||
|
|
8220baf6db | ||
|
|
fc26c8145c | ||
|
|
9e4f9d317b | ||
|
|
3937af3d75 | ||
|
|
646df6ba16 | ||
|
|
552fa10a60 | ||
|
|
7d2dbe8787 | ||
|
|
3bd1dd633f | ||
|
|
d824f7e085 | ||
|
|
381c0f2b61 | ||
|
|
2d3dec41ca | ||
|
|
cec9758c2d | ||
|
|
c4477939d0 | ||
|
|
864acddb4a | ||
|
|
26ff270e28 | ||
|
|
6469890178 | ||
|
|
37f9984d71 | ||
|
|
138476d635 | ||
|
|
ea10bdf154 | ||
|
|
b8c53b1d29 | ||
|
|
e7f4fc9baf | ||
|
|
d145b9f8ee | ||
|
|
05a81248df | ||
|
|
9928cf3d64 | ||
|
|
aa4aff280b | ||
|
|
eee58f4506 | ||
|
|
756396ad8f | ||
|
|
cc89a853e5 | ||
|
|
1c1bd8e064 | ||
|
|
a20e029718 | ||
|
|
95e33d88a8 | ||
|
|
351a941756 | ||
|
|
124e34ef5a | ||
|
|
f88e503f3d | ||
|
|
2e4b079e73 | ||
|
|
9e87560376 | ||
|
|
466a24893b | ||
|
|
acb7bc5f22 | ||
|
|
595d87b5e6 | ||
|
|
361bfdbc5c | ||
|
|
2b257854f9 | ||
|
|
18248651a3 | ||
|
|
a35ba44197 | ||
|
|
a7ecae5189 | ||
|
|
42e8011320 | ||
|
|
ec008ff55a | ||
|
|
72196169b6 | ||
|
|
9466a052bc | ||
|
|
589dde0c3b | ||
|
|
b9e888df4e | ||
|
|
088f8b0b9c | ||
|
|
30ea4170a7 | ||
|
|
0738e4d61a | ||
|
|
3b40682b22 | ||
|
|
06037ade0f | ||
|
|
9895e25e95 | ||
|
|
19e1fe55f3 | ||
|
|
5bf5c73f74 | ||
|
|
5326530383 | ||
|
|
9f99c512e7 | ||
|
|
d247dcffc4 | ||
|
|
2fff4c6522 | ||
|
|
c213882788 | ||
|
|
6e711bf067 | ||
|
|
cfef643d03 | ||
|
|
bf51e1dcfa | ||
|
|
1d0d3915ca | ||
|
|
3c100ada2a | ||
|
|
383c0caa91 | ||
|
|
cbf6fe5d1b | ||
|
|
e11800d3c8 | ||
|
|
c9b8508f6b | ||
|
|
ecce5e69bf | ||
|
|
459e9f702f | ||
|
|
62f2f92293 | ||
|
|
6cbcbce750 | ||
|
|
cdb994b776 | ||
|
|
b7ac6243a9 | ||
|
|
2ca3bc2859 | ||
|
|
03a6e58cec | ||
|
|
72ddc479bf | ||
|
|
c5e04176b8 | ||
|
|
4b77e226ab | ||
|
|
d4c832ecb0 | ||
|
|
9cbff55c56 | ||
|
|
e0650a0336 | ||
|
|
76f32e2273 | ||
|
|
f2415b7a9a | ||
|
|
455fd0b448 | ||
|
|
b3753ba6db | ||
|
|
8afaa1bc11 | ||
|
|
71991296e0 | ||
|
|
b0a12cb49f | ||
|
|
ab606ba754 | ||
|
|
6ca57a74ed | ||
|
|
0ba40b798b | ||
|
|
42ded564bd | ||
|
|
f0738c2cd1 | ||
|
|
5f561bfee2 | ||
|
|
af6d2077a0 | ||
|
|
31d629cb67 | ||
|
|
d60ef53d54 | ||
|
|
dd57725244 | ||
|
|
e548fa414c | ||
|
|
b94cf2c9be | ||
|
|
dd28f00588 | ||
|
|
54fbe931ab | ||
|
|
fb261921b9 | ||
|
|
0173444d24 | ||
|
|
1377da0c76 | ||
|
|
5db4f96699 | ||
|
|
8bc3eb1265 | ||
|
|
cac2c47376 | ||
|
|
3fe368e8e7 | ||
|
|
f8866dcc59 | ||
|
|
9263a6cc9c | ||
|
|
edcef51434 | ||
|
|
79838834c1 | ||
|
|
edf804c70f | ||
|
|
8b7cbe7d2e | ||
|
|
a0c503cf2b | ||
|
|
0e83422fb6 | ||
|
|
3dd99fc29c | ||
|
|
0646bc5979 | ||
|
|
2eca5ca6e4 | ||
|
|
1fc4768b68 | ||
|
|
1e1ed16a05 | ||
|
|
226a90f1eb | ||
|
|
519ccf5d9d | ||
|
|
1c1c534a03 | ||
|
|
8b103f33cf | ||
|
|
a0c8404ab8 | ||
|
|
c0d5b9b52c | ||
|
|
96461a4b03 | ||
|
|
310abce62b | ||
|
|
2da5b528b7 | ||
|
|
ca23ed0c17 | ||
|
|
5e165e358c | ||
|
|
429734c02f | ||
|
|
35a36ae343 | ||
|
|
f9dc77673b | ||
|
|
1ae680c5e2 | ||
|
|
057b70b443 | ||
|
|
677561522d | ||
|
|
af5b47295f | ||
|
|
3282ac6f96 | ||
|
|
5bd331e85d | ||
|
|
856825a4d2 | ||
|
|
16508196e0 | ||
|
|
4eba5ea96d |
@@ -39,6 +39,7 @@ These comments explain the scripts' behavior, which repositories get special han
|
||||
|
||||
## Important Notes
|
||||
|
||||
- **NEVER merge PRs autonomously** - always wait for the user to merge PRs themselves
|
||||
- The `release_steps.py` script is idempotent - it's safe to rerun
|
||||
- The `release_checklist.py` script is idempotent - it's safe to rerun
|
||||
- Some repositories depend on others (e.g., mathlib4 depends on batteries, aesop, etc.)
|
||||
|
||||
1
.gitattributes
vendored
1
.gitattributes
vendored
@@ -4,6 +4,7 @@ RELEASES.md merge=union
|
||||
stage0/** binary linguist-generated
|
||||
# The following file is often manually edited, so do show it in diffs
|
||||
stage0/src/stdlib_flags.h -binary -linguist-generated
|
||||
doc/std/grove/GroveStdlib/Generated/** linguist-generated
|
||||
# These files should not have line endings translated on Windows, because
|
||||
# it throws off parser tests. Later lines override earlier ones, so the
|
||||
# runner code is still treated as ordinary text.
|
||||
|
||||
2
.github/ISSUE_TEMPLATE/bug_report.md
vendored
2
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@@ -9,7 +9,7 @@ assignees: ''
|
||||
|
||||
### Prerequisites
|
||||
|
||||
Please put an X between the brackets as you perform the following steps:
|
||||
<!-- Please put an X between the brackets as you perform the following steps: -->
|
||||
|
||||
* [ ] Check that your issue is not already filed:
|
||||
https://github.com/leanprover/lean4/issues
|
||||
|
||||
2
.github/workflows/build-template.yml
vendored
2
.github/workflows/build-template.yml
vendored
@@ -220,7 +220,7 @@ jobs:
|
||||
path: pack/*
|
||||
- name: Lean stats
|
||||
run: |
|
||||
build/$TARGET_STAGE/bin/lean --stats src/Lean.lean -Dexperimental.module=true
|
||||
build/$TARGET_STAGE/bin/lean --stats src/Lean.lean
|
||||
if: ${{ !matrix.cross }}
|
||||
- name: Test
|
||||
id: test
|
||||
|
||||
57
.github/workflows/check-stdlib-flags.yml
vendored
Normal file
57
.github/workflows/check-stdlib-flags.yml
vendored
Normal file
@@ -0,0 +1,57 @@
|
||||
name: Check stdlib_flags.h modifications
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: [opened, synchronize, reopened, labeled, unlabeled]
|
||||
|
||||
jobs:
|
||||
check-stdlib-flags:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Check if stdlib_flags.h was modified
|
||||
uses: actions/github-script@v8
|
||||
with:
|
||||
script: |
|
||||
// Get the list of files changed in this PR
|
||||
const files = await github.paginate(
|
||||
github.rest.pulls.listFiles,
|
||||
{
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
pull_number: context.payload.pull_request.number,
|
||||
}
|
||||
);
|
||||
|
||||
// Check if stdlib_flags.h was modified
|
||||
const stdlibFlagsModified = files.some(file =>
|
||||
file.filename === 'src/stdlib_flags.h'
|
||||
);
|
||||
|
||||
if (stdlibFlagsModified) {
|
||||
console.log('src/stdlib_flags.h was modified in this PR');
|
||||
|
||||
// Check if the unlock label is present
|
||||
|
||||
const { data: pr } = await github.rest.pulls.get({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
pull_number: context.issue.number,
|
||||
});
|
||||
|
||||
const hasUnlockLabel = pr.labels.some(label =>
|
||||
label.name === 'unlock-upstream-stdlib-flags'
|
||||
);
|
||||
|
||||
if (!hasUnlockLabel) {
|
||||
core.setFailed(
|
||||
'src/stdlib_flags.h was modified. This is likely a mistake. If you would like to change ' +
|
||||
'bootstrapping settings or request a stage0 update, you should modify stage0/src/stdlib_flags.h. ' +
|
||||
'If you really want to change src/stdlib_flags.h (which should be extremely rare), set the ' +
|
||||
'unlock-upstream-stdlib-flags label.'
|
||||
);
|
||||
} else {
|
||||
console.log('Found unlock-upstream-stdlib-flags');
|
||||
}
|
||||
} else {
|
||||
console.log('src/stdlib_flags.h was not modified');
|
||||
}
|
||||
15
.github/workflows/ci.yml
vendored
15
.github/workflows/ci.yml
vendored
@@ -52,7 +52,7 @@ jobs:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v5
|
||||
# don't schedule nightlies on forks
|
||||
if: github.event_name == 'schedule' && github.repository == 'leanprover/lean4' || inputs.action == 'release nightly'
|
||||
if: github.event_name == 'schedule' && github.repository == 'leanprover/lean4' || inputs.action == 'release nightly' || (startsWith(github.ref, 'refs/tags/') && github.repository == 'leanprover/lean4')
|
||||
- name: Set Nightly
|
||||
if: github.event_name == 'schedule' && github.repository == 'leanprover/lean4' || inputs.action == 'release nightly'
|
||||
id: set-nightly
|
||||
@@ -115,7 +115,7 @@ jobs:
|
||||
CMAKE_MAJOR=$(grep -E "^set\(LEAN_VERSION_MAJOR " src/CMakeLists.txt | grep -oE '[0-9]+')
|
||||
CMAKE_MINOR=$(grep -E "^set\(LEAN_VERSION_MINOR " src/CMakeLists.txt | grep -oE '[0-9]+')
|
||||
CMAKE_PATCH=$(grep -E "^set\(LEAN_VERSION_PATCH " src/CMakeLists.txt | grep -oE '[0-9]+')
|
||||
CMAKE_IS_RELEASE=$(grep -E "^set\(LEAN_VERSION_IS_RELEASE " src/CMakeLists.txt | grep -oE '[0-9]+')
|
||||
CMAKE_IS_RELEASE=$(grep -m 1 -E "^set\(LEAN_VERSION_IS_RELEASE " src/CMakeLists.txt | grep -oE '[0-9]+')
|
||||
|
||||
# Expected values from tag parsing
|
||||
TAG_MAJOR="${{ steps.set-release.outputs.LEAN_VERSION_MAJOR }}"
|
||||
@@ -267,11 +267,14 @@ jobs:
|
||||
"test": true,
|
||||
// turn off custom allocator & symbolic functions to make LSAN do its magic
|
||||
"CMAKE_PRESET": "sanitize",
|
||||
// `StackOverflow*` correctly triggers ubsan
|
||||
// `reverse-ffi` fails to link in sanitizers
|
||||
// `StackOverflow*` correctly triggers ubsan.
|
||||
// `reverse-ffi` fails to link in sanitizers.
|
||||
// `interactive` and `async_select_channel` fail nondeterministically, would need to
|
||||
// be investigated.
|
||||
"CTEST_OPTIONS": "-E 'StackOverflow|reverse-ffi|interactive|async_select_channel'"
|
||||
// be investigated..
|
||||
// 9366 is too close to timeout.
|
||||
// `bv_` sometimes times out calling into cadical even though we should be using the
|
||||
// standard compile flags for it.
|
||||
"CTEST_OPTIONS": "-E 'StackOverflow|reverse-ffi|interactive|async_select_channel|9366|run/bv_'"
|
||||
},
|
||||
{
|
||||
"name": "macOS",
|
||||
|
||||
5
.github/workflows/grove.yml
vendored
5
.github/workflows/grove.yml
vendored
@@ -51,7 +51,7 @@ jobs:
|
||||
- name: Fetch upstream invalidated facts
|
||||
if: ${{ steps.should-run.outputs.should-run == 'true' && steps.workflow-info.outputs.pullRequestNumber != '' }}
|
||||
id: fetch-upstream
|
||||
uses: TwoFx/grove-action/fetch-upstream@v0.4
|
||||
uses: TwoFx/grove-action/fetch-upstream@v0.5
|
||||
with:
|
||||
artifact-name: grove-invalidated-facts
|
||||
base-ref: master
|
||||
@@ -65,6 +65,7 @@ jobs:
|
||||
workflow: ci.yml
|
||||
path: artifacts
|
||||
name: "build-Linux release"
|
||||
allow_forks: true
|
||||
name_is_regexp: true
|
||||
|
||||
- name: Unpack toolchain
|
||||
@@ -95,7 +96,7 @@ jobs:
|
||||
- name: Build
|
||||
if: ${{ steps.should-run.outputs.should-run == 'true' }}
|
||||
id: build
|
||||
uses: TwoFx/grove-action/build@v0.4
|
||||
uses: TwoFx/grove-action/build@v0.5
|
||||
with:
|
||||
project-path: doc/std/grove
|
||||
script-name: grove-stdlib
|
||||
|
||||
14
.github/workflows/pr-release.yml
vendored
14
.github/workflows/pr-release.yml
vendored
@@ -127,7 +127,7 @@ jobs:
|
||||
description: "${{ github.repository_owner }}/lean4-pr-releases:pr-release-${{ steps.workflow-info.outputs.pullRequestNumber }}-${{ env.SHORT_SHA }}",
|
||||
});
|
||||
|
||||
- name: Add label
|
||||
- name: Add toolchain-available label
|
||||
if: ${{ steps.workflow-info.outputs.pullRequestNumber != '' }}
|
||||
uses: actions/github-script@v8
|
||||
with:
|
||||
@@ -515,6 +515,18 @@ jobs:
|
||||
run: |
|
||||
git push origin lean-pr-testing-${{ steps.workflow-info.outputs.pullRequestNumber }}
|
||||
|
||||
- name: Add mathlib4-nightly-available label
|
||||
if: steps.workflow-info.outputs.pullRequestNumber != '' && steps.ready.outputs.mathlib_ready == 'true'
|
||||
uses: actions/github-script@v8
|
||||
with:
|
||||
script: |
|
||||
await github.rest.issues.addLabels({
|
||||
issue_number: ${{ steps.workflow-info.outputs.pullRequestNumber }},
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
labels: ['mathlib4-nightly-available']
|
||||
})
|
||||
|
||||
# We next automatically create a reference manual branch using this toolchain.
|
||||
# Reference manual CI will be responsible for reporting back success or failure
|
||||
# to the PR comments asynchronously (and thus transitively SubVerso/Verso).
|
||||
|
||||
@@ -44,7 +44,9 @@ if (NOT ${CMAKE_SYSTEM_NAME} MATCHES "Emscripten")
|
||||
set(CADICAL_CXX c++)
|
||||
if (CADICAL_USE_CUSTOM_CXX)
|
||||
set(CADICAL_CXX ${CMAKE_CXX_COMPILER})
|
||||
set(CADICAL_CXXFLAGS "${LEAN_EXTRA_CXX_FLAGS}")
|
||||
# Use same platform flags as for Lean executables, in particular from `prepare-llvm-linux.sh`,
|
||||
# but not Lean-specific `LEAN_EXTRA_CXX_FLAGS` such as fsanitize.
|
||||
set(CADICAL_CXXFLAGS "${CMAKE_CXX_FLAGS}")
|
||||
set(CADICAL_LDFLAGS "-Wl,-rpath=\\$$ORIGIN/../lib")
|
||||
endif()
|
||||
find_program(CCACHE ccache)
|
||||
|
||||
@@ -69,6 +69,10 @@ We'll use `v4.6.0` as the intended release version as a running example.
|
||||
- `repl`:
|
||||
There are two copies of `lean-toolchain`/`lakefile.lean`:
|
||||
in the root, and in `test/Mathlib/`. Edit both, and run `lake update` in both directories.
|
||||
- `lean-fro.org`:
|
||||
After updating the toolchains and running `lake update`, you must run `scripts/update.sh` to regenerate
|
||||
the site content. This script updates generated files that depend on the Lean version.
|
||||
The `release_steps.py` script handles this automatically.
|
||||
- An awkward situation that sometimes occurs (e.g. with Verso) is that the `master`/`main` branch has already been moved
|
||||
to a nightly toolchain that comes *after* the stable toolchain we are
|
||||
targeting. In this case it is necessary to create a branch `releases/v4.6.0` from the last commit which was on
|
||||
|
||||
@@ -51,6 +51,10 @@ All these tests are included by [src/shell/CMakeLists.txt](https://github.com/le
|
||||
codes and do not check the expected output even though output is
|
||||
produced, it is ignored.
|
||||
|
||||
**Note:** Tests in this directory run with `-Dlinter.all=false` to reduce noise.
|
||||
If your test needs to verify linter behavior (e.g., deprecation warnings),
|
||||
explicitly enable the relevant linter with `set_option linter.<name> true`.
|
||||
|
||||
- [`tests/lean/interactive`](https://github.com/leanprover/lean4/tree/master/tests/lean/interactive/): are designed to test server requests at a
|
||||
given position in the input file. Each .lean file contains comments
|
||||
that indicate how to simulate a client request at that position.
|
||||
|
||||
@@ -4,6 +4,7 @@ import GroveStdlib.Generated.«associative-creation-operations»
|
||||
import GroveStdlib.Generated.«associative-modification-operations»
|
||||
import GroveStdlib.Generated.«associative-create-then-query»
|
||||
import GroveStdlib.Generated.«associative-all-operations-covered»
|
||||
import GroveStdlib.Generated.«slice-producing»
|
||||
|
||||
/-
|
||||
This file is autogenerated by grove. You can manually edit it, for example to resolve merge
|
||||
@@ -20,3 +21,4 @@ def restoreState : RestoreStateM Unit := do
|
||||
«associative-modification-operations».restoreState
|
||||
«associative-create-then-query».restoreState
|
||||
«associative-all-operations-covered».restoreState
|
||||
«slice-producing».restoreState
|
||||
|
||||
459
doc/std/grove/GroveStdlib/Generated/slice-producing.lean
generated
Normal file
459
doc/std/grove/GroveStdlib/Generated/slice-producing.lean
generated
Normal file
@@ -0,0 +1,459 @@
|
||||
import Grove.Framework
|
||||
|
||||
/-
|
||||
This file is autogenerated by grove. You can manually edit it, for example to resolve merge
|
||||
conflicts, but be careful.
|
||||
-/
|
||||
|
||||
open Grove.Framework Widget
|
||||
|
||||
namespace GroveStdlib.Generated.«slice-producing»
|
||||
|
||||
def «c8a13d6d-7ed6-4cd1-a386-23e2d55ce6f7» : AssociationTable.Fact .declaration where
|
||||
widgetId := "slice-producing"
|
||||
factId := "c8a13d6d-7ed6-4cd1-a386-23e2d55ce6f7"
|
||||
rowId := "c8a13d6d-7ed6-4cd1-a386-23e2d55ce6f7"
|
||||
rowState := #[⟨"String", "String.slice", Declaration.def {
|
||||
name := `String.slice
|
||||
renderedStatement := "String.slice (s : String) (startInclusive endExclusive : s.Pos)\n (h : startInclusive ≤ endExclusive) : String.Slice"
|
||||
isDeprecated := false
|
||||
}
|
||||
⟩,⟨"String.Slice", "String.Slice.slice", Declaration.def {
|
||||
name := `String.Slice.slice
|
||||
renderedStatement := "String.Slice.slice (s : String.Slice) (newStart newEnd : s.Pos) (h : newStart ≤ newEnd) :\n String.Slice"
|
||||
isDeprecated := false
|
||||
}
|
||||
⟩,⟨"string-pos-forwards", "String.Pos.slice", Declaration.def {
|
||||
name := `String.Pos.slice
|
||||
renderedStatement := "String.Pos.slice {s : String} (pos p₀ p₁ : s.Pos) (h₁ : p₀ ≤ pos) (h₂ : pos ≤ p₁) :\n (s.slice p₀ p₁ ⋯).Pos"
|
||||
isDeprecated := false
|
||||
}
|
||||
⟩,⟨"string-pos-backwards", "String.Pos.ofSlice", Declaration.def {
|
||||
name := `String.Pos.ofSlice
|
||||
renderedStatement := "String.Pos.ofSlice {s : String} {p₀ p₁ : s.Pos} {h : p₀ ≤ p₁} (pos : (s.slice p₀ p₁ h).Pos) : s.Pos"
|
||||
isDeprecated := false
|
||||
}
|
||||
⟩,⟨"string-slice-pos-forwards", "String.Slice.Pos.slice", Declaration.def {
|
||||
name := `String.Slice.Pos.slice
|
||||
renderedStatement := "String.Slice.Pos.slice {s : String.Slice} (pos p₀ p₁ : s.Pos) (h₁ : p₀ ≤ pos) (h₂ : pos ≤ p₁) :\n (s.slice p₀ p₁ ⋯).Pos"
|
||||
isDeprecated := false
|
||||
}
|
||||
⟩,⟨"string-slice-pos-backwards", "String.Slice.Pos.ofSlice", Declaration.def {
|
||||
name := `String.Slice.Pos.ofSlice
|
||||
renderedStatement := "String.Slice.Pos.ofSlice {s : String.Slice} {p₀ p₁ : s.Pos} {h : p₀ ≤ p₁}\n (pos : (s.slice p₀ p₁ h).Pos) : s.Pos"
|
||||
isDeprecated := false
|
||||
}
|
||||
⟩,⟨"string-pos-noproof", "String.Pos.sliceOrPanic", Declaration.def {
|
||||
name := `String.Pos.sliceOrPanic
|
||||
renderedStatement := "String.Pos.sliceOrPanic {s : String} (pos p₀ p₁ : s.Pos) {h : p₀ ≤ p₁} : (s.slice p₀ p₁ h).Pos"
|
||||
isDeprecated := false
|
||||
}
|
||||
⟩,⟨"string-slice-pos-noproof", "String.Slice.Pos.sliceOrPanic", Declaration.def {
|
||||
name := `String.Slice.Pos.sliceOrPanic
|
||||
renderedStatement := "String.Slice.Pos.sliceOrPanic {s : String.Slice} (pos p₀ p₁ : s.Pos) {h : p₀ ≤ p₁} :\n (s.slice p₀ p₁ h).Pos"
|
||||
isDeprecated := false
|
||||
}
|
||||
⟩,]
|
||||
metadata := {
|
||||
status := .done
|
||||
comment := ""
|
||||
}
|
||||
def «21b4fdfd-f8b3-44f5-a59e-57f1dc1d6819» : AssociationTable.Fact .declaration where
|
||||
widgetId := "slice-producing"
|
||||
factId := "21b4fdfd-f8b3-44f5-a59e-57f1dc1d6819"
|
||||
rowId := "21b4fdfd-f8b3-44f5-a59e-57f1dc1d6819"
|
||||
rowState := #[⟨"String", "String.slice?", Declaration.def {
|
||||
name := `String.slice?
|
||||
renderedStatement := "String.slice? (s : String) (startInclusive endExclusive : s.Pos) : Option String.Slice"
|
||||
isDeprecated := false
|
||||
}
|
||||
⟩,⟨"String.Slice", "String.Slice.slice?", Declaration.def {
|
||||
name := `String.Slice.slice?
|
||||
renderedStatement := "String.Slice.slice? (s : String.Slice) (newStart newEnd : s.Pos) : Option String.Slice"
|
||||
isDeprecated := false
|
||||
}
|
||||
⟩,]
|
||||
metadata := {
|
||||
status := .postponed
|
||||
comment := "Would be good to have better support"
|
||||
}
|
||||
def «6f2b6ecb-2f0c-4e45-9da3-eb7f2e15eff0» : AssociationTable.Fact .declaration where
|
||||
widgetId := "slice-producing"
|
||||
factId := "6f2b6ecb-2f0c-4e45-9da3-eb7f2e15eff0"
|
||||
rowId := "6f2b6ecb-2f0c-4e45-9da3-eb7f2e15eff0"
|
||||
rowState := #[⟨"String", "String.slice!", Declaration.def {
|
||||
name := `String.slice!
|
||||
renderedStatement := "String.slice! (s : String) (p₁ p₂ : s.Pos) : String.Slice"
|
||||
isDeprecated := false
|
||||
}
|
||||
⟩,⟨"String.Slice", "String.Slice.slice!", Declaration.def {
|
||||
name := `String.Slice.slice!
|
||||
renderedStatement := "String.Slice.slice! (s : String.Slice) (newStart newEnd : s.Pos) : String.Slice"
|
||||
isDeprecated := false
|
||||
}
|
||||
⟩,⟨"string-pos-forwards", "String.Pos.slice!", Declaration.def {
|
||||
name := `String.Pos.slice!
|
||||
renderedStatement := "String.Pos.slice! {s : String} (pos p₀ p₁ : s.Pos) : (s.slice! p₀ p₁).Pos"
|
||||
isDeprecated := false
|
||||
}
|
||||
⟩,⟨"string-pos-backwards", "String.Pos.ofSlice!", Declaration.def {
|
||||
name := `String.Pos.ofSlice!
|
||||
renderedStatement := "String.Pos.ofSlice! {s : String} {p₀ p₁ : s.Pos} (pos : (s.slice! p₀ p₁).Pos) : s.Pos"
|
||||
isDeprecated := false
|
||||
}
|
||||
⟩,⟨"string-slice-pos-forwards", "String.Slice.Pos.slice!", Declaration.def {
|
||||
name := `String.Slice.Pos.slice!
|
||||
renderedStatement := "String.Slice.Pos.slice! {s : String.Slice} (pos p₀ p₁ : s.Pos) : (s.slice! p₀ p₁).Pos"
|
||||
isDeprecated := false
|
||||
}
|
||||
⟩,⟨"string-slice-pos-backwards", "String.Slice.Pos.ofSlice!", Declaration.def {
|
||||
name := `String.Slice.Pos.ofSlice!
|
||||
renderedStatement := "String.Slice.Pos.ofSlice! {s : String.Slice} {p₀ p₁ : s.Pos} (pos : (s.slice! p₀ p₁).Pos) : s.Pos"
|
||||
isDeprecated := false
|
||||
}
|
||||
⟩,]
|
||||
metadata := {
|
||||
status := .done
|
||||
comment := ""
|
||||
}
|
||||
def «a3bdf66d-bc11-4019-aee9-2f1c1701de52» : AssociationTable.Fact .declaration where
|
||||
widgetId := "slice-producing"
|
||||
factId := "a3bdf66d-bc11-4019-aee9-2f1c1701de52"
|
||||
rowId := "a3bdf66d-bc11-4019-aee9-2f1c1701de52"
|
||||
rowState := #[⟨"String", "String.trimAsciiStart", Declaration.def {
|
||||
name := `String.trimAsciiStart
|
||||
renderedStatement := "String.trimAsciiStart (s : String) : String.Slice"
|
||||
isDeprecated := false
|
||||
}
|
||||
⟩,⟨"String.Slice", "String.Slice.trimAsciiStart", Declaration.def {
|
||||
name := `String.Slice.trimAsciiStart
|
||||
renderedStatement := "String.Slice.trimAsciiStart (s : String.Slice) : String.Slice"
|
||||
isDeprecated := false
|
||||
}
|
||||
⟩,]
|
||||
metadata := {
|
||||
status := .bad
|
||||
comment := "Missing `of` version at least"
|
||||
}
|
||||
def «f12b2730-7a4d-465c-8a6d-9d051c300fd5» : AssociationTable.Fact .declaration where
|
||||
widgetId := "slice-producing"
|
||||
factId := "f12b2730-7a4d-465c-8a6d-9d051c300fd5"
|
||||
rowId := "f12b2730-7a4d-465c-8a6d-9d051c300fd5"
|
||||
rowState := #[⟨"String", "String.trimAsciiEnd", Declaration.def {
|
||||
name := `String.trimAsciiEnd
|
||||
renderedStatement := "String.trimAsciiEnd (s : String) : String.Slice"
|
||||
isDeprecated := false
|
||||
}
|
||||
⟩,⟨"String.Slice", "String.Slice.trimAsciiEnd", Declaration.def {
|
||||
name := `String.Slice.trimAsciiEnd
|
||||
renderedStatement := "String.Slice.trimAsciiEnd (s : String.Slice) : String.Slice"
|
||||
isDeprecated := false
|
||||
}
|
||||
⟩,]
|
||||
metadata := {
|
||||
status := .bad
|
||||
comment := "Missing `of` version at least"
|
||||
}
|
||||
def «32307b55-d6d1-4756-a947-dbe4dfde573c» : AssociationTable.Fact .declaration where
|
||||
widgetId := "slice-producing"
|
||||
factId := "32307b55-d6d1-4756-a947-dbe4dfde573c"
|
||||
rowId := "32307b55-d6d1-4756-a947-dbe4dfde573c"
|
||||
rowState := #[⟨"String", "String.trimAscii", Declaration.def {
|
||||
name := `String.trimAscii
|
||||
renderedStatement := "String.trimAscii (s : String) : String.Slice"
|
||||
isDeprecated := false
|
||||
}
|
||||
⟩,⟨"String.Slice", "String.Slice.trimAscii", Declaration.def {
|
||||
name := `String.Slice.trimAscii
|
||||
renderedStatement := "String.Slice.trimAscii (s : String.Slice) : String.Slice"
|
||||
isDeprecated := false
|
||||
}
|
||||
⟩,]
|
||||
metadata := {
|
||||
status := .bad
|
||||
comment := "Missing `of` version at least\n"
|
||||
}
|
||||
def «dce95a38-f55a-4d6a-ae79-078ffe4b5c15» : AssociationTable.Fact .declaration where
|
||||
widgetId := "slice-producing"
|
||||
factId := "dce95a38-f55a-4d6a-ae79-078ffe4b5c15"
|
||||
rowId := "dce95a38-f55a-4d6a-ae79-078ffe4b5c15"
|
||||
rowState := #[⟨"String", "String.toSlice", Declaration.def {
|
||||
name := `String.toSlice
|
||||
renderedStatement := "String.toSlice (s : String) : String.Slice"
|
||||
isDeprecated := false
|
||||
}
|
||||
⟩,⟨"string-pos-forwards", "String.Pos.toSlice", Declaration.def {
|
||||
name := `String.Pos.toSlice
|
||||
renderedStatement := "String.Pos.toSlice {s : String} (pos : s.Pos) : s.toSlice.Pos"
|
||||
isDeprecated := false
|
||||
}
|
||||
⟩,⟨"string-pos-backwards", "String.Pos.ofToSlice", Declaration.def {
|
||||
name := `String.Pos.ofToSlice
|
||||
renderedStatement := "String.Pos.ofToSlice {s : String} (pos : s.toSlice.Pos) : s.Pos"
|
||||
isDeprecated := false
|
||||
}
|
||||
⟩,]
|
||||
metadata := {
|
||||
status := .done
|
||||
comment := ""
|
||||
}
|
||||
def «005a3f30-5dab-493f-b168-32c36a2bdf7c» : AssociationTable.Fact .declaration where
|
||||
widgetId := "slice-producing"
|
||||
factId := "005a3f30-5dab-493f-b168-32c36a2bdf7c"
|
||||
rowId := "005a3f30-5dab-493f-b168-32c36a2bdf7c"
|
||||
rowState := #[⟨"String.Slice", "String.Slice.str", Declaration.def {
|
||||
name := `String.Slice.str
|
||||
renderedStatement := "String.Slice.str (self : String.Slice) : String"
|
||||
isDeprecated := false
|
||||
}
|
||||
⟩,⟨"string-slice-pos-forwards", "String.Slice.Pos.str", Declaration.def {
|
||||
name := `String.Slice.Pos.str
|
||||
renderedStatement := "String.Slice.Pos.str {s : String.Slice} (pos : s.Pos) : s.str.Pos"
|
||||
isDeprecated := false
|
||||
}
|
||||
⟩,⟨"string-slice-pos-backwards", "String.Slice.Pos.ofStr", Declaration.def {
|
||||
name := `String.Slice.Pos.ofStr
|
||||
renderedStatement := "String.Slice.Pos.ofStr {s : String.Slice} (pos : s.str.Pos) (h₁ : s.startInclusive ≤ pos)\n (h₂ : pos ≤ s.endExclusive) : s.Pos"
|
||||
isDeprecated := false
|
||||
}
|
||||
⟩,]
|
||||
metadata := {
|
||||
status := .bad
|
||||
comment := "Missing `no proof` version\n"
|
||||
}
|
||||
def «5f1a154c-ae2f-43a1-9409-2ce95b163ef3» : AssociationTable.Fact .declaration where
|
||||
widgetId := "slice-producing"
|
||||
factId := "5f1a154c-ae2f-43a1-9409-2ce95b163ef3"
|
||||
rowId := "5f1a154c-ae2f-43a1-9409-2ce95b163ef3"
|
||||
rowState := #[⟨"String", "String.drop", Declaration.def {
|
||||
name := `String.drop
|
||||
renderedStatement := "String.drop (s : String) (n : Nat) : String.Slice"
|
||||
isDeprecated := false
|
||||
}
|
||||
⟩,⟨"String.Slice", "String.Slice.drop", Declaration.def {
|
||||
name := `String.Slice.drop
|
||||
renderedStatement := "String.Slice.drop (s : String.Slice) (n : Nat) : String.Slice"
|
||||
isDeprecated := false
|
||||
}
|
||||
⟩,]
|
||||
metadata := {
|
||||
status := .bad
|
||||
comment := "Missing position transformations"
|
||||
}
|
||||
def «179518d1-ad07-4b2b-8ffe-3b7616e4c4ab» : AssociationTable.Fact .declaration where
|
||||
widgetId := "slice-producing"
|
||||
factId := "179518d1-ad07-4b2b-8ffe-3b7616e4c4ab"
|
||||
rowId := "179518d1-ad07-4b2b-8ffe-3b7616e4c4ab"
|
||||
rowState := #[⟨"String", "String.take", Declaration.def {
|
||||
name := `String.take
|
||||
renderedStatement := "String.take (s : String) (n : Nat) : String.Slice"
|
||||
isDeprecated := false
|
||||
}
|
||||
⟩,⟨"String.Slice", "String.Slice.take", Declaration.def {
|
||||
name := `String.Slice.take
|
||||
renderedStatement := "String.Slice.take (s : String.Slice) (n : Nat) : String.Slice"
|
||||
isDeprecated := false
|
||||
}
|
||||
⟩,]
|
||||
metadata := {
|
||||
status := .bad
|
||||
comment := "Missing position transformations"
|
||||
}
|
||||
def «55c587fd-a7a8-4633-a4ae-e2c4e768ad28» : AssociationTable.Fact .declaration where
|
||||
widgetId := "slice-producing"
|
||||
factId := "55c587fd-a7a8-4633-a4ae-e2c4e768ad28"
|
||||
rowId := "55c587fd-a7a8-4633-a4ae-e2c4e768ad28"
|
||||
rowState := #[⟨"String", "String.dropWhile", Declaration.def {
|
||||
name := `String.dropWhile
|
||||
renderedStatement := "String.dropWhile {ρ : Type} (s : String) (pat : ρ) [String.Slice.Pattern.ForwardPattern pat] :\n String.Slice"
|
||||
isDeprecated := false
|
||||
}
|
||||
⟩,⟨"String.Slice", "String.Slice.dropWhile", Declaration.def {
|
||||
name := `String.Slice.dropWhile
|
||||
renderedStatement := "String.Slice.dropWhile {ρ : Type} (s : String.Slice) (pat : ρ)\n [String.Slice.Pattern.ForwardPattern pat] : String.Slice"
|
||||
isDeprecated := false
|
||||
}
|
||||
⟩,]
|
||||
metadata := {
|
||||
status := .bad
|
||||
comment := "Missing position transformations"
|
||||
}
|
||||
def «d4444684-4279-4400-9be2-561a7cdb32c1» : AssociationTable.Fact .declaration where
|
||||
widgetId := "slice-producing"
|
||||
factId := "d4444684-4279-4400-9be2-561a7cdb32c1"
|
||||
rowId := "d4444684-4279-4400-9be2-561a7cdb32c1"
|
||||
rowState := #[⟨"String", "String.takeWhile", Declaration.def {
|
||||
name := `String.takeWhile
|
||||
renderedStatement := "String.takeWhile {ρ : Type} (s : String) (pat : ρ) [String.Slice.Pattern.ForwardPattern pat] :\n String.Slice"
|
||||
isDeprecated := false
|
||||
}
|
||||
⟩,⟨"String.Slice", "String.Slice.takeWhile", Declaration.def {
|
||||
name := `String.Slice.takeWhile
|
||||
renderedStatement := "String.Slice.takeWhile {ρ : Type} (s : String.Slice) (pat : ρ)\n [String.Slice.Pattern.ForwardPattern pat] : String.Slice"
|
||||
isDeprecated := false
|
||||
}
|
||||
⟩,]
|
||||
metadata := {
|
||||
status := .bad
|
||||
comment := "Missing position transformations"
|
||||
}
|
||||
def «1c9e6689-65a0-4d4b-b001-256e83917d98» : AssociationTable.Fact .declaration where
|
||||
widgetId := "slice-producing"
|
||||
factId := "1c9e6689-65a0-4d4b-b001-256e83917d98"
|
||||
rowId := "1c9e6689-65a0-4d4b-b001-256e83917d98"
|
||||
rowState := #[⟨"String", "String.dropEndWhile", Declaration.def {
|
||||
name := `String.dropEndWhile
|
||||
renderedStatement := "String.dropEndWhile {ρ : Type} (s : String) (pat : ρ) [String.Slice.Pattern.BackwardPattern pat] :\n String.Slice"
|
||||
isDeprecated := false
|
||||
}
|
||||
⟩,⟨"String.Slice", "String.Slice.dropEndWhile", Declaration.def {
|
||||
name := `String.Slice.dropEndWhile
|
||||
renderedStatement := "String.Slice.dropEndWhile {ρ : Type} (s : String.Slice) (pat : ρ)\n [String.Slice.Pattern.BackwardPattern pat] : String.Slice"
|
||||
isDeprecated := false
|
||||
}
|
||||
⟩,]
|
||||
metadata := {
|
||||
status := .bad
|
||||
comment := "Missing position transformations"
|
||||
}
|
||||
def «b836052b-3470-4a8e-8989-6951c898de37» : AssociationTable.Fact .declaration where
|
||||
widgetId := "slice-producing"
|
||||
factId := "b836052b-3470-4a8e-8989-6951c898de37"
|
||||
rowId := "b836052b-3470-4a8e-8989-6951c898de37"
|
||||
rowState := #[⟨"String", "String.takeEndWhile", Declaration.def {
|
||||
name := `String.takeEndWhile
|
||||
renderedStatement := "String.takeEndWhile {ρ : Type} (s : String) (pat : ρ) [String.Slice.Pattern.BackwardPattern pat] :\n String.Slice"
|
||||
isDeprecated := false
|
||||
}
|
||||
⟩,⟨"String.Slice", "String.Slice.takeEndWhile", Declaration.def {
|
||||
name := `String.Slice.takeEndWhile
|
||||
renderedStatement := "String.Slice.takeEndWhile {ρ : Type} (s : String.Slice) (pat : ρ)\n [String.Slice.Pattern.BackwardPattern pat] : String.Slice"
|
||||
isDeprecated := false
|
||||
}
|
||||
⟩,]
|
||||
metadata := {
|
||||
status := .bad
|
||||
comment := "Missing position transformations"
|
||||
}
|
||||
def «5aa777d8-9642-43d8-9e20-30400fb8bb9d» : AssociationTable.Fact .declaration where
|
||||
widgetId := "slice-producing"
|
||||
factId := "5aa777d8-9642-43d8-9e20-30400fb8bb9d"
|
||||
rowId := "5aa777d8-9642-43d8-9e20-30400fb8bb9d"
|
||||
rowState := #[⟨"String", "String.dropPrefix", Declaration.def {
|
||||
name := `String.dropPrefix
|
||||
renderedStatement := "String.dropPrefix {ρ : Type} (s : String) (pat : ρ) [String.Slice.Pattern.ForwardPattern pat] :\n String.Slice"
|
||||
isDeprecated := false
|
||||
}
|
||||
⟩,⟨"String.Slice", "String.Slice.dropPrefix", Declaration.def {
|
||||
name := `String.Slice.dropPrefix
|
||||
renderedStatement := "String.Slice.dropPrefix {ρ : Type} (s : String.Slice) (pat : ρ)\n [String.Slice.Pattern.ForwardPattern pat] : String.Slice"
|
||||
isDeprecated := false
|
||||
}
|
||||
⟩,]
|
||||
metadata := {
|
||||
status := .bad
|
||||
comment := "Missing position transformations"
|
||||
}
|
||||
def «80e3869d-fcfe-459d-8433-fe221f7b3c7a» : AssociationTable.Fact .declaration where
|
||||
widgetId := "slice-producing"
|
||||
factId := "80e3869d-fcfe-459d-8433-fe221f7b3c7a"
|
||||
rowId := "80e3869d-fcfe-459d-8433-fe221f7b3c7a"
|
||||
rowState := #[⟨"String", "String.dropSuffix", Declaration.def {
|
||||
name := `String.dropSuffix
|
||||
renderedStatement := "String.dropSuffix {ρ : Type} (s : String) (pat : ρ) [String.Slice.Pattern.BackwardPattern pat] :\n String.Slice"
|
||||
isDeprecated := false
|
||||
}
|
||||
⟩,⟨"String.Slice", "String.Slice.dropSuffix", Declaration.def {
|
||||
name := `String.Slice.dropSuffix
|
||||
renderedStatement := "String.Slice.dropSuffix {ρ : Type} (s : String.Slice) (pat : ρ)\n [String.Slice.Pattern.BackwardPattern pat] : String.Slice"
|
||||
isDeprecated := false
|
||||
}
|
||||
⟩,]
|
||||
metadata := {
|
||||
status := .bad
|
||||
comment := "Missing position transformations"
|
||||
}
|
||||
def «4feda3e0-903b-4d52-b34e-0af70f7866e0» : AssociationTable.Fact .declaration where
|
||||
widgetId := "slice-producing"
|
||||
factId := "4feda3e0-903b-4d52-b34e-0af70f7866e0"
|
||||
rowId := "4feda3e0-903b-4d52-b34e-0af70f7866e0"
|
||||
rowState := #[⟨"String", "String.dropPrefix?", Declaration.def {
|
||||
name := `String.dropPrefix?
|
||||
renderedStatement := "String.dropPrefix? {ρ : Type} (s : String) (pat : ρ) [String.Slice.Pattern.ForwardPattern pat] :\n Option String.Slice"
|
||||
isDeprecated := false
|
||||
}
|
||||
⟩,⟨"String.Slice", "String.Slice.dropPrefix?", Declaration.def {
|
||||
name := `String.Slice.dropPrefix?
|
||||
renderedStatement := "String.Slice.dropPrefix? {ρ : Type} (s : String.Slice) (pat : ρ)\n [String.Slice.Pattern.ForwardPattern pat] : Option String.Slice"
|
||||
isDeprecated := false
|
||||
}
|
||||
⟩,]
|
||||
metadata := {
|
||||
status := .postponed
|
||||
comment := "Missing position transformations"
|
||||
}
|
||||
def «45ca44c8-fbd5-4400-8297-a60778f302b0» : AssociationTable.Fact .declaration where
|
||||
widgetId := "slice-producing"
|
||||
factId := "45ca44c8-fbd5-4400-8297-a60778f302b0"
|
||||
rowId := "45ca44c8-fbd5-4400-8297-a60778f302b0"
|
||||
rowState := #[⟨"String", "String.dropSuffix?", Declaration.def {
|
||||
name := `String.dropSuffix?
|
||||
renderedStatement := "String.dropSuffix? {ρ : Type} (s : String) (pat : ρ) [String.Slice.Pattern.BackwardPattern pat] :\n Option String.Slice"
|
||||
isDeprecated := false
|
||||
}
|
||||
⟩,⟨"String.Slice", "String.Slice.dropSuffix?", Declaration.def {
|
||||
name := `String.Slice.dropSuffix?
|
||||
renderedStatement := "String.Slice.dropSuffix? {ρ : Type} (s : String.Slice) (pat : ρ)\n [String.Slice.Pattern.BackwardPattern pat] : Option String.Slice"
|
||||
isDeprecated := false
|
||||
}
|
||||
⟩,]
|
||||
metadata := {
|
||||
status := .postponed
|
||||
comment := "Missing position transformations"
|
||||
}
|
||||
|
||||
def table : AssociationTable.Data .declaration where
|
||||
widgetId := "slice-producing"
|
||||
rows := #[
|
||||
⟨"c8a13d6d-7ed6-4cd1-a386-23e2d55ce6f7", "slice", #[⟨"String", "String.slice"⟩,⟨"String.Slice", "String.Slice.slice"⟩,⟨"string-pos-forwards", "String.Pos.slice"⟩,⟨"string-pos-backwards", "String.Pos.ofSlice"⟩,⟨"string-slice-pos-forwards", "String.Slice.Pos.slice"⟩,⟨"string-slice-pos-backwards", "String.Slice.Pos.ofSlice"⟩,⟨"string-pos-noproof", "String.Pos.sliceOrPanic"⟩,⟨"string-slice-pos-noproof", "String.Slice.Pos.sliceOrPanic"⟩,]⟩,
|
||||
⟨"21b4fdfd-f8b3-44f5-a59e-57f1dc1d6819", "slice?", #[⟨"String", "String.slice?"⟩,⟨"String.Slice", "String.Slice.slice?"⟩,]⟩,
|
||||
⟨"6f2b6ecb-2f0c-4e45-9da3-eb7f2e15eff0", "slice!", #[⟨"String", "String.slice!"⟩,⟨"String.Slice", "String.Slice.slice!"⟩,⟨"string-pos-forwards", "String.Pos.slice!"⟩,⟨"string-pos-backwards", "String.Pos.ofSlice!"⟩,⟨"string-slice-pos-forwards", "String.Slice.Pos.slice!"⟩,⟨"string-slice-pos-backwards", "String.Slice.Pos.ofSlice!"⟩,]⟩,
|
||||
⟨"a3bdf66d-bc11-4019-aee9-2f1c1701de52", "trimAsciiStart", #[⟨"String", "String.trimAsciiStart"⟩,⟨"String.Slice", "String.Slice.trimAsciiStart"⟩,]⟩,
|
||||
⟨"f12b2730-7a4d-465c-8a6d-9d051c300fd5", "trimAsciiEnd", #[⟨"String", "String.trimAsciiEnd"⟩,⟨"String.Slice", "String.Slice.trimAsciiEnd"⟩,]⟩,
|
||||
⟨"32307b55-d6d1-4756-a947-dbe4dfde573c", "trimAscii", #[⟨"String", "String.trimAscii"⟩,⟨"String.Slice", "String.Slice.trimAscii"⟩,]⟩,
|
||||
⟨"dce95a38-f55a-4d6a-ae79-078ffe4b5c15", "toSlice", #[⟨"String", "String.toSlice"⟩,⟨"string-pos-forwards", "String.Pos.toSlice"⟩,⟨"string-pos-backwards", "String.Pos.ofToSlice"⟩,]⟩,
|
||||
⟨"005a3f30-5dab-493f-b168-32c36a2bdf7c", "str", #[⟨"String.Slice", "String.Slice.str"⟩,⟨"string-slice-pos-forwards", "String.Slice.Pos.str"⟩,⟨"string-slice-pos-backwards", "String.Slice.Pos.ofStr"⟩,]⟩,
|
||||
⟨"5f1a154c-ae2f-43a1-9409-2ce95b163ef3", "drop", #[⟨"String", "String.drop"⟩,⟨"String.Slice", "String.Slice.drop"⟩,]⟩,
|
||||
⟨"179518d1-ad07-4b2b-8ffe-3b7616e4c4ab", "take", #[⟨"String", "String.take"⟩,⟨"String.Slice", "String.Slice.take"⟩,]⟩,
|
||||
⟨"55c587fd-a7a8-4633-a4ae-e2c4e768ad28", "dropWhile", #[⟨"String", "String.dropWhile"⟩,⟨"String.Slice", "String.Slice.dropWhile"⟩,]⟩,
|
||||
⟨"d4444684-4279-4400-9be2-561a7cdb32c1", "takeWhile", #[⟨"String", "String.takeWhile"⟩,⟨"String.Slice", "String.Slice.takeWhile"⟩,]⟩,
|
||||
⟨"1c9e6689-65a0-4d4b-b001-256e83917d98", "dropEndWhile", #[⟨"String", "String.dropEndWhile"⟩,⟨"String.Slice", "String.Slice.dropEndWhile"⟩,]⟩,
|
||||
⟨"b836052b-3470-4a8e-8989-6951c898de37", "takeEndWhile", #[⟨"String", "String.takeEndWhile"⟩,⟨"String.Slice", "String.Slice.takeEndWhile"⟩,]⟩,
|
||||
⟨"5aa777d8-9642-43d8-9e20-30400fb8bb9d", "dropPrefix", #[⟨"String", "String.dropPrefix"⟩,⟨"String.Slice", "String.Slice.dropPrefix"⟩,]⟩,
|
||||
⟨"80e3869d-fcfe-459d-8433-fe221f7b3c7a", "dropSuffix", #[⟨"String", "String.dropSuffix"⟩,⟨"String.Slice", "String.Slice.dropSuffix"⟩,]⟩,
|
||||
⟨"4feda3e0-903b-4d52-b34e-0af70f7866e0", "dropPrefix?", #[⟨"String", "String.dropPrefix?"⟩,⟨"String.Slice", "String.Slice.dropPrefix?"⟩,]⟩,
|
||||
⟨"45ca44c8-fbd5-4400-8297-a60778f302b0", "dropSuffix?", #[⟨"String", "String.dropSuffix?"⟩,⟨"String.Slice", "String.Slice.dropSuffix?"⟩,]⟩,
|
||||
]
|
||||
facts := #[
|
||||
«c8a13d6d-7ed6-4cd1-a386-23e2d55ce6f7»,
|
||||
«21b4fdfd-f8b3-44f5-a59e-57f1dc1d6819»,
|
||||
«6f2b6ecb-2f0c-4e45-9da3-eb7f2e15eff0»,
|
||||
«a3bdf66d-bc11-4019-aee9-2f1c1701de52»,
|
||||
«f12b2730-7a4d-465c-8a6d-9d051c300fd5»,
|
||||
«32307b55-d6d1-4756-a947-dbe4dfde573c»,
|
||||
«dce95a38-f55a-4d6a-ae79-078ffe4b5c15»,
|
||||
«005a3f30-5dab-493f-b168-32c36a2bdf7c»,
|
||||
«5f1a154c-ae2f-43a1-9409-2ce95b163ef3»,
|
||||
«179518d1-ad07-4b2b-8ffe-3b7616e4c4ab»,
|
||||
«55c587fd-a7a8-4633-a4ae-e2c4e768ad28»,
|
||||
«d4444684-4279-4400-9be2-561a7cdb32c1»,
|
||||
«1c9e6689-65a0-4d4b-b001-256e83917d98»,
|
||||
«b836052b-3470-4a8e-8989-6951c898de37»,
|
||||
«5aa777d8-9642-43d8-9e20-30400fb8bb9d»,
|
||||
«80e3869d-fcfe-459d-8433-fe221f7b3c7a»,
|
||||
«4feda3e0-903b-4d52-b34e-0af70f7866e0»,
|
||||
«45ca44c8-fbd5-4400-8297-a60778f302b0»,
|
||||
]
|
||||
|
||||
def restoreState : RestoreStateM Unit := do
|
||||
addAssociationTable table
|
||||
@@ -15,7 +15,7 @@ namespace GroveStdlib
|
||||
namespace Std
|
||||
|
||||
def introduction : Node :=
|
||||
.text "Welcome to the interactive Lean standard library outline!"
|
||||
.text ⟨"introduction", "Welcome to the interactive Lean standard library outline!"⟩
|
||||
|
||||
end Std
|
||||
|
||||
|
||||
@@ -11,9 +11,87 @@ namespace GroveStdlib.Std.CoreTypesAndOperations
|
||||
|
||||
namespace StringsAndFormatting
|
||||
|
||||
open Lean Meta
|
||||
|
||||
def introduction : Text where
|
||||
id := "string-introduction"
|
||||
content := Grove.Markdown.render [
|
||||
.h1 "The Lean string library",
|
||||
.text "The Lean standard library contains a fully-featured string library, centered around the types `String` and `String.Slice`.",
|
||||
.text "`String` is defined as the subtype of `ByteArray` of valid UTF-8 strings. A `String.Slice` is a `String` together with a start and end position.",
|
||||
.text "`String` is equivalent to `List Char`, but it has a more efficient runtime representation. While the logical model based on `ByteArray` is overwritten in the runtime, the runtime implementation is very similar to the logical model, with the main difference being that the length of a string in Unicode code points is cached in the runtime implementation.",
|
||||
.text "We are considering removing this feature in the future (i.e., deprecating `String.length`), as the number of UTF-8 codepoints in a string is not particularly useful, and if needed it can be computed in linear time using `s.positions.count`."
|
||||
]
|
||||
|
||||
def highLevelStringTypes : List Lean.Name :=
|
||||
[`String, `String.Slice, `String.Pos, `String.Slice.Pos]
|
||||
|
||||
def creatingStringsAndSlices : Text where
|
||||
id := "transforming-strings-and-slices"
|
||||
content := Grove.Markdown.render [
|
||||
.h2 "Transforming strings and slices",
|
||||
.text "The Lean standard library contains a number of functions that take one or more strings and slices and return a string or a slice.",
|
||||
.text "If possible, these functions should avoid allocating a new string, and return a slice of their input(s) instead.",
|
||||
.text "Usually, for every operation `f`, there will be functions `String.f` and `String.Slice.f`, where `String.f s` is defined as `String.Slice.f s.toSlice`.",
|
||||
.text "In particular, functions that transform strings and slices should live in the `String` and `String.Slice` namespaces even if they involve a `String.Pos`/`String.Slice.Pos` (like `String.sliceTo`), for reasons that will become clear shortly.",
|
||||
|
||||
.h3 "Transforming positions",
|
||||
.text "Since positions on strings and slices are dependent on the string or slice, whenever users transform a string/slice, they will be interested in interpreting positions on the original string/slice as positions on the result, or vice versa.",
|
||||
.text "Consequently, every operation that transforms a string or slice should come with a corresponding set of transformations between positions, usually in both directions, possibly with one of the directions being conditional.",
|
||||
.text "For example, given a string `s` and a position `p` on `s`, we have the slice `s.sliceFrom p`, which is the slice from `p` to the end of `s`. A position on `s.sliceFrom p` can always be interpreted as a position on `s`. This is the \"backwards\" transformation. Conversely, a position `q` on `s` can be interpreted as a position on `s.sliceFrom p` as long as `p ≤ q`. This is the conditional forwards direction.",
|
||||
.text "The convention for naming these transformations is that the forwards transformation should have the same name as the transformation on strings/slices, but it should be located in the `String.Pos` or `String.Slice.Pos` namespace, depending on the type of the starting position (so that dot notation is possible for the forward direction). The backwards transformation should have the same name as the operation on strings/slices, but with an `of` prefix, and live in the same namespace as the forwards transformation (so in general dot notation will not be available).",
|
||||
.text "So, in the `sliceFrom` example, the forward direction would be called `String.Pos.sliceFrom`, while the backwards direction should be called `String.Pos.ofSliceFrom` (not `String.Slice.Pos.ofSliceFrom`).",
|
||||
.text "If one of the directions is conditional, it should have a corresponding panicking operation that does not require a proof; in our example this would be `String.Pos.sliceFrom!`.",
|
||||
.text "Sometimes there is a name clash for the panicking operations if the operation on strings is already panicking. For example, there are both `String.slice` and `String.slice!`. If the original operation is already panicking, we only provide panicking transformation operations. But now `String.Pos.slice!` could refer both to the panicking forwards transformation associated with `String.slice`, and also to the (only) forwards transformation associated with `String.slice!`. In this situation, we use an `orPanic` suffix to disambiguate. So the panicking forwards operation associated with `String.slice` is called `String.Pos.sliceOrPanic`, and the forwards operation associated with `String.slice!` is called `String.Pos.slice!`."
|
||||
]
|
||||
|
||||
-- TODO: also include the `HAppend` instance(s)
|
||||
def sliceProducing : AssociationTable (β := Alias Lean.Name) .declaration
|
||||
[`String, `String.Slice,
|
||||
Alias.mk `String.Pos "string-pos-forwards" "String.Pos (forwards)",
|
||||
Alias.mk `String.Pos "string-pos-backwards" "String.Pos (backwards)",
|
||||
Alias.mk `String.Pos "string-pos-noproof" "String.Pos (no proof)",
|
||||
Alias.mk `String.Slice.Pos "string-slice-pos-forwards" "String.Slice.Pos (forwards)",
|
||||
Alias.mk `String.Slice.Pos "string-slice-pos-backwards" "String.Slice.Pos (backwards)",
|
||||
Alias.mk `String.Slice.Pos "string-slice-pos-noproof" "String.Slice.Pos (no proof)"] where
|
||||
id := "slice-producing"
|
||||
title := "String functions returning strings or slices"
|
||||
description := "Operations on strings and string slices that themselves return a new string slice."
|
||||
dataSources n := DataSource.definitionsInNamespace n.inner
|
||||
|
||||
def sliceProducingComplete : Assertion where
|
||||
widgetId := "slice-producing-complete"
|
||||
title := "Slice-producing table is complete"
|
||||
description := "All functions in the `String.**` namespace that return a string or a slice are covered in the table"
|
||||
check := do
|
||||
let mut ans := #[]
|
||||
let covered := Std.HashSet.ofArray (← valuesInAssociationTable sliceProducing)
|
||||
let pred : DataSource.DeclarationPredicate :=
|
||||
DataSource.DeclarationPredicate.all [.isDefinition, .not .isDeprecated,
|
||||
.notInNamespace `String.Pos.Raw, .notInNamespace `String.Legacy,
|
||||
.not .isInstance]
|
||||
let env ← getEnv
|
||||
for name in ← declarationsMatching `String pred do
|
||||
let some c := env.find? name | continue
|
||||
if c.type.getForallBody.getUsedConstants.any (fun n => n == ``String || n == ``String.Slice) then
|
||||
let success : Bool := name.toString ∈ covered
|
||||
ans := ans.push {
|
||||
assertionId := name.toString
|
||||
description := s!"`{name}` should appear in the table."
|
||||
passed := success
|
||||
message := s!"`{name}` was{if success then "" else " not"} found in the table."
|
||||
}
|
||||
return ans
|
||||
|
||||
end StringsAndFormatting
|
||||
|
||||
def stringsAndFormatting : Node :=
|
||||
.section "strings-and-formatting" "Strings and formatting" #[]
|
||||
open StringsAndFormatting
|
||||
|
||||
end GroveStdlib.Std.CoreTypesAndOperations
|
||||
def stringsAndFormatting : Node :=
|
||||
.section "strings-and-formatting" "Strings and formatting"
|
||||
#[.text introduction,
|
||||
.text creatingStringsAndSlices,
|
||||
.associationTable sliceProducing,
|
||||
.assertion sliceProducingComplete]
|
||||
|
||||
end GroveStdlib.Std.CoreTypesAndOperations
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
"type": "git",
|
||||
"subDir": "backend",
|
||||
"scope": "",
|
||||
"rev": "3e8aabdea58c11813c5d3b7eeb187ded44ee9a34",
|
||||
"rev": "c580a425c9b7fa2aebaec2a1d8de16b2e2283c40",
|
||||
"name": "grove",
|
||||
"manifestFile": "lake-manifest.json",
|
||||
"inputRev": "master",
|
||||
@@ -15,10 +15,10 @@
|
||||
"type": "git",
|
||||
"subDir": null,
|
||||
"scope": "leanprover",
|
||||
"rev": "1604206fcd0462da9a241beeac0e2df471647435",
|
||||
"rev": "d9fc8ae23024be37424a189982c92356e37935c8",
|
||||
"name": "Cli",
|
||||
"manifestFile": "lake-manifest.json",
|
||||
"inputRev": "main",
|
||||
"inputRev": "nightly-testing",
|
||||
"inherited": true,
|
||||
"configFile": "lakefile.toml"}],
|
||||
"name": "grovestdlib",
|
||||
|
||||
@@ -3,16 +3,21 @@ Copyright (c) 2023 Mario Carneiro. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Mario Carneiro, Sebastian Ullrich
|
||||
-/
|
||||
import Lake.CLI.Main
|
||||
module
|
||||
|
||||
import Lean.Environment
|
||||
import Lean.ExtraModUses
|
||||
|
||||
/-! # `lake exe shake` command
|
||||
import Lake.CLI.Main
|
||||
import Lean.Parser.Module
|
||||
import Lake.Load.Workspace
|
||||
|
||||
/-! # Shake: A Lean import minimizer
|
||||
|
||||
This command will check the current project (or a specified target module) and all dependencies for
|
||||
unused imports. This works by looking at generated `.olean` files to deduce required imports and
|
||||
ensuring that every import is used to contribute some constant or other elaboration dependency
|
||||
recorded by `recordExtraModUse`. Because recompilation is not needed this is quite fast (about 8
|
||||
seconds to check `Mathlib` and all dependencies).
|
||||
recorded by `recordExtraModUse` and friends.
|
||||
-/
|
||||
|
||||
/-- help string for the command line interface -/
|
||||
@@ -28,13 +33,83 @@ Options:
|
||||
--force
|
||||
Skips the `lake build --no-build` sanity check
|
||||
|
||||
--keep-implied
|
||||
Preserves existing imports that are implied by other imports and thus not technically needed
|
||||
anymore
|
||||
|
||||
--keep-prefix
|
||||
If an import `X` would be replaced in favor of a more specific import `X.Y...` it implies,
|
||||
preserves the original import instead. More generally, prefers inserting `import X` even if it
|
||||
was not part of the original imports as long as it was in the original transitive import closure
|
||||
of the current module.
|
||||
|
||||
--keep-public
|
||||
Preserves all `public` imports to avoid breaking changes for external downstream modules
|
||||
|
||||
--add-public
|
||||
Adds new imports as `public` if they have been in the original public closure of that module.
|
||||
In other words, public imports will not be removed from a module unless they are unused even
|
||||
in the private scope, and those that are removed will be re-added as `public` in downstream
|
||||
modules even if only needed in the private scope there. Unlike `--keep-public`, this may
|
||||
introduce breaking changes but will still limit the number of inserted imports.
|
||||
|
||||
--explain
|
||||
Gives constants explaining why each module is needed
|
||||
|
||||
--fix
|
||||
Apply the suggested fixes directly. Make sure you have a clean checkout
|
||||
before running this, so you can review the changes.
|
||||
|
||||
--gh-style
|
||||
Outputs messages that can be parsed by `gh-problem-matcher-wrap`
|
||||
|
||||
Annotations:
|
||||
The following annotations can be added to Lean files in order to configure the behavior of
|
||||
`shake`. Only the substring `shake: ` directly followed by a directive is checked for, so multiple
|
||||
directives can be mixed in one line such as `-- shake: keep-downstream, shake: keep-all`, and they
|
||||
can be surrounded by arbitrary comments such as `-- shake: keep (metaprogram output dependency)`.
|
||||
|
||||
* `module -- shake: keep-downstream`:
|
||||
Preserves this module in all (current) downstream modules, adding new imports of it if needed.
|
||||
|
||||
* `module -- shake: keep-all`:
|
||||
Preserves all existing imports in this module as is. New imports now needed because of upstream
|
||||
changes may still be added.
|
||||
|
||||
* `import X -- shake: keep`:
|
||||
Preserves this specific import in the current module. The most common use case is to preserve a
|
||||
public import that will be needed in downstream modules to make sense of the output of a
|
||||
metaprogram defined in this module. For example, if a tactic is defined that may synthesize a
|
||||
reference to a theorem when run, there is no way for `shake` to detect this by itself and the
|
||||
module of that theorem should be publicly imported and annotated with `keep` in the tactic's
|
||||
module.
|
||||
```
|
||||
public import X -- shake: keep (metaprogram output dependency)
|
||||
|
||||
...
|
||||
|
||||
elab \"my_tactic\" : tactic => do
|
||||
... mkConst ``f -- `f`, defined in `X`, may appear in the output of this tactic
|
||||
```
|
||||
"
|
||||
|
||||
open Lean
|
||||
|
||||
/-- The parsed CLI arguments. See `help` for more information -/
|
||||
structure Args where
|
||||
help : Bool := false
|
||||
keepImplied : Bool := false
|
||||
keepPrefix : Bool := false
|
||||
keepPublic : Bool := false
|
||||
addPublic : Bool := false
|
||||
force : Bool := false
|
||||
githubStyle : Bool := false
|
||||
explain : Bool := false
|
||||
trace : Bool := false
|
||||
fix : Bool := false
|
||||
/-- `<MODULE>..`: the list of root modules to check -/
|
||||
mods : Array Name := #[]
|
||||
|
||||
/-- We use `Nat` as a bitset for doing efficient set operations.
|
||||
The bit indexes will usually be a module index. -/
|
||||
structure Bitset where
|
||||
@@ -88,7 +163,7 @@ def ofImport : Lean.Import → NeedsKind
|
||||
|
||||
end NeedsKind
|
||||
|
||||
/-- Logically, a map `NeedsKind → Bitset`. -/
|
||||
/-- Logically, a map `NeedsKind → Set ModuleIdx`, or `Set Import`. -/
|
||||
structure Needs where
|
||||
pub : Bitset
|
||||
priv : Bitset
|
||||
@@ -124,6 +199,20 @@ def Needs.union (needs : Needs) (k : NeedsKind) (s : Bitset) : Needs :=
|
||||
def Needs.sub (needs : Needs) (k : NeedsKind) (s : Bitset) : Needs :=
|
||||
needs.modify k (fun s' => s' ^^^ (s' ∩ s))
|
||||
|
||||
instance : Union Needs where
|
||||
union a b := {
|
||||
pub := a.pub ∪ b.pub
|
||||
priv := a.priv ∪ b.priv
|
||||
metaPub := a.metaPub ∪ b.metaPub
|
||||
metaPriv := a.metaPriv ∪ b.metaPriv }
|
||||
|
||||
/-- The list of edits that will be applied in `--fix`. `edits[i] = (removed, added)` where:
|
||||
|
||||
* If `j ∈ removed` then we want to delete module named `j` from the imports of `i`
|
||||
* If `j ∈ added` then we want to add module index `j` to the imports of `i`.
|
||||
-/
|
||||
abbrev Edits := Std.HashMap Name (Array Import × Array Import)
|
||||
|
||||
/-- The main state of the checker, containing information on all loaded modules. -/
|
||||
structure State where
|
||||
env : Environment
|
||||
@@ -143,6 +232,10 @@ structure State where
|
||||
changes to upstream headers.
|
||||
-/
|
||||
transDepsOrig : Array Needs := #[]
|
||||
/-- Modules that should always be preserved downstream. -/
|
||||
preserve : Needs := default
|
||||
/-- Edits to be applied to the module imports. -/
|
||||
edits : Edits := {}
|
||||
|
||||
def State.mods (s : State) := s.env.header.moduleData
|
||||
def State.modNames (s : State) := s.env.header.moduleNames
|
||||
@@ -185,13 +278,36 @@ def addTransitiveImps (transImps : Needs) (imp : Import) (j : Nat) (impTransImps
|
||||
|
||||
transImps
|
||||
|
||||
def isDeclMeta' (env : Environment) (declName : Name) : Bool :=
|
||||
-- Matchers are not compiled by themselves but inlined by the compiler, so there is no IR decl
|
||||
-- to be tagged as `meta`.
|
||||
-- TODO: It would be better to base the entire `meta` inference on the IR only and consider module
|
||||
-- references from any other context as compatible with both phases.
|
||||
let inferFor :=
|
||||
if declName.isStr && (declName.getString!.startsWith "match_" || declName.getString! == "_unsafe_rec") then declName.getPrefix else declName
|
||||
isDeclMeta env inferFor
|
||||
|
||||
/--
|
||||
Given an `Expr` reference, returns the declaration name that should be considered the reference, if
|
||||
any.
|
||||
-/
|
||||
def getDepConstName? (env : Environment) (ref : Name) : Option Name := do
|
||||
-- Ignore references to reserved names, they can be re-generated in-place
|
||||
guard <| !isReservedName env ref
|
||||
-- `_simp_...` constants are similar, use base decl instead
|
||||
return if ref.isStr && ref.getString!.startsWith "_simp_" then
|
||||
ref.getPrefix
|
||||
else
|
||||
ref
|
||||
|
||||
/-- Calculates the needs for a given module `mod` from constants and recorded extra uses. -/
|
||||
def calcNeeds (env : Environment) (i : ModuleIdx) : Needs := Id.run do
|
||||
def calcNeeds (s : State) (i : ModuleIdx) : Needs := Id.run do
|
||||
let env := s.env
|
||||
let mut needs := default
|
||||
for ci in env.header.moduleData[i]!.constants do
|
||||
-- Added guard for cases like `structure` that are still exported even if private
|
||||
let pubCI? := guard (!isPrivateName ci.name) *> (env.setExporting true).find? ci.name
|
||||
let k := { isExported := pubCI?.isSome, isMeta := isMeta env ci.name }
|
||||
let k := { isExported := pubCI?.isSome, isMeta := isDeclMeta' env ci.name }
|
||||
needs := visitExpr k ci.type needs
|
||||
if let some e := ci.value? (allowOpaque := true) then
|
||||
-- type and value has identical visibility under `meta`
|
||||
@@ -206,12 +322,19 @@ def calcNeeds (env : Environment) (i : ModuleIdx) : Needs := Id.run do
|
||||
return needs
|
||||
where
|
||||
/-- Accumulate the results from expression `e` into `deps`. -/
|
||||
visitExpr (k : NeedsKind) e deps :=
|
||||
Lean.Expr.foldConsts e deps fun c deps => match env.getModuleIdxFor? c with
|
||||
| some j =>
|
||||
let k := { k with isMeta := k.isMeta && !isMeta env c }
|
||||
if j != i then deps.union k {j} else deps
|
||||
| _ => deps
|
||||
visitExpr (k : NeedsKind) (e : Expr) (deps : Needs) : Needs :=
|
||||
let env := s.env
|
||||
Lean.Expr.foldConsts e deps fun c deps => Id.run do
|
||||
let mut deps := deps
|
||||
if let some c := getDepConstName? env c then
|
||||
if let some j := env.getModuleIdxFor? c then
|
||||
let k := { k with isMeta := k.isMeta && !isDeclMeta' env c }
|
||||
if j != i then
|
||||
deps := deps.union k {j}
|
||||
for indMod in (indirectModUseExt.getState env)[c]?.getD #[] do
|
||||
if s.transDeps[i]!.has k indMod then
|
||||
deps := deps.union k {indMod}
|
||||
return deps
|
||||
|
||||
/--
|
||||
Calculates the same as `calcNeeds` but tracing each module to a use-def declaration pair or
|
||||
@@ -223,7 +346,7 @@ def getExplanations (env : Environment) (i : ModuleIdx) :
|
||||
for ci in env.header.moduleData[i]!.constants do
|
||||
-- Added guard for cases like `structure` that are still exported even if private
|
||||
let pubCI? := guard (!isPrivateName ci.name) *> (env.setExporting true).find? ci.name
|
||||
let k := { isExported := pubCI?.isSome, isMeta := isMeta env ci.name }
|
||||
let k := { isExported := pubCI?.isSome, isMeta := isDeclMeta' env ci.name }
|
||||
deps := visitExpr k ci.name ci.type deps
|
||||
if let some e := ci.value? (allowOpaque := true) then
|
||||
let k := if k.isMeta then k else
|
||||
@@ -239,18 +362,18 @@ def getExplanations (env : Environment) (i : ModuleIdx) :
|
||||
where
|
||||
/-- Accumulate the results from expression `e` into `deps`. -/
|
||||
visitExpr (k : NeedsKind) name e deps :=
|
||||
Lean.Expr.foldConsts e deps fun c deps => match env.getModuleIdxFor? c with
|
||||
| some i =>
|
||||
let k := { k with isMeta := k.isMeta && !isMeta env c }
|
||||
if
|
||||
if let some (some (name', _)) := deps[(i, k)]? then
|
||||
decide (name.toString.length < name'.toString.length)
|
||||
else true
|
||||
then
|
||||
deps.insert (i, k) (name, c)
|
||||
else
|
||||
deps
|
||||
| _ => deps
|
||||
Lean.Expr.foldConsts e deps fun c deps => Id.run do
|
||||
let mut deps := deps
|
||||
if let some c := getDepConstName? env c then
|
||||
if let some j := env.getModuleIdxFor? c then
|
||||
let k := { k with isMeta := k.isMeta && !isDeclMeta' env c }
|
||||
if
|
||||
if let some (some (name', _)) := deps[(j, k)]? then
|
||||
decide (name.toString.length < name'.toString.length)
|
||||
else true
|
||||
then
|
||||
deps := deps.insert (j, k) (name, c)
|
||||
return deps
|
||||
|
||||
partial def initStateFromEnv (env : Environment) : State := Id.run do
|
||||
let mut s := { env }
|
||||
@@ -266,13 +389,6 @@ partial def initStateFromEnv (env : Environment) : State := Id.run do
|
||||
s := { s with transDepsOrig := s.transDeps }
|
||||
return s
|
||||
|
||||
/-- The list of edits that will be applied in `--fix`. `edits[i] = (removed, added)` where:
|
||||
|
||||
* If `j ∈ removed` then we want to delete module named `j` from the imports of `i`
|
||||
* If `j ∈ added` then we want to add module index `j` to the imports of `i`.
|
||||
-/
|
||||
abbrev Edits := Std.HashMap Name (Array Import × Array Import)
|
||||
|
||||
/-- Register that we want to remove `tgt` from the imports of `src`. -/
|
||||
def Edits.remove (ed : Edits) (src : Name) (tgt : Import) : Edits :=
|
||||
match ed.get? src with
|
||||
@@ -291,8 +407,8 @@ Returns `(path, inputCtx, imports, endPos)` where `imports` is the `Lean.Parser.
|
||||
and `endPos` is the position of the end of the header.
|
||||
-/
|
||||
def parseHeaderFromString (text path : String) :
|
||||
IO (System.FilePath × Parser.InputContext ×
|
||||
TSyntax ``Parser.Module.header × String.Pos.Raw) := do
|
||||
IO (System.FilePath × (ictx : Parser.InputContext) ×
|
||||
TSyntax ``Parser.Module.header × String.Pos ictx.fileMap.source) := do
|
||||
let inputCtx := Parser.mkInputContext text path
|
||||
let (header, parserState, msgs) ← Parser.parseHeader inputCtx
|
||||
if !msgs.toList.isEmpty then -- skip this file if there are parse errors
|
||||
@@ -300,8 +416,8 @@ def parseHeaderFromString (text path : String) :
|
||||
throw <| .userError "parse errors in file"
|
||||
-- the insertion point for `add` is the first newline after the imports
|
||||
let insertion := header.raw.getTailPos?.getD parserState.pos
|
||||
let insertion := text.findAux (· == '\n') text.rawEndPos insertion + '\n'
|
||||
pure (path, inputCtx, header, insertion)
|
||||
let insertion := inputCtx.fileMap.source.pos! insertion |>.find (· == '\n') |>.next!
|
||||
pure ⟨path, inputCtx, header, insertion⟩
|
||||
|
||||
/-- Parse a source file to extract the location of the import lines, for edits and error messages.
|
||||
|
||||
@@ -309,8 +425,8 @@ Returns `(path, inputCtx, imports, endPos)` where `imports` is the `Lean.Parser.
|
||||
and `endPos` is the position of the end of the header.
|
||||
-/
|
||||
def parseHeader (srcSearchPath : SearchPath) (mod : Name) :
|
||||
IO (System.FilePath × Parser.InputContext ×
|
||||
TSyntax ``Parser.Module.header × String.Pos.Raw) := do
|
||||
IO (System.FilePath × (ictx : Parser.InputContext) ×
|
||||
TSyntax ``Parser.Module.header × String.Pos ictx.fileMap.source) := do
|
||||
-- Parse the input file
|
||||
let some path ← srcSearchPath.findModuleWithExt "lean" mod
|
||||
| throw <| .userError s!"error: failed to find source file for {mod}"
|
||||
@@ -320,7 +436,7 @@ def parseHeader (srcSearchPath : SearchPath) (mod : Name) :
|
||||
def decodeHeader : TSyntax ``Parser.Module.header → Option (TSyntax `module) × Option (TSyntax `prelude) × TSyntaxArray ``Parser.Module.import
|
||||
| `(Parser.Module.header| $[module%$moduleTk?]? $[prelude%$preludeTk?]? $imports*) =>
|
||||
(moduleTk?.map .mk, preludeTk?.map .mk, imports)
|
||||
| _ => unreachable!
|
||||
| stx => panic! s!"unexpected header syntax {stx}"
|
||||
|
||||
def decodeImport : TSyntax ``Parser.Module.import → Import
|
||||
| `(Parser.Module.import| $[public%$pubTk?]? $[meta%$metaTk?]? import $[all%$allTk?]? $id) =>
|
||||
@@ -329,73 +445,174 @@ def decodeImport : TSyntax ``Parser.Module.import → Import
|
||||
|
||||
/-- Analyze and report issues from module `i`. Arguments:
|
||||
|
||||
* `pkg`: the first component of the module name
|
||||
* `srcSearchPath`: Used to find the path for error reporting purposes
|
||||
* `i`: the module index
|
||||
* `needs`: the module's calculated needs
|
||||
* `pinned`: dependencies that should be preserved even if unused
|
||||
* `edits`: accumulates the list of edits to apply if `--fix` is true
|
||||
* `addOnly`: if true, only add missing imports, do not remove unused ones
|
||||
-/
|
||||
def visitModule (srcSearchPath : SearchPath)
|
||||
(i : Nat) (needs : Needs) (preserve : Needs) (edits : Edits) (headerStx : TSyntax ``Parser.Module.header)
|
||||
(addOnly := false) (githubStyle := false) (explain := false) : StateT State IO Edits := do
|
||||
def visitModule (pkg : Name) (srcSearchPath : SearchPath)
|
||||
(i : Nat) (needs : Needs) (headerStx : TSyntax ``Parser.Module.header) (args : Args)
|
||||
(addOnly := false) : StateT State IO Unit := do
|
||||
if isExtraRevModUse (← get).env i then
|
||||
modify fun s => { s with preserve := s.preserve.union (if args.addPublic then .pub else .priv) {i} }
|
||||
if args.trace then
|
||||
IO.eprintln s!"Preserving `{(← get).modNames[i]!}` because of recorded extra rev use"
|
||||
|
||||
-- only process modules in the selected package
|
||||
-- TODO: should be after `keep-downstream` but core headers are not found yet?
|
||||
if !pkg.isPrefixOf (← get).modNames[i]! then
|
||||
return
|
||||
|
||||
let (module?, prelude?, imports) := decodeHeader headerStx
|
||||
if module?.any (·.raw.getTrailing?.any (·.toString.contains "shake: keep-downstream")) then
|
||||
modify fun s => { s with preserve := s.preserve.union (if args.addPublic then .pub else .priv) {i} }
|
||||
|
||||
let s ← get
|
||||
-- Do transitive reduction of `needs` in `deps`.
|
||||
|
||||
let addOnly := addOnly || module?.any (·.raw.getTrailing?.any (·.toString.contains "shake: keep-all"))
|
||||
let mut deps := needs
|
||||
let (_, prelude?, imports) := decodeHeader headerStx
|
||||
|
||||
-- Add additional preserved imports
|
||||
for impStx in imports do
|
||||
let imp := decodeImport impStx
|
||||
let j := s.env.getModuleIdx? imp.module |>.get!
|
||||
let k := NeedsKind.ofImport imp
|
||||
if addOnly ||
|
||||
args.keepPublic && imp.isExported ||
|
||||
impStx.raw.getTrailing?.any (·.toString.contains "shake: keep") then
|
||||
deps := deps.union k {j}
|
||||
if args.trace then
|
||||
IO.eprintln s!"Adding `{imp}` as additional dependency"
|
||||
for j in [0:s.mods.size] do
|
||||
for k in NeedsKind.all do
|
||||
-- Remove `meta` while preserving, no use-case for preserving `meta` so far.
|
||||
-- Downgrade to private unless `--add-public` is used.
|
||||
if s.transDepsOrig[i]!.has k j &&
|
||||
(s.preserve.has { k with isMeta := false, isExported := false } j ||
|
||||
s.preserve.has { k with isMeta := false, isExported := true } j) then
|
||||
deps := deps.union { k with isMeta := false, isExported := k.isExported && args.addPublic } {j}
|
||||
|
||||
-- Do transitive reduction of `needs` in `deps`.
|
||||
if !addOnly then
|
||||
for j in [0:s.mods.size] do
|
||||
let transDeps := s.transDeps[j]!
|
||||
for k in NeedsKind.all do
|
||||
if deps.has k j then
|
||||
let transDeps := addTransitiveImps .empty { k with module := .anonymous } j transDeps
|
||||
for k' in NeedsKind.all do
|
||||
deps := deps.sub k' (transDeps.sub k' {j} |>.get k')
|
||||
|
||||
if prelude?.isNone then
|
||||
deps := deps.union .pub {s.env.getModuleIdx? `Init |>.get!}
|
||||
for imp in imports do
|
||||
if addOnly || imp.raw.getTrailing?.any (·.toString.toSlice.contains "shake: keep") then
|
||||
let imp := decodeImport imp
|
||||
let j := s.env.getModuleIdx? imp.module |>.get!
|
||||
let k := NeedsKind.ofImport imp
|
||||
deps := deps.union k {j}
|
||||
for j in [0:s.mods.size] do
|
||||
let transDeps := s.transDeps[j]!
|
||||
for k in NeedsKind.all do
|
||||
if s.transDepsOrig[i]!.has k j && preserve.has k j then
|
||||
deps := deps.union k {j}
|
||||
if deps.has k j then
|
||||
let transDeps := addTransitiveImps .empty { k with module := .anonymous } j transDeps
|
||||
for k' in NeedsKind.all do
|
||||
deps := deps.sub k' (transDeps.sub k' {j} |>.get k')
|
||||
|
||||
-- Any import which is not in `transDeps` was unused.
|
||||
-- Also accumulate `newDeps` which is the transitive closure of the remaining imports
|
||||
let mut toRemove : Array Import := #[]
|
||||
let mut newDeps := Needs.empty
|
||||
-- Accumulate `transDeps` which is the non-reflexive transitive closure of the still-live imports
|
||||
let mut transDeps := Needs.empty
|
||||
let mut alwaysAdd : Array Import := #[] -- to be added even if implied by other imports
|
||||
for imp in s.mods[i]!.imports do
|
||||
let j := s.env.getModuleIdx? imp.module |>.get!
|
||||
if
|
||||
-- skip folder-nested imports
|
||||
s.modNames[i]!.isPrefixOf imp.module ||
|
||||
imp.importAll then
|
||||
newDeps := addTransitiveImps newDeps imp j s.transDeps[j]!
|
||||
else
|
||||
let k := NeedsKind.ofImport imp
|
||||
-- A private import should also be removed if the public version is needed
|
||||
if !deps.has k j || !k.isExported && deps.has { k with isExported := true } j then
|
||||
toRemove := toRemove.push imp
|
||||
else
|
||||
newDeps := addTransitiveImps newDeps imp j s.transDeps[j]!
|
||||
let k := NeedsKind.ofImport imp
|
||||
if deps.has k j || imp.importAll then
|
||||
transDeps := addTransitiveImps transDeps imp j s.transDeps[j]!
|
||||
deps := deps.union k {j}
|
||||
-- skip folder-nested `public (meta)? import`s but remove `meta`
|
||||
else if s.modNames[i]!.isPrefixOf imp.module then
|
||||
let imp := { imp with isMeta := false }
|
||||
let k := { k with isMeta := false }
|
||||
if args.trace then
|
||||
IO.eprintln s!"`{imp}` is preserved as folder-nested import"
|
||||
transDeps := addTransitiveImps transDeps imp j s.transDeps[j]!
|
||||
deps := deps.union k {j}
|
||||
if !s.mods[i]!.imports.contains imp then
|
||||
alwaysAdd := alwaysAdd.push imp
|
||||
|
||||
-- If `newDeps` does not cover `deps`, then we have to add back some imports until it does.
|
||||
-- If `transDeps` does not cover `deps`, then we have to add back some imports until it does.
|
||||
-- To minimize new imports we pick only new imports which are not transitively implied by
|
||||
-- another new import
|
||||
-- another new import, so we visit module indices in descending order.
|
||||
let mut keptPrefix := false
|
||||
let mut newTransDeps := transDeps
|
||||
let mut toAdd : Array Import := #[]
|
||||
for j in [0:s.mods.size] do
|
||||
for j in (0...s.mods.size).toArray.reverse do
|
||||
for k in NeedsKind.all do
|
||||
if deps.has k j && !newDeps.has k j && !newDeps.has { k with isExported := true } j then
|
||||
let imp := { k with module := s.modNames[j]! }
|
||||
toAdd := toAdd.push imp
|
||||
newDeps := addTransitiveImps newDeps imp j s.transDeps[j]!
|
||||
if deps.has k j && !newTransDeps.has k j && !newTransDeps.has { k with isExported := true } j then
|
||||
-- `add-public/keep-prefix` may change the import and even module we're considering
|
||||
let mut k := k
|
||||
let mut imp : Import := { k with module := s.modNames[j]! }
|
||||
let mut j := j
|
||||
if args.trace then
|
||||
IO.eprintln s!"`{imp}` is needed"
|
||||
if args.addPublic && !k.isExported &&
|
||||
-- also add as public if previously `public meta`, which could be from automatic porting
|
||||
(s.transDepsOrig[i]!.has { k with isExported := true } j || s.transDepsOrig[i]!.has { k with isExported := true, isMeta := true } j) then
|
||||
k := { k with isExported := true }
|
||||
imp := { imp with isExported := true }
|
||||
if args.trace then
|
||||
IO.eprintln s!"* upgrading to `{imp}` because of `--add-public`"
|
||||
if args.keepPrefix then
|
||||
let rec tryPrefix : Name → Option ModuleIdx
|
||||
| .str p _ => tryPrefix p <|> (do
|
||||
let j' ← s.env.getModuleIdx? p
|
||||
-- `j'` must be reachable from `i` (allow downgrading from `meta`)
|
||||
guard <| s.transDepsOrig[i]!.has k j' || s.transDepsOrig[i]!.has { k with isMeta := true } j'
|
||||
let j'transDeps := addTransitiveImps .empty p j' s.transDeps[j']!
|
||||
-- `j` must be reachable from `j'` (now downgrading must be done in the other direction)
|
||||
guard <| j'transDeps.has k j || j'transDeps.has { k with isMeta := false } j
|
||||
return j')
|
||||
| _ => none
|
||||
if let some j' := tryPrefix imp.module then
|
||||
imp := { imp with module := s.modNames[j']! }
|
||||
j := j'
|
||||
keptPrefix := true
|
||||
if args.trace then
|
||||
IO.eprintln s!"* upgrading to `{imp}` because of `--keep-prefix`"
|
||||
if !s.mods[i]!.imports.contains imp then
|
||||
toAdd := toAdd.push imp
|
||||
deps := deps.union k {j}
|
||||
newTransDeps := addTransitiveImps newTransDeps imp j s.transDeps[j]!
|
||||
|
||||
if keptPrefix then
|
||||
-- if an import was replaced by `--keep-prefix`, we did not necessarily visit the modules in
|
||||
-- dependency order anymore and so we have to redo the transitive closure checking
|
||||
newTransDeps := transDeps
|
||||
for j in (0...s.mods.size).toArray.reverse do
|
||||
for k in NeedsKind.all do
|
||||
if deps.has k j then
|
||||
let mut imp : Import := { k with module := s.modNames[j]! }
|
||||
if toAdd.contains imp && (newTransDeps.has k j || newTransDeps.has { k with isExported := true } j) then
|
||||
if args.trace then
|
||||
IO.eprintln s!"Removing `{imp}` from imports to be added because it is now implied"
|
||||
toAdd := toAdd.erase imp
|
||||
deps := deps.sub k {j}
|
||||
else
|
||||
newTransDeps := addTransitiveImps newTransDeps imp j s.transDeps[j]!
|
||||
|
||||
-- now that `toAdd` filtering is done, add `alwaysAdd`
|
||||
toAdd := alwaysAdd ++ toAdd
|
||||
|
||||
-- Any import which is still not in `deps` was unused
|
||||
let mut toRemove : Array Import := #[]
|
||||
for imp in s.mods[i]!.imports do
|
||||
let j := s.env.getModuleIdx? imp.module |>.get!
|
||||
let k := NeedsKind.ofImport imp
|
||||
if args.keepImplied && newTransDeps.has k j then
|
||||
if args.trace && !deps.has k j then
|
||||
IO.eprintln s!"`{imp}` is implied by other imports"
|
||||
else if !deps.has k j then
|
||||
if args.trace then
|
||||
IO.eprintln s!"`{imp}` is now unused"
|
||||
toRemove := toRemove.push imp
|
||||
-- A private import should also be removed if the public version has been added
|
||||
else if !k.isExported && !imp.importAll && newTransDeps.has { k with isExported := true } j then
|
||||
if args.trace then
|
||||
IO.eprintln s!"`{imp}` is already covered by `{ { imp with isExported := true } }`"
|
||||
toRemove := toRemove.push imp
|
||||
|
||||
-- mark and report the removals
|
||||
let mut edits := toRemove.foldl (init := edits) fun edits imp =>
|
||||
edits.remove s.modNames[i]! imp
|
||||
modify fun s => { s with
|
||||
edits := toRemove.foldl (init := s.edits) fun edits imp =>
|
||||
edits.remove s.modNames[i]! imp }
|
||||
|
||||
if !toAdd.isEmpty || !toRemove.isEmpty || explain then
|
||||
if !toAdd.isEmpty || !toRemove.isEmpty || args.explain then
|
||||
if let some path ← srcSearchPath.findModuleWithExt "lean" s.modNames[i]! then
|
||||
println! "{path}:"
|
||||
else
|
||||
@@ -404,9 +621,9 @@ def visitModule (srcSearchPath : SearchPath)
|
||||
if !toRemove.isEmpty then
|
||||
println! " remove {toRemove}"
|
||||
|
||||
if githubStyle then
|
||||
if args.githubStyle then
|
||||
try
|
||||
let (path, inputCtx, stx, endHeader) ← parseHeader srcSearchPath s.modNames[i]!
|
||||
let ⟨path, inputCtx, stx, endHeader⟩ ← parseHeader srcSearchPath s.modNames[i]!
|
||||
let (_, _, imports) := decodeHeader stx
|
||||
for stx in imports do
|
||||
if toRemove.any fun imp => imp == decodeImport stx then
|
||||
@@ -415,14 +632,15 @@ def visitModule (srcSearchPath : SearchPath)
|
||||
(use `lake exe shake --fix` to fix this, or `lake exe shake --update` to ignore)"
|
||||
if !toAdd.isEmpty then
|
||||
-- we put the insert message on the beginning of the last import line
|
||||
let pos := inputCtx.fileMap.toPosition endHeader
|
||||
let pos := inputCtx.fileMap.toPosition endHeader.offset
|
||||
println! "{path}:{pos.line-1}:1: warning: \
|
||||
add {toAdd} instead"
|
||||
catch _ => pure ()
|
||||
|
||||
-- mark and report the additions
|
||||
edits := toAdd.foldl (init := edits) fun edits imp =>
|
||||
edits.add s.modNames[i]! imp
|
||||
modify fun s => { s with
|
||||
edits := toAdd.foldl (init := s.edits) fun edits imp =>
|
||||
edits.add s.modNames[i]! imp }
|
||||
|
||||
if !toAdd.isEmpty then
|
||||
println! " add {toAdd}"
|
||||
@@ -437,14 +655,15 @@ def visitModule (srcSearchPath : SearchPath)
|
||||
let j := s.env.getModuleIdx? imp.module |>.get!
|
||||
newTransDepsI := addTransitiveImps newTransDepsI imp j s.transDeps[j]!
|
||||
|
||||
set { s with transDeps := s.transDeps.set! i newTransDepsI }
|
||||
modify fun s => { s with transDeps := s.transDeps.set! i newTransDepsI }
|
||||
|
||||
if explain then
|
||||
if args.explain then
|
||||
let explanation := getExplanations s.env i
|
||||
let sanitize n := if n.hasMacroScopes then (sanitizeName n).run' { options := {} } else n
|
||||
let run (imp : Import) := do
|
||||
let j := s.env.getModuleIdx? imp.module |>.get!
|
||||
if let some exp? := explanation[(j, NeedsKind.ofImport imp)]? then
|
||||
let mut k := NeedsKind.ofImport imp
|
||||
if let some exp? := explanation[(j, k)]? <|> guard args.addPublic *> explanation[(j, { k with isExported := false})]? then
|
||||
println! " note: `{imp}` required"
|
||||
if let some (n, c) := exp? then
|
||||
println! " because `{sanitize n}` refers to `{sanitize c}`"
|
||||
@@ -455,8 +674,6 @@ def visitModule (srcSearchPath : SearchPath)
|
||||
run j
|
||||
for i in toAdd do run i
|
||||
|
||||
return edits
|
||||
|
||||
/-- Convert a list of module names to a bitset of module indexes -/
|
||||
def toBitset (s : State) (ns : List Name) : Bitset :=
|
||||
ns.foldl (init := ∅) fun c name =>
|
||||
@@ -464,40 +681,26 @@ def toBitset (s : State) (ns : List Name) : Bitset :=
|
||||
| some i => c ∪ {i}
|
||||
| none => c
|
||||
|
||||
/-- The parsed CLI arguments. See `help` for more information -/
|
||||
structure Args where
|
||||
/-- `--help`: shows the help -/
|
||||
help : Bool := false
|
||||
/-- `--force`: skips the `lake build --no-build` sanity check -/
|
||||
force : Bool := false
|
||||
/-- `--gh-style`: output messages that can be parsed by `gh-problem-matcher-wrap` -/
|
||||
githubStyle : Bool := false
|
||||
/-- `--explain`: give constants explaining why each module is needed -/
|
||||
explain : Bool := false
|
||||
/-- `--fix`: apply the fixes directly -/
|
||||
fix : Bool := false
|
||||
/-- `<MODULE>..`: the list of root modules to check -/
|
||||
mods : Array Name := #[]
|
||||
|
||||
local instance : Ord Import where
|
||||
compare a b :=
|
||||
if a.isExported && !b.isExported then
|
||||
Ordering.lt
|
||||
else if !a.isExported && b.isExported then
|
||||
Ordering.gt
|
||||
else
|
||||
a.module.cmp b.module
|
||||
compare :=
|
||||
let _ := @lexOrd
|
||||
compareOn fun imp => (!imp.isExported, imp.module.toString)
|
||||
|
||||
/-- The main entry point. See `help` for more information on arguments. -/
|
||||
def main (args : List String) : IO UInt32 := do
|
||||
public def main (args : List String) : IO UInt32 := do
|
||||
initSearchPath (← findSysroot)
|
||||
-- Parse the arguments
|
||||
let rec parseArgs (args : Args) : List String → Args
|
||||
| [] => args
|
||||
| "--help" :: rest => parseArgs { args with help := true } rest
|
||||
| "--keep-implied" :: rest => parseArgs { args with keepImplied := true } rest
|
||||
| "--keep-prefix" :: rest => parseArgs { args with keepPrefix := true } rest
|
||||
| "--keep-public" :: rest => parseArgs { args with keepPublic := true } rest
|
||||
| "--add-public" :: rest => parseArgs { args with addPublic := true } rest
|
||||
| "--force" :: rest => parseArgs { args with force := true } rest
|
||||
| "--fix" :: rest => parseArgs { args with fix := true } rest
|
||||
| "--explain" :: rest => parseArgs { args with explain := true } rest
|
||||
| "--trace" :: rest => parseArgs { args with trace := true } rest
|
||||
| "--gh-style" :: rest => parseArgs { args with githubStyle := true } rest
|
||||
| "--" :: rest => { args with mods := args.mods ++ rest.map (·.toName) }
|
||||
| other :: rest => parseArgs { args with mods := args.mods.push other.toName } rest
|
||||
@@ -540,69 +743,69 @@ def main (args : List String) : IO UInt32 := do
|
||||
let imps := mods.map ({ module := · })
|
||||
let (_, s) ← importModulesCore imps (isExported := true) |>.run
|
||||
let s := s.markAllExported
|
||||
let env ← finalizeImport s (isModule := true) imps {} (leakEnv := false) (loadExts := false)
|
||||
let mut env ← finalizeImport s (isModule := true) imps {} (leakEnv := false) (loadExts := false)
|
||||
-- the one env ext we want to initialize
|
||||
let is := indirectModUseExt.toEnvExtension.getState env
|
||||
let newState ← indirectModUseExt.addImportedFn is.importedEntries { env := env, opts := {} }
|
||||
env := indirectModUseExt.toEnvExtension.setState (asyncMode := .sync) env { is with state := newState }
|
||||
|
||||
StateT.run' (s := initStateFromEnv env) do
|
||||
|
||||
let s ← get
|
||||
-- Parse the config file
|
||||
|
||||
-- Run the calculation of the `needs` array in parallel
|
||||
let needs := s.mods.mapIdx fun i _ =>
|
||||
Task.spawn fun _ => calcNeeds s.env i
|
||||
Task.spawn fun _ => calcNeeds s i
|
||||
|
||||
-- Parse headers in parallel
|
||||
let headers ← s.mods.mapIdxM fun i _ =>
|
||||
BaseIO.asTask (parseHeader srcSearchPath s.modNames[i]! |>.toBaseIO)
|
||||
if !pkg.isPrefixOf s.modNames[i]! then
|
||||
pure <| Task.pure <| .ok ⟨default, default, default, default⟩
|
||||
else
|
||||
BaseIO.asTask (parseHeader srcSearchPath s.modNames[i]! |>.toBaseIO)
|
||||
|
||||
if args.fix then
|
||||
println! "The following changes will be made automatically:"
|
||||
|
||||
-- Check all selected modules
|
||||
let mut edits : Edits := ∅
|
||||
let mut revNeeds : Needs := default
|
||||
for i in [0:s.mods.size], t in needs, header in headers do
|
||||
match header.get with
|
||||
| .ok (_, _, stx, _) =>
|
||||
edits ← visitModule (addOnly := !pkg.isPrefixOf s.modNames[i]!)
|
||||
srcSearchPath i t.get revNeeds edits stx args.githubStyle args.explain
|
||||
if isExtraRevModUse s.env i then
|
||||
revNeeds := revNeeds.union .priv {i}
|
||||
| .ok ⟨_, _, stx, _⟩ =>
|
||||
visitModule pkg srcSearchPath i t.get stx args
|
||||
| .error e =>
|
||||
println! e.toString
|
||||
|
||||
if !args.fix then
|
||||
-- return error if any issues were found
|
||||
return if edits.isEmpty then 0 else 1
|
||||
return if (← get).edits.isEmpty then 0 else 1
|
||||
|
||||
-- Apply the edits to existing files
|
||||
let mut count := 0
|
||||
for mod in s.modNames, header? in headers do
|
||||
let some (remove, add) := edits[mod]? | continue
|
||||
let some (remove, add) := (← get).edits[mod]? | continue
|
||||
let add : Array Import := add.qsortOrd
|
||||
|
||||
-- Parse the input file
|
||||
let .ok (path, inputCtx, stx, insertion) := header?.get | continue
|
||||
let .ok ⟨path, inputCtx, stx, insertion⟩ := header?.get | continue
|
||||
let (_, _, imports) := decodeHeader stx
|
||||
let text := inputCtx.fileMap.source
|
||||
|
||||
-- Calculate the edit result
|
||||
let mut pos : String.Pos.Raw := 0
|
||||
let mut pos : String.Pos text := text.startPos
|
||||
let mut out : String := ""
|
||||
let mut seen : Std.HashSet Import := {}
|
||||
for stx in imports do
|
||||
let mod := decodeImport stx
|
||||
if remove.contains mod || seen.contains mod then
|
||||
out := out ++ String.Pos.Raw.extract text pos stx.raw.getPos?.get!
|
||||
out := out ++ text.extract pos (text.pos! stx.raw.getPos?.get!)
|
||||
-- We use the end position of the syntax, but include whitespace up to the first newline
|
||||
pos := text.findAux (· == '\n') text.rawEndPos stx.raw.getTailPos?.get! + '\n'
|
||||
pos := text.pos! stx.raw.getTailPos?.get! |>.find '\n' |>.next!
|
||||
seen := seen.insert mod
|
||||
out := out ++ String.Pos.Raw.extract text pos insertion
|
||||
out := out ++ text.extract pos insertion
|
||||
for mod in add do
|
||||
if !seen.contains mod then
|
||||
seen := seen.insert mod
|
||||
out := out ++ s!"{mod}\n"
|
||||
out := out ++ String.Pos.Raw.extract text insertion text.rawEndPos
|
||||
out := out ++ text.extract insertion text.endPos
|
||||
|
||||
IO.FS.writeFile path out
|
||||
count := count + 1
|
||||
|
||||
@@ -7,3 +7,5 @@ root = "Modulize"
|
||||
[[lean_exe]]
|
||||
name = "shake"
|
||||
root = "Shake"
|
||||
# needed by `Lake.loadWorkspace`
|
||||
supportInterpreter = true
|
||||
|
||||
@@ -23,6 +23,7 @@ What this script does:
|
||||
- Special merging strategies for repositories with nightly-testing branches
|
||||
- Safety checks for repositories using bump branches
|
||||
- Custom build and test procedures
|
||||
- lean-fro.org: runs scripts/update.sh to regenerate site content
|
||||
|
||||
6. Commits the changes with message "chore: bump toolchain to {version}"
|
||||
|
||||
@@ -412,20 +413,14 @@ def execute_release_steps(repo, version, config):
|
||||
run_command("lake update", cwd=repo_path, stream_output=True)
|
||||
print(blue("Running `lake update` in examples/hero..."))
|
||||
run_command("lake update", cwd=repo_path / "examples" / "hero", stream_output=True)
|
||||
|
||||
# Run scripts/update.sh to regenerate content
|
||||
print(blue("Running `scripts/update.sh` to regenerate content..."))
|
||||
run_command("scripts/update.sh", cwd=repo_path, stream_output=True)
|
||||
print(green("Content regenerated successfully"))
|
||||
elif repo_name == "cslib":
|
||||
print(blue("Updating lakefile.toml..."))
|
||||
run_command(f'perl -pi -e \'s/"v4\\.[0-9]+(\\.[0-9]+)?(-rc[0-9]+)?"/"' + version + '"/g\' lakefile.*', cwd=repo_path)
|
||||
|
||||
print(blue("Updating docs/lakefile.toml..."))
|
||||
run_command(f'perl -pi -e \'s/"v4\\.[0-9]+(\\.[0-9]+)?(-rc[0-9]+)?"/"' + version + '"/g\' lakefile.*', cwd=repo_path / "docs")
|
||||
|
||||
# Update lean-toolchain in docs
|
||||
print(blue("Updating docs/lean-toolchain..."))
|
||||
docs_toolchain = repo_path / "docs" / "lean-toolchain"
|
||||
with open(docs_toolchain, "w") as f:
|
||||
f.write(f"leanprover/lean4:{version}\n")
|
||||
print(green(f"Updated docs/lean-toolchain to leanprover/lean4:{version}"))
|
||||
|
||||
run_command("lake update", cwd=repo_path, stream_output=True)
|
||||
elif dependencies:
|
||||
run_command(f'perl -pi -e \'s/"v4\\.[0-9]+(\\.[0-9]+)?(-rc[0-9]+)?"/"' + version + '"/g\' lakefile.*', cwd=repo_path)
|
||||
|
||||
@@ -10,7 +10,7 @@ endif()
|
||||
include(ExternalProject)
|
||||
project(LEAN CXX C)
|
||||
set(LEAN_VERSION_MAJOR 4)
|
||||
set(LEAN_VERSION_MINOR 27)
|
||||
set(LEAN_VERSION_MINOR 28)
|
||||
set(LEAN_VERSION_PATCH 0)
|
||||
set(LEAN_VERSION_IS_RELEASE 0) # This number is 1 in the release revision, and 0 otherwise.
|
||||
set(LEAN_SPECIAL_VERSION_DESC "" CACHE STRING "Additional version description like 'nightly-2018-03-11'")
|
||||
@@ -448,8 +448,8 @@ if(LLVM AND ${STAGE} GREATER 0)
|
||||
# - In particular, `host/bin/llvm-config` produces flags like `-Lllvm-host/lib/libLLVM`, while
|
||||
# we need the path to be `-Lllvm/lib/libLLVM`. Thus, we perform this replacement here.
|
||||
string(REPLACE "llvm-host" "llvm" LEANSHARED_LINKER_FLAGS ${LEANSHARED_LINKER_FLAGS})
|
||||
string(REPLACE "llvm-host" "llvm" LEAN_EXTRA_CXX_FLAGS ${LEAN_EXTRA_CXX_FLAGS})
|
||||
message(VERBOSE "leanshared linker flags: '${LEANSHARED_LINKER_FLAGS}' | lean extra cxx flags '${LEAN_EXTR_CXX_FLAGS}'")
|
||||
string(REPLACE "llvm-host" "llvm" CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS})
|
||||
message(VERBOSE "leanshared linker flags: '${LEANSHARED_LINKER_FLAGS}' | lean extra cxx flags '${CMAKE_CXX_FLAGS}'")
|
||||
endif()
|
||||
|
||||
# get rid of unused parts of C++ stdlib
|
||||
|
||||
@@ -15,6 +15,7 @@ public import Init.RCases
|
||||
public import Init.Core
|
||||
public import Init.Control
|
||||
public import Init.WF
|
||||
public import Init.WFComputable
|
||||
public import Init.WFTactics
|
||||
public import Init.Data
|
||||
public import Init.System
|
||||
|
||||
@@ -116,7 +116,7 @@ On top of these instances this file defines several auxiliary type classes:
|
||||
* `CoeOTC := CoeOut* Coe*`
|
||||
* `CoeHTC := CoeHead? CoeOut* Coe*`
|
||||
* `CoeHTCT := CoeHead? CoeOut* Coe* CoeTail?`
|
||||
* `CoeDep := CoeHead? CoeOut* Coe* CoeTail? | CoeDep`
|
||||
* `CoeT := CoeHead? CoeOut* Coe* CoeTail? | CoeDep`
|
||||
|
||||
-/
|
||||
|
||||
|
||||
@@ -17,6 +17,9 @@ public section
|
||||
|
||||
open Function
|
||||
|
||||
@[simp, grind =] theorem monadMap_refl {m : Type _ → Type _} {α} (f : ∀ {α}, m α → m α) :
|
||||
monadMap @f = @f α := rfl
|
||||
|
||||
/-! # ExceptT -/
|
||||
|
||||
namespace ExceptT
|
||||
@@ -25,6 +28,8 @@ namespace ExceptT
|
||||
simp [run] at h
|
||||
assumption
|
||||
|
||||
@[simp, grind =] theorem run_mk (x : m (Except ε α)) : run (mk x : ExceptT ε m α) = x := rfl
|
||||
|
||||
@[simp, grind =] theorem run_pure [Monad m] (x : α) : run (pure x : ExceptT ε m α) = pure (Except.ok x) := rfl
|
||||
|
||||
@[simp, grind =] theorem run_lift [Monad.{u, v} m] (x : m α) : run (ExceptT.lift x : ExceptT ε m α) = (Except.ok <$> x : m (Except ε α)) := rfl
|
||||
@@ -55,6 +60,9 @@ theorem run_bind [Monad m] (x : ExceptT ε m α) (f : α → ExceptT ε m β)
|
||||
apply bind_congr
|
||||
intro a; cases a <;> simp [Except.map]
|
||||
|
||||
@[simp, grind =] theorem run_monadMap [MonadFunctorT n m] (f : {β : Type u} → n β → n β) (x : ExceptT ε m α)
|
||||
: (monadMap @f x : ExceptT ε m α).run = monadMap @f (x.run) := rfl
|
||||
|
||||
protected theorem seq_eq {α β ε : Type u} [Monad m] (mf : ExceptT ε m (α → β)) (x : ExceptT ε m α) : mf <*> x = mf >>= fun f => f <$> x :=
|
||||
rfl
|
||||
|
||||
@@ -97,6 +105,22 @@ instance [Monad m] [LawfulMonad m] : LawfulMonad (ExceptT ε m) where
|
||||
simp only [ExceptT.instMonad, ExceptT.map, ExceptT.mk, throw, throwThe, MonadExceptOf.throw,
|
||||
pure_bind]
|
||||
|
||||
/-! Note that the `MonadControl` instance for `ExceptT` is not monad-generic. -/
|
||||
|
||||
@[simp] theorem run_restoreM [Monad m] (x : stM m (ExceptT ε m) α) :
|
||||
ExceptT.run (restoreM x) = pure x := rfl
|
||||
|
||||
@[simp] theorem run_liftWith [Monad m] (f : ({β : Type u} → ExceptT ε m β → m (stM m (ExceptT ε m) β)) → m α) :
|
||||
ExceptT.run (liftWith f) = Except.ok <$> (f fun x => x.run) :=
|
||||
rfl
|
||||
|
||||
@[simp] theorem run_controlAt [Monad m] [LawfulMonad m] (f : ({β : Type u} → ExceptT ε m β → m (stM m (ExceptT ε m) β)) → m (stM m (ExceptT ε m) α)) :
|
||||
ExceptT.run (controlAt m f) = f fun x => x.run := by
|
||||
simp [controlAt, run_bind, bind_map_left]
|
||||
|
||||
@[simp] theorem run_control [Monad m] [LawfulMonad m] (f : ({β : Type u} → ExceptT ε m β → m (stM m (ExceptT ε m) β)) → m (stM m (ExceptT ε m) α)) :
|
||||
ExceptT.run (control f) = f fun x => x.run := run_controlAt f
|
||||
|
||||
end ExceptT
|
||||
|
||||
/-! # Except -/
|
||||
@@ -150,6 +174,9 @@ namespace OptionT
|
||||
apply bind_congr
|
||||
intro a; cases a <;> simp [OptionT.pure, OptionT.mk]
|
||||
|
||||
@[simp, grind =] theorem run_monadMap [MonadFunctorT n m] (f : {β : Type u} → n β → n β) (x : OptionT m α)
|
||||
: (monadMap @f x : OptionT m α).run = monadMap @f (x.run) := rfl
|
||||
|
||||
protected theorem seq_eq {α β : Type u} [Monad m] (mf : OptionT m (α → β)) (x : OptionT m α) : mf <*> x = mf >>= fun f => f <$> x :=
|
||||
rfl
|
||||
|
||||
@@ -211,6 +238,24 @@ instance [Monad m] [LawfulMonad m] : LawfulMonad (OptionT m) where
|
||||
(x <|> y).run = Option.elimM x.run y.run (fun x => pure (some x)) :=
|
||||
bind_congr fun | some _ => by rfl | none => by rfl
|
||||
|
||||
/-! Note that the `MonadControl` instance for `OptionT` is not monad-generic. -/
|
||||
|
||||
@[simp] theorem run_restoreM [Monad m] (x : stM m (OptionT m) α) :
|
||||
OptionT.run (restoreM x) = pure x := rfl
|
||||
|
||||
@[simp] theorem run_liftWith [Monad m] [LawfulMonad m] (f : ({β : Type u} → OptionT m β → m (stM m (OptionT m) β)) → m α) :
|
||||
OptionT.run (liftWith f) = Option.some <$> (f fun x => x.run) := by
|
||||
dsimp [liftWith]
|
||||
rw [← bind_pure_comp]
|
||||
rfl
|
||||
|
||||
@[simp] theorem run_controlAt [Monad m] [LawfulMonad m] (f : ({β : Type u} → OptionT m β → m (stM m (OptionT m) β)) → m (stM m (OptionT m) α)) :
|
||||
OptionT.run (controlAt m f) = f fun x => x.run := by
|
||||
simp [controlAt, Option.elimM, Option.elim]
|
||||
|
||||
@[simp] theorem run_control [Monad m] [LawfulMonad m] (f : ({β : Type u} → OptionT m β → m (stM m (OptionT m) β)) → m (stM m (OptionT m) α)) :
|
||||
OptionT.run (control f) = f fun x => x.run := run_controlAt f
|
||||
|
||||
end OptionT
|
||||
|
||||
/-! # Option -/
|
||||
@@ -232,6 +277,9 @@ namespace ReaderT
|
||||
simp [run] at h
|
||||
exact funext h
|
||||
|
||||
@[simp, grind =] theorem run_mk (x : ρ → m α) (ctx : ρ) : run (.mk x : ReaderT ρ m α) ctx = x ctx :=
|
||||
rfl
|
||||
|
||||
@[simp, grind =] theorem run_pure [Monad m] (a : α) (ctx : ρ) : (pure a : ReaderT ρ m α).run ctx = pure a := rfl
|
||||
|
||||
@[simp, grind =] theorem run_bind [Monad m] (x : ReaderT ρ m α) (f : α → ReaderT ρ m β) (ctx : ρ)
|
||||
@@ -279,6 +327,22 @@ instance [Monad m] [LawfulMonad m] : LawfulMonad (ReaderT ρ m) where
|
||||
pure_bind := by intros; apply ext; intros; simp
|
||||
bind_assoc := by intros; apply ext; intros; simp
|
||||
|
||||
/-! Note that the `MonadControl` instance for `ReaderT` is not monad-generic. -/
|
||||
|
||||
@[simp] theorem run_restoreM [Monad m] (x : stM m (ReaderT ρ m) α) (ctx : ρ) :
|
||||
ReaderT.run (restoreM x) ctx = pure x := rfl
|
||||
|
||||
@[simp] theorem run_liftWith [Monad m] (f : ({β : Type u} → ReaderT ρ m β → m (stM m (ReaderT ρ m) β)) → m α) (ctx : ρ) :
|
||||
ReaderT.run (liftWith f) ctx = (f fun x => x.run ctx) :=
|
||||
rfl
|
||||
|
||||
@[simp] theorem run_controlAt [Monad m] [LawfulMonad m] (f : ({β : Type u} → ReaderT ρ m β → m (stM m (ReaderT ρ m) β)) → m (stM m (ReaderT ρ m) α)) (ctx : ρ) :
|
||||
ReaderT.run (controlAt m f) ctx = f fun x => x.run ctx := by
|
||||
simp [controlAt]
|
||||
|
||||
@[simp] theorem run_control [Monad m] [LawfulMonad m] (f : ({β : Type u} → ReaderT ρ m β → m (stM m (ReaderT ρ m) β)) → m (stM m (ReaderT ρ m) α)) (ctx : ρ) :
|
||||
ReaderT.run (control f) ctx = f fun x => x.run ctx := run_controlAt f ctx
|
||||
|
||||
end ReaderT
|
||||
|
||||
/-! # StateRefT -/
|
||||
@@ -293,17 +357,20 @@ namespace StateT
|
||||
@[ext, grind ext] theorem ext {x y : StateT σ m α} (h : ∀ s, x.run s = y.run s) : x = y :=
|
||||
funext h
|
||||
|
||||
@[simp, grind =] theorem run_mk [Monad m] (x : σ → m (α × σ)) (s : σ) : run (.mk x) s = x s :=
|
||||
rfl
|
||||
|
||||
@[simp, grind =] theorem run'_eq [Monad m] (x : StateT σ m α) (s : σ) : run' x s = (·.1) <$> run x s :=
|
||||
rfl
|
||||
|
||||
@[simp, grind =] theorem run_pure [Monad m] (a : α) (s : σ) : (pure a : StateT σ m α).run s = pure (a, s) := rfl
|
||||
|
||||
@[simp, grind =] theorem run_bind [Monad m] (x : StateT σ m α) (f : α → StateT σ m β) (s : σ)
|
||||
: (x >>= f).run s = x.run s >>= λ p => (f p.1).run p.2 := by
|
||||
simp [bind, StateT.bind, run]
|
||||
: (x >>= f).run s = x.run s >>= λ p => (f p.1).run p.2 := rfl
|
||||
|
||||
@[simp, grind =] theorem run_map {α β σ : Type u} [Monad m] [LawfulMonad m] (f : α → β) (x : StateT σ m α) (s : σ) : (f <$> x).run s = (fun (p : α × σ) => (f p.1, p.2)) <$> x.run s := by
|
||||
simp [Functor.map, StateT.map, run, ←bind_pure_comp]
|
||||
rw [← bind_pure_comp (m := m)]
|
||||
rfl
|
||||
|
||||
@[simp, grind =] theorem run_get [Monad m] (s : σ) : (get : StateT σ m σ).run s = pure (s, s) := rfl
|
||||
|
||||
@@ -312,13 +379,13 @@ namespace StateT
|
||||
@[simp, grind =] theorem run_modify [Monad m] (f : σ → σ) (s : σ) : (modify f : StateT σ m PUnit).run s = pure (⟨⟩, f s) := rfl
|
||||
|
||||
@[simp, grind =] theorem run_modifyGet [Monad m] (f : σ → α × σ) (s : σ) : (modifyGet f : StateT σ m α).run s = pure ((f s).1, (f s).2) := by
|
||||
simp [modifyGet, MonadStateOf.modifyGet, StateT.modifyGet, run]
|
||||
rfl
|
||||
|
||||
@[simp, grind =] theorem run_lift {α σ : Type u} [Monad m] (x : m α) (s : σ) : (StateT.lift x : StateT σ m α).run s = x >>= fun a => pure (a, s) := rfl
|
||||
|
||||
@[grind =]
|
||||
theorem run_bind_lift {α σ : Type u} [Monad m] [LawfulMonad m] (x : m α) (f : α → StateT σ m β) (s : σ) : (StateT.lift x >>= f).run s = x >>= fun a => (f a).run s := by
|
||||
simp [StateT.lift, StateT.run, bind, StateT.bind]
|
||||
simp
|
||||
|
||||
@[simp, grind =] theorem run_monadLift {α σ : Type u} [Monad m] [MonadLiftT n m] (x : n α) (s : σ) : (monadLift x : StateT σ m α).run s = (monadLift x : m α) >>= fun a => pure (a, s) := rfl
|
||||
|
||||
@@ -358,10 +425,48 @@ instance [Monad m] [LawfulMonad m] : LawfulMonad (StateT σ m) where
|
||||
pure_bind := by intros; apply ext; intros; simp
|
||||
bind_assoc := by intros; apply ext; intros; simp
|
||||
|
||||
/-! Note that the `MonadControl` instance for `StateT` is not monad-generic. -/
|
||||
|
||||
@[simp] theorem run_restoreM [Monad m] [LawfulMonad m] (x : stM m (StateT σ m) α) (s : σ) :
|
||||
StateT.run (restoreM x) s = pure x := by
|
||||
simp [restoreM, MonadControl.restoreM]
|
||||
rfl
|
||||
|
||||
@[simp] theorem run_liftWith [Monad m] [LawfulMonad m] (f : ({β : Type u} → StateT σ m β → m (stM m (StateT σ m) β)) → m α) (s : σ) :
|
||||
StateT.run (liftWith f) s = ((·, s) <$> f fun x => x.run s) := by
|
||||
simp [liftWith, MonadControl.liftWith, Function.comp_def]
|
||||
|
||||
@[simp] theorem run_controlAt [Monad m] [LawfulMonad m] (f : ({β : Type u} → StateT σ m β → m (stM m (StateT σ m) β)) → m (stM m (StateT σ m) α)) (s : σ) :
|
||||
StateT.run (controlAt m f) s = f fun x => x.run s := by
|
||||
simp [controlAt]
|
||||
|
||||
@[simp] theorem run_control [Monad m] [LawfulMonad m] (f : ({β : Type u} → StateT σ m β → m (stM m (StateT σ m) β)) → m (stM m (StateT σ m) α)) (s : σ) :
|
||||
StateT.run (control f) s = f fun x => x.run s := run_controlAt f s
|
||||
|
||||
end StateT
|
||||
|
||||
/-! # EStateM -/
|
||||
|
||||
namespace EStateM
|
||||
|
||||
@[simp, grind =] theorem run_pure (a : α) (s : σ) :
|
||||
EStateM.run (pure a : EStateM ε σ α) s = .ok a s := rfl
|
||||
|
||||
@[simp, grind =] theorem run_get (s : σ) :
|
||||
EStateM.run (get : EStateM ε σ σ) s = .ok s s := rfl
|
||||
|
||||
@[simp, grind =] theorem run_set (s₁ s₂ : σ) :
|
||||
EStateM.run (set s₁ : EStateM ε σ PUnit) s₂ = .ok .unit s₁ := rfl
|
||||
|
||||
@[simp, grind =] theorem run_modify (f : σ → σ) (s : σ) :
|
||||
EStateM.run (modify f : EStateM ε σ PUnit) s = .ok .unit (f s) := rfl
|
||||
|
||||
@[simp, grind =] theorem run_modifyGet (f : σ → α × σ) (s : σ) :
|
||||
EStateM.run (modifyGet f : EStateM ε σ α) s = .ok (f s).1 (f s).2 := rfl
|
||||
|
||||
@[simp, grind =] theorem run_throw (e : ε) (s : σ):
|
||||
EStateM.run (throw e : EStateM ε σ PUnit) s = .error e s := rfl
|
||||
|
||||
instance : LawfulMonad (EStateM ε σ) := .mk'
|
||||
(id_map := fun x => funext <| fun s => by
|
||||
dsimp only [EStateM.instMonad, EStateM.map]
|
||||
@@ -375,3 +480,5 @@ instance : LawfulMonad (EStateM ε σ) := .mk'
|
||||
| .ok _ _ => rfl
|
||||
| .error _ _ => rfl)
|
||||
(map_const := fun _ _ => rfl)
|
||||
|
||||
end EStateM
|
||||
|
||||
@@ -25,6 +25,12 @@ of a value and a state.
|
||||
@[expose] def StateT (σ : Type u) (m : Type u → Type v) (α : Type u) : Type (max u v) :=
|
||||
σ → m (α × σ)
|
||||
|
||||
/--
|
||||
Interpret `σ → m (α × σ)` as an element of `StateT σ m α`.
|
||||
-/
|
||||
@[always_inline, inline, expose]
|
||||
def StateT.mk {σ : Type u} {m : Type u → Type v} {α : Type u} (x : σ → m (α × σ)) : StateT σ m α := x
|
||||
|
||||
/--
|
||||
Executes an action from a monad with added state in the underlying monad `m`. Given an initial
|
||||
state, it returns a value paired with the final state.
|
||||
|
||||
@@ -201,6 +201,7 @@ An element of `α ⊕ β` is either an `a : α` wrapped in `Sum.inl` or a `b :
|
||||
indication of which of the two types was chosen. The union of a singleton set with itself contains
|
||||
one element, while `Unit ⊕ Unit` contains distinct values `inl ()` and `inr ()`.
|
||||
-/
|
||||
@[suggest_for Either]
|
||||
inductive Sum (α : Type u) (β : Type v) where
|
||||
/-- Left injection into the sum type `α ⊕ β`. -/
|
||||
| inl (val : α) : Sum α β
|
||||
@@ -939,9 +940,7 @@ theorem HEq.subst {p : (T : Sort u) → T → Prop} (h₁ : a ≍ b) (h₂ : p
|
||||
@[symm] theorem HEq.symm (h : a ≍ b) : b ≍ a :=
|
||||
h.rec (HEq.refl a)
|
||||
|
||||
/-- Propositionally equal terms are also heterogeneously equal. -/
|
||||
theorem heq_of_eq (h : a = a') : a ≍ a' :=
|
||||
Eq.subst h (HEq.refl a)
|
||||
|
||||
|
||||
/-- Heterogeneous equality is transitive. -/
|
||||
theorem HEq.trans (h₁ : a ≍ b) (h₂ : b ≍ c) : a ≍ c :=
|
||||
@@ -1370,7 +1369,7 @@ instance {α : Type u} {p : α → Prop} [BEq α] [LawfulBEq α] : LawfulBEq {x
|
||||
instance {α : Sort u} {p : α → Prop} [DecidableEq α] : DecidableEq {x : α // p x} :=
|
||||
fun ⟨a, h₁⟩ ⟨b, h₂⟩ =>
|
||||
if h : a = b then isTrue (by subst h; exact rfl)
|
||||
else isFalse (fun h' => Subtype.noConfusion h' (fun h' => absurd h' h))
|
||||
else isFalse (fun h' => Subtype.noConfusion rfl .rfl (heq_of_eq h') (fun h' => absurd (eq_of_heq h') h))
|
||||
|
||||
end Subtype
|
||||
|
||||
@@ -1429,8 +1428,8 @@ instance [DecidableEq α] [DecidableEq β] : DecidableEq (α × β) :=
|
||||
| isTrue e₁ =>
|
||||
match decEq b b' with
|
||||
| isTrue e₂ => isTrue (e₁ ▸ e₂ ▸ rfl)
|
||||
| isFalse n₂ => isFalse fun h => Prod.noConfusion h fun _ e₂' => absurd e₂' n₂
|
||||
| isFalse n₁ => isFalse fun h => Prod.noConfusion h fun e₁' _ => absurd e₁' n₁
|
||||
| isFalse n₂ => isFalse fun h => Prod.noConfusion rfl rfl (heq_of_eq h) fun _ e₂' => absurd (eq_of_heq e₂') n₂
|
||||
| isFalse n₁ => isFalse fun h => Prod.noConfusion rfl rfl (heq_of_eq h) fun e₁' _ => absurd (eq_of_heq e₁') n₁
|
||||
|
||||
instance [BEq α] [BEq β] : BEq (α × β) where
|
||||
beq := fun (a₁, b₁) (a₂, b₂) => a₁ == a₂ && b₁ == b₂
|
||||
|
||||
@@ -572,9 +572,6 @@ def unattach {α : Type _} {p : α → Prop} (xs : Array { x // p x }) : Array
|
||||
@[simp] theorem unattach_empty {p : α → Prop} : (#[] : Array { x // p x }).unattach = #[] := by
|
||||
simp [unattach]
|
||||
|
||||
@[deprecated unattach_empty (since := "2025-05-26")]
|
||||
abbrev unattach_nil := @unattach_empty
|
||||
|
||||
@[simp] theorem unattach_push {p : α → Prop} {a : { x // p x }} {xs : Array { x // p x }} :
|
||||
(xs.push a).unattach = xs.unattach.push a.1 := by
|
||||
simp only [unattach, Array.map_push]
|
||||
|
||||
@@ -1348,7 +1348,7 @@ Examples:
|
||||
* `#[2, 4, 5, 6].any (· % 2 = 0) = true`
|
||||
* `#[2, 4, 5, 6].any (· % 2 = 1) = true`
|
||||
-/
|
||||
@[inline, expose]
|
||||
@[inline, expose, suggest_for Array.some]
|
||||
def any (as : Array α) (p : α → Bool) (start := 0) (stop := as.size) : Bool :=
|
||||
Id.run <| as.anyM (pure <| p ·) start stop
|
||||
|
||||
@@ -1366,7 +1366,7 @@ Examples:
|
||||
* `#[2, 4, 6].all (· % 2 = 0) = true`
|
||||
* `#[2, 4, 5, 6].all (· % 2 = 0) = false`
|
||||
-/
|
||||
@[inline]
|
||||
@[inline, suggest_for Array.every]
|
||||
def all (as : Array α) (p : α → Bool) (start := 0) (stop := as.size) : Bool :=
|
||||
Id.run <| as.allM (pure <| p ·) start stop
|
||||
|
||||
|
||||
@@ -73,9 +73,6 @@ theorem foldrM_eq_reverse_foldlM_toList [Monad m] {f : α → β → m β} {init
|
||||
rcases xs with ⟨xs⟩
|
||||
simp [push, List.concat_eq_append]
|
||||
|
||||
@[deprecated toList_push (since := "2025-05-26")]
|
||||
abbrev push_toList := @toList_push
|
||||
|
||||
@[simp, grind =] theorem toListAppend_eq {xs : Array α} {l : List α} : xs.toListAppend l = xs.toList ++ l := by
|
||||
simp [toListAppend, ← foldr_toList]
|
||||
|
||||
|
||||
@@ -62,12 +62,12 @@ theorem size_eq_countP_add_countP {xs : Array α} : xs.size = countP p xs + coun
|
||||
rcases xs with ⟨xs⟩
|
||||
simp [List.length_eq_countP_add_countP (p := p)]
|
||||
|
||||
@[grind =]
|
||||
theorem countP_eq_size_filter {xs : Array α} : countP p xs = (filter p xs).size := by
|
||||
rcases xs with ⟨xs⟩
|
||||
simp [List.countP_eq_length_filter]
|
||||
|
||||
@[grind =]
|
||||
grind_pattern countP_eq_size_filter => xs.countP p, xs.filter p
|
||||
|
||||
theorem countP_eq_size_filter' : countP p = size ∘ filter p := by
|
||||
funext xs
|
||||
apply countP_eq_size_filter
|
||||
|
||||
@@ -99,23 +99,23 @@ instance instDecidableEq [DecidableEq α] : DecidableEq (Array α) := fun xs ys
|
||||
| ⟨[]⟩ =>
|
||||
match ys with
|
||||
| ⟨[]⟩ => isTrue rfl
|
||||
| ⟨_ :: _⟩ => isFalse (Array.noConfusion · (List.noConfusion ·))
|
||||
| ⟨_ :: _⟩ => isFalse (fun h => Array.noConfusion rfl (heq_of_eq h) (fun h => List.noConfusion rfl h))
|
||||
| ⟨a :: as⟩ =>
|
||||
match ys with
|
||||
| ⟨[]⟩ => isFalse (Array.noConfusion · (List.noConfusion ·))
|
||||
| ⟨[]⟩ => isFalse (fun h => Array.noConfusion rfl (heq_of_eq h) (fun h => List.noConfusion rfl h))
|
||||
| ⟨b :: bs⟩ => instDecidableEqImpl ⟨a :: as⟩ ⟨b :: bs⟩
|
||||
|
||||
@[csimp]
|
||||
theorem instDecidableEq_csimp : @instDecidableEq = @instDecidableEqImpl :=
|
||||
Subsingleton.allEq _ _
|
||||
|
||||
|
||||
/--
|
||||
Equality with `#[]` is decidable even if the underlying type does not have decidable equality.
|
||||
-/
|
||||
instance instDecidableEqEmp (xs : Array α) : Decidable (xs = #[]) :=
|
||||
match xs with
|
||||
| ⟨[]⟩ => isTrue rfl
|
||||
| ⟨_ :: _⟩ => isFalse (Array.noConfusion · (List.noConfusion ·))
|
||||
| ⟨_ :: _⟩ => isFalse (fun h => Array.noConfusion rfl (heq_of_eq h) (fun h => List.noConfusion rfl h))
|
||||
|
||||
/--
|
||||
Equality with `#[]` is decidable even if the underlying type does not have decidable equality.
|
||||
@@ -123,7 +123,7 @@ Equality with `#[]` is decidable even if the underlying type does not have decid
|
||||
instance instDecidableEmpEq (ys : Array α) : Decidable (#[] = ys) :=
|
||||
match ys with
|
||||
| ⟨[]⟩ => isTrue rfl
|
||||
| ⟨_ :: _⟩ => isFalse (Array.noConfusion · (List.noConfusion ·))
|
||||
| ⟨_ :: _⟩ => isFalse (fun h => Array.noConfusion rfl (heq_of_eq h) (fun h => List.noConfusion rfl h))
|
||||
|
||||
theorem beq_eq_decide [BEq α] (xs ys : Array α) :
|
||||
(xs == ys) = if h : xs.size = ys.size then
|
||||
|
||||
@@ -389,9 +389,6 @@ theorem eraseIdx_append_of_size_le {xs : Array α} {k : Nat} (hk : xs.size ≤ k
|
||||
simp at hk
|
||||
simp [List.eraseIdx_append_of_length_le, *]
|
||||
|
||||
@[deprecated eraseIdx_append_of_size_le (since := "2025-06-11")]
|
||||
abbrev eraseIdx_append_of_length_le := @eraseIdx_append_of_size_le
|
||||
|
||||
@[grind =]
|
||||
theorem eraseIdx_append {xs ys : Array α} (h : k < (xs ++ ys).size) :
|
||||
eraseIdx (xs ++ ys) k =
|
||||
|
||||
@@ -159,9 +159,6 @@ theorem find?_singleton {a : α} {p : α → Bool} :
|
||||
findRev? p (xs.push a) = findRev? p xs := by
|
||||
cases xs; simp [h]
|
||||
|
||||
@[deprecated findRev?_push_of_neg (since := "2025-06-12")]
|
||||
abbrev findRev?_cons_of_neg := @findRev?_push_of_neg
|
||||
|
||||
@[grind =]
|
||||
theorem finRev?_push {xs : Array α} :
|
||||
findRev? p (xs.push a) = (Option.guard p a).or (xs.findRev? p) := by
|
||||
@@ -171,9 +168,6 @@ theorem finRev?_push {xs : Array α} :
|
||||
· rw [findRev?_push_of_pos, Option.guard_eq_some_iff.mpr ⟨rfl, h⟩]
|
||||
all_goals simp [h]
|
||||
|
||||
@[deprecated finRev?_push (since := "2025-06-12")]
|
||||
abbrev findRev?_cons := @finRev?_push
|
||||
|
||||
@[simp, grind =] theorem find?_eq_none : find? p xs = none ↔ ∀ x ∈ xs, ¬ p x := by
|
||||
cases xs; simp
|
||||
|
||||
|
||||
@@ -53,11 +53,6 @@ theorem eraseIdx_insertIdx_self {i : Nat} {xs : Array α} (h : i ≤ xs.size) :
|
||||
rcases xs with ⟨xs⟩
|
||||
simp_all
|
||||
|
||||
@[deprecated eraseIdx_insertIdx_self (since := "2025-06-15")]
|
||||
theorem eraseIdx_insertIdx {i : Nat} {xs : Array α} (h : i ≤ xs.size) :
|
||||
(xs.insertIdx i a).eraseIdx i (by simp; omega) = xs := by
|
||||
simp [eraseIdx_insertIdx_self]
|
||||
|
||||
theorem insertIdx_eraseIdx_of_ge {as : Array α}
|
||||
(w₁ : i < as.size) (w₂ : j ≤ (as.eraseIdx i).size) (h : i ≤ j) :
|
||||
(as.eraseIdx i).insertIdx j a =
|
||||
|
||||
@@ -1758,11 +1758,6 @@ theorem toArray_append {xs : List α} {ys : Array α} :
|
||||
|
||||
theorem singleton_eq_toArray_singleton {a : α} : #[a] = [a].toArray := rfl
|
||||
|
||||
@[deprecated empty_append (since := "2025-05-26")]
|
||||
theorem empty_append_fun : ((#[] : Array α) ++ ·) = id := by
|
||||
funext ⟨l⟩
|
||||
simp
|
||||
|
||||
@[simp, grind =] theorem mem_append {a : α} {xs ys : Array α} : a ∈ xs ++ ys ↔ a ∈ xs ∨ a ∈ ys := by
|
||||
simp only [mem_def, toList_append, List.mem_append]
|
||||
|
||||
@@ -3248,14 +3243,6 @@ rather than `(arr.push a).size` as the argument.
|
||||
l.foldl (fun xs x => xs.push x) xs = xs ++ l.toArray := by
|
||||
simpa using List.foldl_push_eq_append (f := id)
|
||||
|
||||
@[deprecated _root_.List.foldl_push_eq_append' (since := "2025-05-18")]
|
||||
theorem _root_.List.foldl_push {l : List α} {as : Array α} : l.foldl Array.push as = as ++ l.toArray := by
|
||||
induction l generalizing as <;> simp [*]
|
||||
|
||||
@[deprecated _root_.List.foldr_push_eq_append' (since := "2025-05-18")]
|
||||
theorem _root_.List.foldr_push {l : List α} {as : Array α} : l.foldr (fun a bs => push bs a) as = as ++ l.reverse.toArray := by
|
||||
rw [List.foldr_eq_foldl_reverse, List.foldl_push_eq_append']
|
||||
|
||||
-- TODO: a multi-pattern is being selected there because E-matching does not go inside lambdas.
|
||||
@[simp, grind! ←] theorem foldr_append_eq_append {xs : Array α} {f : α → Array β} {ys : Array β} :
|
||||
xs.foldr (f · ++ ·) ys = (xs.map f).flatten ++ ys := by
|
||||
@@ -4334,11 +4321,6 @@ theorem getElem_eq_getD {xs : Array α} {i} {h : i < xs.size} (fallback : α) :
|
||||
xs[i]'h = xs.getD i fallback := by
|
||||
rw [getD_eq_getD_getElem?, getElem_eq_getElem?_get, Option.get_eq_getD]
|
||||
|
||||
/-! # mem -/
|
||||
|
||||
@[deprecated mem_toList_iff (since := "2025-05-26")]
|
||||
theorem mem_toList {a : α} {xs : Array α} : a ∈ xs.toList ↔ a ∈ xs := mem_def.symm
|
||||
|
||||
/-! # get lemmas -/
|
||||
|
||||
theorem lt_of_getElem {x : α} {xs : Array α} {i : Nat} {hidx : i < xs.size} (_ : xs[i] = x) :
|
||||
|
||||
@@ -73,19 +73,11 @@ private theorem cons_lex_cons [BEq α] {lt : α → α → Bool} {a b : α} {xs
|
||||
(lt a b || a == b && xs.lex ys lt) := by
|
||||
simp only [lex, size_append, List.size_toArray, List.length_cons, List.length_nil, Nat.zero_add,
|
||||
Nat.add_min_add_left, Nat.add_lt_add_iff_left, Std.Rco.forIn'_eq_forIn'_toList]
|
||||
conv =>
|
||||
lhs; congr; congr
|
||||
rw [cons_lex_cons.forIn'_congr_aux Std.Rco.toList_eq_if_roo rfl (fun _ _ _ => rfl)]
|
||||
simp only [bind_pure_comp, map_pure]
|
||||
rw [cons_lex_cons.forIn'_congr_aux (if_pos (by omega)) rfl (fun _ _ _ => rfl)]
|
||||
simp only [Std.toList_roo_eq_toList_rco_of_isSome_succ? (lo := 0) (h := rfl),
|
||||
Std.PRange.UpwardEnumerable.succ?, Nat.add_comm 1, Std.PRange.Nat.toList_rco_succ_succ,
|
||||
Option.get_some, List.forIn'_cons, List.size_toArray, List.length_cons, List.length_nil,
|
||||
Nat.lt_add_one, getElem_append_left, List.getElem_toArray, List.getElem_cons_zero]
|
||||
cases lt a b
|
||||
· rw [bne]
|
||||
cases a == b <;> simp
|
||||
· simp
|
||||
rw [cons_lex_cons.forIn'_congr_aux (Nat.toList_rco_eq_cons (by omega)) rfl (fun _ _ _ => rfl)]
|
||||
simp only [bind_pure_comp, map_pure, Nat.toList_rco_succ_succ, Nat.add_comm 1]
|
||||
cases h : lt a b
|
||||
· cases h' : a == b <;> simp [bne, *]
|
||||
· simp [*]
|
||||
|
||||
@[simp, grind =] theorem _root_.List.lex_toArray [BEq α] {lt : α → α → Bool} {l₁ l₂ : List α} :
|
||||
l₁.toArray.lex l₂.toArray lt = l₁.lex l₂ lt := by
|
||||
|
||||
@@ -39,10 +39,6 @@ theorem map_toList_inj [Monad m] [LawfulMonad m]
|
||||
@[simp, grind =] theorem idRun_mapM {xs : Array α} {f : α → Id β} : (xs.mapM f).run = xs.map (f · |>.run) :=
|
||||
mapM_pure
|
||||
|
||||
@[deprecated idRun_mapM (since := "2025-05-21")]
|
||||
theorem mapM_id {xs : Array α} {f : α → Id β} : xs.mapM f = xs.map f :=
|
||||
mapM_pure
|
||||
|
||||
@[simp, grind =] theorem mapM_map [Monad m] [LawfulMonad m] {f : α → β} {g : β → m γ} {xs : Array α} :
|
||||
(xs.map f).mapM g = xs.mapM (g ∘ f) := by
|
||||
rcases xs with ⟨xs⟩
|
||||
@@ -201,13 +197,6 @@ theorem idRun_forIn'_yield_eq_foldl
|
||||
xs.attach.foldl (fun b ⟨a, h⟩ => f a h b |>.run) init := by
|
||||
simp
|
||||
|
||||
@[deprecated idRun_forIn'_yield_eq_foldl (since := "2025-05-21")]
|
||||
theorem forIn'_yield_eq_foldl
|
||||
{xs : Array α} (f : (a : α) → a ∈ xs → β → β) (init : β) :
|
||||
forIn' (m := Id) xs init (fun a m b => .yield (f a m b)) =
|
||||
xs.attach.foldl (fun b ⟨a, h⟩ => f a h b) init :=
|
||||
forIn'_pure_yield_eq_foldl _ _
|
||||
|
||||
@[simp, grind =] theorem forIn'_map [Monad m] [LawfulMonad m]
|
||||
{xs : Array α} (g : α → β) (f : (b : β) → b ∈ xs.map g → γ → m (ForInStep γ)) :
|
||||
forIn' (xs.map g) init f = forIn' xs init fun a h y => f (g a) (mem_map_of_mem h) y := by
|
||||
@@ -249,13 +238,6 @@ theorem idRun_forIn_yield_eq_foldl
|
||||
xs.foldl (fun b a => f a b |>.run) init := by
|
||||
simp
|
||||
|
||||
@[deprecated idRun_forIn_yield_eq_foldl (since := "2025-05-21")]
|
||||
theorem forIn_yield_eq_foldl
|
||||
{xs : Array α} (f : α → β → β) (init : β) :
|
||||
forIn (m := Id) xs init (fun a b => .yield (f a b)) =
|
||||
xs.foldl (fun b a => f a b) init :=
|
||||
forIn_pure_yield_eq_foldl _ _
|
||||
|
||||
@[simp, grind =] theorem forIn_map [Monad m] [LawfulMonad m]
|
||||
{xs : Array α} {g : α → β} {f : β → γ → m (ForInStep γ)} :
|
||||
forIn (xs.map g) init f = forIn xs init fun a y => f (g a) y := by
|
||||
|
||||
@@ -280,7 +280,7 @@ Checks whether any of the elements in a subarray satisfy a Boolean predicate.
|
||||
The elements are tested starting at the lowest index and moving up. The search terminates as soon as
|
||||
an element that satisfies the predicate is found.
|
||||
-/
|
||||
@[inline]
|
||||
@[inline, suggest_for Subarray.some]
|
||||
def any {α : Type u} (p : α → Bool) (as : Subarray α) : Bool :=
|
||||
Id.run <| as.anyM (pure <| p ·)
|
||||
|
||||
@@ -290,7 +290,7 @@ Checks whether all of the elements in a subarray satisfy a Boolean predicate.
|
||||
The elements are tested starting at the lowest index and moving up. The search terminates as soon as
|
||||
an element that does not satisfy the predicate is found.
|
||||
-/
|
||||
@[inline]
|
||||
@[inline, suggest_for Subarray.every]
|
||||
def all {α : Type u} (p : α → Bool) (as : Subarray α) : Bool :=
|
||||
Id.run <| as.allM (pure <| p ·)
|
||||
|
||||
|
||||
@@ -353,14 +353,6 @@ theorem zipWithM_eq_mapM_id_zipWith {m : Type v → Type w} [Monad m] [LawfulMon
|
||||
|
||||
/-! ### unzip -/
|
||||
|
||||
@[deprecated fst_unzip (since := "2025-05-26")]
|
||||
theorem unzip_fst : (unzip l).fst = l.map Prod.fst := by
|
||||
simp
|
||||
|
||||
@[deprecated snd_unzip (since := "2025-05-26")]
|
||||
theorem unzip_snd : (unzip l).snd = l.map Prod.snd := by
|
||||
simp
|
||||
|
||||
@[grind =]
|
||||
theorem unzip_eq_map {xs : Array (α × β)} : unzip xs = (xs.map Prod.fst, xs.map Prod.snd) := by
|
||||
cases xs
|
||||
|
||||
@@ -77,9 +77,6 @@ Returns the `i`th least significant bit.
|
||||
-/
|
||||
@[inline, expose] def getLsb (x : BitVec w) (i : Fin w) : Bool := x.toNat.testBit i
|
||||
|
||||
@[deprecated getLsb (since := "2025-06-17"), inherit_doc getLsb]
|
||||
abbrev getLsb' := @getLsb
|
||||
|
||||
/-- Returns the `i`th least significant bit, or `none` if `i ≥ w`. -/
|
||||
@[inline, expose] def getLsb? (x : BitVec w) (i : Nat) : Option Bool :=
|
||||
if h : i < w then some (getLsb x ⟨i, h⟩) else none
|
||||
@@ -89,9 +86,6 @@ Returns the `i`th most significant bit.
|
||||
-/
|
||||
@[inline] def getMsb (x : BitVec w) (i : Fin w) : Bool := x.getLsb ⟨w-1-i, by omega⟩
|
||||
|
||||
@[deprecated getMsb (since := "2025-06-17"), inherit_doc getMsb]
|
||||
abbrev getMsb' := @getMsb
|
||||
|
||||
/-- Returns the `i`th most significant bit or `none` if `i ≥ w`. -/
|
||||
@[inline] def getMsb? (x : BitVec w) (i : Nat) : Option Bool :=
|
||||
if h : i < w then some (getMsb x ⟨i, h⟩) else none
|
||||
|
||||
@@ -835,7 +835,7 @@ execution. -/
|
||||
structure DivModArgs (w : Nat) where
|
||||
/-- the numerator (aka, dividend) -/
|
||||
n : BitVec w
|
||||
/-- the denumerator (aka, divisor)-/
|
||||
/-- the denominator (aka, divisor)-/
|
||||
d : BitVec w
|
||||
|
||||
/-- A `DivModState` is lawful if the remainder width `wr` plus the numerator width `wn` equals `w`,
|
||||
|
||||
@@ -145,10 +145,6 @@ theorem two_pow_le_toNat_of_getElem_eq_true {i : Nat} {x : BitVec w}
|
||||
@[grind =] theorem getMsbD_eq_getLsbD (x : BitVec w) (i : Nat) : x.getMsbD i = (decide (i < w) && x.getLsbD (w - 1 - i)) := by
|
||||
rw [getMsbD, getLsbD]
|
||||
|
||||
@[deprecated getMsb_eq_getLsb (since := "2025-06-17")]
|
||||
theorem getMsb'_eq_getLsb' (x : BitVec w) (i : Nat) : x.getMsbD i = (decide (i < w) && x.getLsbD (w - 1 - i)) := by
|
||||
rw [getMsbD, getLsbD]
|
||||
|
||||
theorem getLsbD_eq_getMsbD (x : BitVec w) (i : Nat) : x.getLsbD i = (decide (i < w) && x.getMsbD (w - 1 - i)) := by
|
||||
rw [getMsbD]
|
||||
by_cases h₁ : i < w <;> by_cases h₂ : w - 1 - i < w <;>
|
||||
@@ -5601,7 +5597,7 @@ theorem msb_eq_toNat {x : BitVec w}:
|
||||
simp only [msb_eq_decide, ge_iff_le]
|
||||
|
||||
/-- Negating a bitvector created from a natural number equals
|
||||
creating a bitvector from the the negative of that number.
|
||||
creating a bitvector from the negative of that number.
|
||||
-/
|
||||
theorem neg_ofNat_eq_ofInt_neg {w : Nat} {x : Nat} :
|
||||
- BitVec.ofNat w x = BitVec.ofInt w (- x) := by
|
||||
|
||||
@@ -260,7 +260,7 @@ instance : Std.Associative (· != ·) := ⟨bne_assoc⟩
|
||||
|
||||
theorem eq_not_of_ne : ∀ {x y : Bool}, x ≠ y → x = !y := by decide
|
||||
|
||||
/-! ### coercision related normal forms -/
|
||||
/-! ### coercion related normal forms -/
|
||||
|
||||
theorem beq_eq_decide_eq [BEq α] [LawfulBEq α] [DecidableEq α] (a b : α) :
|
||||
(a == b) = decide (a = b) := by
|
||||
|
||||
@@ -56,10 +56,6 @@ theorem Internal.ofNat_eq_ofNat {n : Nat} {hn} {a : Nat} :
|
||||
letI : NeZero n := ⟨Nat.pos_iff_ne_zero.1 hn⟩
|
||||
Fin.Internal.ofNat n hn a = Fin.ofNat n a := rfl
|
||||
|
||||
@[deprecated Fin.ofNat (since := "2025-05-28")]
|
||||
protected def ofNat' (n : Nat) [NeZero n] (a : Nat) : Fin n :=
|
||||
Fin.ofNat n a
|
||||
|
||||
-- We provide this because other similar types have a `toNat` function, but `simp` rewrites
|
||||
-- `i.toNat` to `i.val`.
|
||||
/--
|
||||
|
||||
@@ -18,8 +18,6 @@ namespace Fin
|
||||
|
||||
@[simp, grind =] theorem ofNat_zero (n : Nat) [NeZero n] : Fin.ofNat n 0 = 0 := rfl
|
||||
|
||||
@[deprecated ofNat_zero (since := "2025-05-28")] abbrev ofNat'_zero := @ofNat_zero
|
||||
|
||||
theorem mod_def (a m : Fin n) : a % m = Fin.mk (a.val % m.val) (Nat.lt_of_le_of_lt (Nat.mod_le _ _) a.2) :=
|
||||
rfl
|
||||
|
||||
@@ -76,22 +74,16 @@ theorem mk_val (i : Fin n) : (⟨i, i.isLt⟩ : Fin n) = i := Fin.eta ..
|
||||
@[simp, grind =] theorem val_ofNat (n : Nat) [NeZero n] (a : Nat) :
|
||||
(Fin.ofNat n a).val = a % n := rfl
|
||||
|
||||
@[deprecated val_ofNat (since := "2025-05-28")] abbrev val_ofNat' := @val_ofNat
|
||||
|
||||
@[simp, grind =] theorem ofNat_self {n : Nat} [NeZero n] : Fin.ofNat n n = 0 := by
|
||||
ext
|
||||
simp
|
||||
congr
|
||||
|
||||
@[deprecated ofNat_self (since := "2025-05-28")] abbrev ofNat'_self := @ofNat_self
|
||||
|
||||
@[simp] theorem ofNat_val_eq_self [NeZero n] (x : Fin n) : (Fin.ofNat n x.val) = x := by
|
||||
ext
|
||||
rw [val_ofNat, Nat.mod_eq_of_lt]
|
||||
exact x.2
|
||||
|
||||
@[deprecated ofNat_val_eq_self (since := "2025-05-28")] abbrev ofNat'_val_eq_self := @ofNat_val_eq_self
|
||||
|
||||
@[simp] theorem mod_val (a b : Fin n) : (a % b).val = a.val % b.val :=
|
||||
rfl
|
||||
|
||||
@@ -1084,15 +1076,11 @@ theorem ofNat_add [NeZero n] (x : Nat) (y : Fin n) :
|
||||
apply Fin.eq_of_val_eq
|
||||
simp [Fin.ofNat, Fin.add_def]
|
||||
|
||||
@[deprecated ofNat_add (since := "2025-05-28")] abbrev ofNat_add' := @ofNat_add
|
||||
|
||||
theorem add_ofNat [NeZero n] (x : Fin n) (y : Nat) :
|
||||
x + Fin.ofNat n y = Fin.ofNat n (x.val + y) := by
|
||||
apply Fin.eq_of_val_eq
|
||||
simp [Fin.ofNat, Fin.add_def]
|
||||
|
||||
@[deprecated add_ofNat (since := "2025-05-28")] abbrev add_ofNat' := @add_ofNat
|
||||
|
||||
/-! ### sub -/
|
||||
|
||||
@[deprecated val_sub (since := "2025-11-21")]
|
||||
@@ -1104,15 +1092,11 @@ theorem ofNat_sub [NeZero n] (x : Nat) (y : Fin n) :
|
||||
apply Fin.eq_of_val_eq
|
||||
simp [Fin.ofNat, Fin.sub_def]
|
||||
|
||||
@[deprecated ofNat_sub (since := "2025-05-28")] abbrev ofNat_sub' := @ofNat_sub
|
||||
|
||||
theorem sub_ofNat [NeZero n] (x : Fin n) (y : Nat) :
|
||||
x - Fin.ofNat n y = Fin.ofNat n ((n - y % n) + x.val) := by
|
||||
apply Fin.eq_of_val_eq
|
||||
simp [Fin.ofNat, Fin.sub_def]
|
||||
|
||||
@[deprecated sub_ofNat (since := "2025-05-28")] abbrev sub_ofNat' := @sub_ofNat
|
||||
|
||||
@[simp] protected theorem sub_self [NeZero n] {x : Fin n} : x - x = 0 := by
|
||||
ext
|
||||
rw [Fin.sub_def]
|
||||
@@ -1175,15 +1159,11 @@ theorem ofNat_mul [NeZero n] (x : Nat) (y : Fin n) :
|
||||
apply Fin.eq_of_val_eq
|
||||
simp [Fin.ofNat, Fin.mul_def]
|
||||
|
||||
@[deprecated ofNat_mul (since := "2025-05-28")] abbrev ofNat_mul' := @ofNat_mul
|
||||
|
||||
theorem mul_ofNat [NeZero n] (x : Fin n) (y : Nat) :
|
||||
x * Fin.ofNat n y = Fin.ofNat n (x.val * y) := by
|
||||
apply Fin.eq_of_val_eq
|
||||
simp [Fin.ofNat, Fin.mul_def]
|
||||
|
||||
@[deprecated mul_ofNat (since := "2025-05-28")] abbrev mul_ofNat' := @mul_ofNat
|
||||
|
||||
@[deprecated val_mul (since := "2025-10-26")]
|
||||
theorem coe_mul {n : Nat} : ∀ a b : Fin n, ((a * b : Fin n) : Nat) = a * b % n
|
||||
| ⟨_, _⟩, ⟨_, _⟩ => rfl
|
||||
|
||||
@@ -42,7 +42,7 @@ instance : EmptyCollection FloatArray where
|
||||
def push : FloatArray → Float → FloatArray
|
||||
| ⟨ds⟩, b => ⟨ds.push b⟩
|
||||
|
||||
@[extern "lean_float_array_size"]
|
||||
@[extern "lean_float_array_size", tagged_return]
|
||||
def size : (@& FloatArray) → Nat
|
||||
| ⟨ds⟩ => ds.size
|
||||
|
||||
|
||||
@@ -42,6 +42,7 @@ larger numbers use a fast arbitrary-precision arithmetic library (usually
|
||||
than the platform's pointer size (i.e. 63 bits on 64-bit architectures and 31 bits on 32-bit
|
||||
architectures).
|
||||
-/
|
||||
@[suggest_for ℤ]
|
||||
inductive Int : Type where
|
||||
/--
|
||||
A natural number is an integer.
|
||||
@@ -278,7 +279,11 @@ set_option bootstrap.genMatcherCode false in
|
||||
def decNonneg (m : @& Int) : Decidable (NonNeg m) :=
|
||||
match m with
|
||||
| ofNat m => isTrue <| NonNeg.mk m
|
||||
| -[_ +1] => isFalse <| fun h => nomatch h
|
||||
| -[i +1] => isFalse <| fun h =>
|
||||
have : ∀ j, (j = -[i +1]) → NonNeg j → False := fun _ hj hnn =>
|
||||
Int.NonNeg.casesOn (motive := fun j _ => j = -[i +1] → False) hnn
|
||||
(fun _ h => Int.noConfusion h) hj
|
||||
this -[i +1] rfl h
|
||||
|
||||
/-- Decides whether `a ≤ b`.
|
||||
|
||||
|
||||
@@ -29,13 +29,6 @@ theorem subNatNat_of_sub_eq_succ {m n k : Nat} (h : n - m = succ k) : subNatNat
|
||||
@[norm_cast] theorem natCast_succ (n : Nat) : (succ n : Int) = n + 1 := rfl
|
||||
@[norm_cast] theorem natCast_add_one (n : Nat) : ((n + 1 : Nat) : Int) = n + 1 := rfl
|
||||
|
||||
@[deprecated natCast_add (since := "2025-04-17")]
|
||||
theorem ofNat_add (n m : Nat) : (↑(n + m) : Int) = n + m := rfl
|
||||
@[deprecated natCast_mul (since := "2025-04-17")]
|
||||
theorem ofNat_mul (n m : Nat) : (↑(n * m) : Int) = n * m := rfl
|
||||
@[deprecated natCast_succ (since := "2025-04-17")]
|
||||
theorem ofNat_succ (n : Nat) : (succ n : Int) = n + 1 := rfl
|
||||
|
||||
theorem neg_ofNat_zero : -((0 : Nat) : Int) = 0 := rfl
|
||||
theorem neg_ofNat_succ (n : Nat) : -(succ n : Int) = -[n+1] := rfl
|
||||
@[simp] theorem neg_negSucc (n : Nat) : -(-[n+1]) = ((n + 1 : Nat) : Int) := rfl
|
||||
|
||||
@@ -81,10 +81,7 @@ theorem lt.dest {a b : Int} (h : a < b) : ∃ n : Nat, a + Nat.succ n = b :=
|
||||
@[simp, norm_cast] theorem ofNat_lt {n m : Nat} : (↑n : Int) < ↑m ↔ n < m := by
|
||||
rw [lt_iff_add_one_le, ← natCast_succ, ofNat_le]; rfl
|
||||
|
||||
@[simp, norm_cast] theorem natCast_pos {n : Nat} : (0 : Int) < n ↔ 0 < n := ofNat_lt
|
||||
|
||||
@[deprecated natCast_pos (since := "2025-05-13"), simp high]
|
||||
theorem ofNat_pos {n : Nat} : 0 < (↑n : Int) ↔ 0 < n := ofNat_lt
|
||||
@[simp high, norm_cast] theorem natCast_pos {n : Nat} : (0 : Int) < n ↔ 0 < n := ofNat_lt
|
||||
|
||||
@[simp]
|
||||
theorem natCast_nonneg (n : Nat) : 0 ≤ (n : Int) := ⟨_⟩
|
||||
@@ -92,6 +89,8 @@ theorem natCast_nonneg (n : Nat) : 0 ≤ (n : Int) := ⟨_⟩
|
||||
@[deprecated natCast_nonneg (since := "2025-10-26")]
|
||||
theorem ofNat_zero_le (n : Nat) : 0 ≤ (↑n : Int) := ofNat_le.2 n.zero_le
|
||||
|
||||
-- This was still being used in `omega` as of 2025-12-12,
|
||||
-- so we're keeping this for another month.
|
||||
@[deprecated natCast_nonneg (since := "2025-05-13")]
|
||||
theorem ofNat_nonneg (n : Nat) : 0 ≤ (n : Int) := ⟨_⟩
|
||||
|
||||
|
||||
@@ -77,8 +77,6 @@ public theorem Shrink.deflate_inj {α} {x y : α} :
|
||||
· rintro rfl
|
||||
rfl
|
||||
|
||||
namespace Iterators
|
||||
|
||||
-- It is not fruitful to move the following docstrings to verso right now because there are lots of
|
||||
-- forward references that cannot be realized nicely.
|
||||
set_option doc.verso false
|
||||
@@ -124,6 +122,7 @@ def x := ([1, 2, 3].iterM IO : IterM IO Nat)
|
||||
-/
|
||||
@[ext]
|
||||
structure IterM {α : Type w} (m : Type w → Type w') (β : Type w) where
|
||||
mk' ::
|
||||
/-- Internal implementation detail of the iterator. -/
|
||||
internalState : α
|
||||
|
||||
@@ -358,21 +357,27 @@ class Iterator (α : Type w) (m : Type w → Type w') (β : outParam (Type w)) w
|
||||
section Monadic
|
||||
|
||||
/--
|
||||
Converts wraps the state of an iterator into an `IterM` object.
|
||||
Wraps the state of an iterator into an `IterM` object.
|
||||
-/
|
||||
@[always_inline, inline, expose]
|
||||
def toIterM {α : Type w} (it : α) (m : Type w → Type w') (β : Type w) :
|
||||
def IterM.mk {α : Type w} (it : α) (m : Type w → Type w') (β : Type w) :
|
||||
IterM (α := α) m β :=
|
||||
⟨it⟩
|
||||
|
||||
@[deprecated IterM.mk (since := "2025-12-01"), inline, expose]
|
||||
def Iterators.toIterM := @IterM.mk
|
||||
|
||||
@[simp]
|
||||
theorem toIterM_internalState {α m β} (it : IterM (α := α) m β) :
|
||||
toIterM it.internalState m β = it :=
|
||||
theorem IterM.mk_internalState {α m β} (it : IterM (α := α) m β) :
|
||||
.mk it.internalState m β = it :=
|
||||
rfl
|
||||
|
||||
@[deprecated IterM.mk_internalState (since := "2025-12-01")]
|
||||
def Iterators.toIterM_internalState := @IterM.mk_internalState
|
||||
|
||||
@[simp]
|
||||
theorem internalState_toIterM {α m β} (it : α) :
|
||||
(toIterM it m β).internalState = it :=
|
||||
(IterM.mk it m β).internalState = it :=
|
||||
rfl
|
||||
|
||||
/--
|
||||
@@ -393,6 +398,16 @@ abbrev IterM.Step {α : Type w} {m : Type w → Type w'} {β : Type w} [Iterator
|
||||
(it : IterM (α := α) m β) :=
|
||||
PlausibleIterStep it.IsPlausibleStep
|
||||
|
||||
/--
|
||||
Makes a single step with the given iterator `it`, potentially emitting a value and providing a
|
||||
succeeding iterator. If this function is used recursively, termination can sometimes be proved with
|
||||
the termination measures `it.finitelyManySteps` and `it.finitelyManySkips`.
|
||||
-/
|
||||
@[always_inline, inline, expose]
|
||||
def IterM.step {α : Type w} {m : Type w → Type w'} {β : Type w} [Iterator α m β]
|
||||
(it : IterM (α := α) m β) : m (Shrink it.Step) :=
|
||||
Iterator.step it
|
||||
|
||||
/--
|
||||
Asserts that a certain output value could plausibly be emitted by the given iterator in its next
|
||||
step.
|
||||
@@ -420,16 +435,6 @@ def IterM.IsPlausibleSkipSuccessorOf {α : Type w} {m : Type w → Type w'} {β
|
||||
[Iterator α m β] (it' it : IterM (α := α) m β) : Prop :=
|
||||
it.IsPlausibleStep (.skip it')
|
||||
|
||||
/--
|
||||
Makes a single step with the given iterator `it`, potentially emitting a value and providing a
|
||||
succeeding iterator. If this function is used recursively, termination can sometimes be proved with
|
||||
the termination measures `it.finitelyManySteps` and `it.finitelyManySkips`.
|
||||
-/
|
||||
@[always_inline, inline, expose]
|
||||
def IterM.step {α : Type w} {m : Type w → Type w'} {β : Type w} [Iterator α m β]
|
||||
(it : IterM (α := α) m β) : m (Shrink it.Step) :=
|
||||
Iterator.step it
|
||||
|
||||
end Monadic
|
||||
|
||||
section Pure
|
||||
@@ -677,11 +682,11 @@ this means that the relation of plausible successors is well-founded.
|
||||
Given this typeclass, termination proofs for well-founded recursion over an iterator `it` can use
|
||||
`it.finitelyManySteps` as a termination measure.
|
||||
-/
|
||||
class Finite (α : Type w) (m : Type w → Type w') {β : Type w} [Iterator α m β] : Prop where
|
||||
class Iterators.Finite (α : Type w) (m : Type w → Type w') {β : Type w} [Iterator α m β] : Prop where
|
||||
/-- The relation of plausible successors is well-founded. -/
|
||||
wf : WellFounded (IterM.IsPlausibleSuccessorOf (α := α) (m := m))
|
||||
|
||||
theorem Finite.wf_of_id {α : Type w} {β : Type w} [Iterator α Id β] [Finite α Id] :
|
||||
theorem Iterators.Finite.wf_of_id {α : Type w} {β : Type w} [Iterator α Id β] [Finite α Id] :
|
||||
WellFounded (Iter.IsPlausibleSuccessorOf (α := α)) := by
|
||||
simpa [Iter.isPlausibleSuccessorOf_eq_invImage] using InvImage.wf _ Finite.wf
|
||||
|
||||
@@ -703,10 +708,11 @@ def IterM.TerminationMeasures.Finite.Rel
|
||||
TerminationMeasures.Finite α m → TerminationMeasures.Finite α m → Prop :=
|
||||
Relation.TransGen <| InvImage IterM.IsPlausibleSuccessorOf IterM.TerminationMeasures.Finite.it
|
||||
|
||||
instance {α : Type w} {m : Type w → Type w'} {β : Type w} [Iterator α m β]
|
||||
[Finite α m] : WellFoundedRelation (IterM.TerminationMeasures.Finite α m) where
|
||||
instance IterM.TerminationMeasures.instWellFoundedRelationFinite {α : Type w} {m : Type w → Type w'}
|
||||
{β : Type w} [Iterator α m β] [Iterators.Finite α m] :
|
||||
WellFoundedRelation (IterM.TerminationMeasures.Finite α m) where
|
||||
rel := IterM.TerminationMeasures.Finite.Rel
|
||||
wf := by exact (InvImage.wf _ Finite.wf).transGen
|
||||
wf := by exact (InvImage.wf _ Iterators.Finite.wf).transGen
|
||||
|
||||
/--
|
||||
Termination measure to be used in well-founded recursive functions recursing over a finite iterator
|
||||
@@ -714,7 +720,16 @@ Termination measure to be used in well-founded recursive functions recursing ove
|
||||
-/
|
||||
@[expose]
|
||||
def IterM.finitelyManySteps {α : Type w} {m : Type w → Type w'} {β : Type w} [Iterator α m β]
|
||||
[Finite α m] (it : IterM (α := α) m β) : IterM.TerminationMeasures.Finite α m :=
|
||||
[Iterators.Finite α m] (it : IterM (α := α) m β) : IterM.TerminationMeasures.Finite α m :=
|
||||
⟨it⟩
|
||||
|
||||
/--
|
||||
Termination measure to be used in well-founded recursive functions recursing over a finite iterator
|
||||
(see also `Finite`).
|
||||
-/
|
||||
@[expose]
|
||||
def IterM.finitelyManySteps! {α : Type w} {m : Type w → Type w'} {β : Type w} [Iterator α m β]
|
||||
(it : IterM (α := α) m β) : IterM.TerminationMeasures.Finite α m :=
|
||||
⟨it⟩
|
||||
|
||||
/--
|
||||
@@ -747,7 +762,7 @@ macro_rules | `(tactic| decreasing_trivial) => `(tactic|
|
||||
| fail)
|
||||
|
||||
@[inherit_doc IterM.finitelyManySteps, expose]
|
||||
def Iter.finitelyManySteps {α : Type w} {β : Type w} [Iterator α Id β] [Finite α Id]
|
||||
def Iter.finitelyManySteps {α : Type w} {β : Type w} [Iterator α Id β] [Iterators.Finite α Id]
|
||||
(it : Iter (α := α) β) : IterM.TerminationMeasures.Finite α Id :=
|
||||
it.toIterM.finitelyManySteps
|
||||
|
||||
@@ -797,7 +812,7 @@ well-founded.
|
||||
Given this typeclass, termination proofs for well-founded recursion over an iterator `it` can use
|
||||
`it.finitelyManySkips` as a termination measure.
|
||||
-/
|
||||
class Productive (α m) {β} [Iterator α m β] : Prop where
|
||||
class Iterators.Productive (α m) {β} [Iterator α m β] : Prop where
|
||||
/-- The relation of plausible successors during skips is well-founded. -/
|
||||
wf : WellFounded (IterM.IsPlausibleSkipSuccessorOf (α := α) (m := m))
|
||||
|
||||
@@ -837,10 +852,11 @@ theorem IterM.TerminationMeasures.Finite.Rel.of_productive
|
||||
refine .trans ih ?_
|
||||
exact .single ⟨_, rfl, hab⟩
|
||||
|
||||
instance {α : Type w} {m : Type w → Type w'} {β : Type w} [Iterator α m β]
|
||||
[Productive α m] : WellFoundedRelation (IterM.TerminationMeasures.Productive α m) where
|
||||
instance IterM.TerminationMeasures.instWellFoundedRelationProductive {α : Type w}
|
||||
{m : Type w → Type w'} {β : Type w} [Iterator α m β] [Iterators.Productive α m] :
|
||||
WellFoundedRelation (IterM.TerminationMeasures.Productive α m) where
|
||||
rel := IterM.TerminationMeasures.Productive.Rel
|
||||
wf := by exact (InvImage.wf _ Productive.wf).transGen
|
||||
wf := by exact (InvImage.wf _ Iterators.Productive.wf).transGen
|
||||
|
||||
/--
|
||||
Termination measure to be used in well-founded recursive functions recursing over a productive
|
||||
@@ -848,7 +864,7 @@ iterator (see also `Productive`).
|
||||
-/
|
||||
@[expose]
|
||||
def IterM.finitelyManySkips {α : Type w} {m : Type w → Type w'} {β : Type w} [Iterator α m β]
|
||||
[Productive α m] (it : IterM (α := α) m β) : IterM.TerminationMeasures.Productive α m :=
|
||||
[Iterators.Productive α m] (it : IterM (α := α) m β) : IterM.TerminationMeasures.Productive α m :=
|
||||
⟨it⟩
|
||||
|
||||
/--
|
||||
@@ -867,7 +883,7 @@ macro_rules | `(tactic| decreasing_trivial) => `(tactic|
|
||||
| fail)
|
||||
|
||||
@[inherit_doc IterM.finitelyManySkips, expose]
|
||||
def Iter.finitelyManySkips {α : Type w} {β : Type w} [Iterator α Id β] [Productive α Id]
|
||||
def Iter.finitelyManySkips {α : Type w} {β : Type w} [Iterator α Id β] [Iterators.Productive α Id]
|
||||
(it : Iter (α := α) β) : IterM.TerminationMeasures.Productive α Id :=
|
||||
it.toIterM.finitelyManySkips
|
||||
|
||||
@@ -886,12 +902,13 @@ macro_rules | `(tactic| decreasing_trivial) => `(tactic|
|
||||
| exact Iter.TerminationMeasures.Productive.rel_of_skip ‹_›
|
||||
| fail)
|
||||
|
||||
instance [Iterator α m β] [Finite α m] : Productive α m where
|
||||
instance Iterators.instProductiveOfFinte [Iterator α m β] [Iterators.Finite α m] :
|
||||
Iterators.Productive α m where
|
||||
wf := by
|
||||
apply Subrelation.wf (r := IterM.IsPlausibleSuccessorOf)
|
||||
· intro it' it h
|
||||
exact IterM.isPlausibleSuccessorOf_of_skip h
|
||||
· exact Finite.wf
|
||||
· exact Iterators.Finite.wf
|
||||
|
||||
end Productive
|
||||
|
||||
@@ -910,8 +927,4 @@ class LawfulDeterministicIterator (α : Type w) (m : Type w → Type w') [Iterat
|
||||
where
|
||||
isPlausibleStep_eq_eq : ∀ it : IterM (α := α) m β, ∃ step, it.IsPlausibleStep = (· = step)
|
||||
|
||||
end Iterators
|
||||
|
||||
export Iterators (Iter IterM)
|
||||
|
||||
end Std
|
||||
|
||||
@@ -11,7 +11,8 @@ public import Init.Data.Iterators.Combinators.FilterMap
|
||||
|
||||
public section
|
||||
|
||||
namespace Std.Iterators
|
||||
namespace Std
|
||||
open Std.Iterators
|
||||
|
||||
@[always_inline, inline, expose, inherit_doc IterM.attachWith]
|
||||
def Iter.attachWith {α β : Type w}
|
||||
@@ -24,4 +25,4 @@ where finally
|
||||
simp only [← isPlausibleIndirectOutput_iff_isPlausibleIndirectOutput_toIterM]
|
||||
exact h
|
||||
|
||||
end Std.Iterators
|
||||
end Std
|
||||
|
||||
@@ -30,7 +30,8 @@ Several variants of these combinators are provided:
|
||||
iterator, and particularly for specialized termination proofs. If possible, avoid this.
|
||||
-/
|
||||
|
||||
namespace Std.Iterators
|
||||
namespace Std
|
||||
open Std.Iterators
|
||||
|
||||
-- We cannot use `inherit_doc` because the docstring for `IterM` states that a `MonadLiftT` instance
|
||||
-- is needed.
|
||||
@@ -305,4 +306,4 @@ def Iter.map {α : Type w} {β : Type w} {γ : Type w} [Iterator α Id β]
|
||||
(f : β → γ) (it : Iter (α := α) β) :=
|
||||
((it.toIterM.map f).toIter : Iter γ)
|
||||
|
||||
end Std.Iterators
|
||||
end Std
|
||||
|
||||
@@ -24,7 +24,7 @@ and so on. In other words, {lit}`it` flattens the iterator of iterators obtained
|
||||
{lit}`f`.
|
||||
-/
|
||||
|
||||
namespace Std.Iterators
|
||||
namespace Std
|
||||
|
||||
@[always_inline, inherit_doc IterM.flatMapAfterM]
|
||||
public def Iter.flatMapAfterM {α : Type w} {β : Type w} {α₂ : Type w}
|
||||
@@ -49,5 +49,3 @@ public def Iter.flatMap {α : Type w} {β : Type w} {α₂ : Type w}
|
||||
{γ : Type w} [Iterator α Id β] [Iterator α₂ Id γ]
|
||||
(f : β → Iter (α := α₂) γ) (it : Iter (α := α) β) :=
|
||||
(it.flatMapAfter f none : Iter γ)
|
||||
|
||||
end Std.Iterators
|
||||
|
||||
@@ -91,22 +91,12 @@ instance Attach.instIteratorCollect {α β : Type w} {m : Type w → Type w'} [M
|
||||
IteratorCollect (Attach α m P) m n :=
|
||||
.defaultImplementation
|
||||
|
||||
instance Attach.instIteratorCollectPartial {α β : Type w} {m : Type w → Type w'} [Monad m]
|
||||
[Monad n] {P : β → Prop} [Iterator α m β] :
|
||||
IteratorCollectPartial (Attach α m P) m n :=
|
||||
.defaultImplementation
|
||||
|
||||
instance Attach.instIteratorLoop {α β : Type w} {m : Type w → Type w'} [Monad m]
|
||||
{n : Type x → Type x'} [Monad n] {P : β → Prop} [Iterator α m β] :
|
||||
IteratorLoop (Attach α m P) m n :=
|
||||
.defaultImplementation
|
||||
|
||||
instance Attach.instIteratorLoopPartial {α β : Type w} {m : Type w → Type w'} [Monad m]
|
||||
{n : Type x → Type x'} [Monad n] {P : β → Prop} [Iterator α m β] :
|
||||
IteratorLoopPartial (Attach α m P) m n :=
|
||||
.defaultImplementation
|
||||
|
||||
end Types
|
||||
end Iterators.Types
|
||||
|
||||
/--
|
||||
“Attaches” individual proofs to an iterator of values that satisfy a predicate `P`, returning an
|
||||
@@ -121,7 +111,7 @@ iterator with values in the corresponding subtype `{ x // P x }`.
|
||||
def IterM.attachWith {α β : Type w} {m : Type w → Type w'} [Monad m]
|
||||
[Iterator α m β] (it : IterM (α := α) m β) (P : β → Prop)
|
||||
(h : ∀ out, it.IsPlausibleIndirectOutput out → P out) :
|
||||
IterM (α := Types.Attach α m P) m { out : β // P out } :=
|
||||
IterM (α := Iterators.Types.Attach α m P) m { out : β // P out } :=
|
||||
⟨⟨it, h⟩⟩
|
||||
|
||||
end Std.Iterators
|
||||
end Std
|
||||
|
||||
@@ -32,7 +32,9 @@ Several variants of these combinators are provided:
|
||||
iterator, and particularly for specialized termination proofs. If possible, avoid this.
|
||||
-/
|
||||
|
||||
namespace Std.Iterators
|
||||
namespace Std
|
||||
|
||||
namespace Iterators.Types
|
||||
|
||||
/--
|
||||
Internal state of the `filterMap` combinator. Do not depend on its internals.
|
||||
@@ -53,19 +55,23 @@ def Map (α : Type w) {β γ : Type w} (m : Type w → Type w') (n : Type w →
|
||||
(f : β → PostconditionT n γ) :=
|
||||
FilterMap α m n lift (fun b => PostconditionT.map some (f b))
|
||||
|
||||
end Iterators.Types
|
||||
|
||||
open Std.Iterators Std.Iterators.Types
|
||||
|
||||
@[always_inline, inline, expose]
|
||||
def IterM.InternalCombinators.filterMap {α β γ : Type w} {m : Type w → Type w'}
|
||||
{n : Type w → Type w''} (lift : ⦃α : Type w⦄ → m α → n α)
|
||||
[Iterator α m β] (f : β → PostconditionT n (Option γ))
|
||||
(it : IterM (α := α) m β) : IterM (α := FilterMap α m n lift f) n γ :=
|
||||
toIterM ⟨it⟩ n γ
|
||||
.mk ⟨it⟩ n γ
|
||||
|
||||
@[always_inline, inline, expose]
|
||||
def IterM.InternalCombinators.map {α β γ : Type w} {m : Type w → Type w'}
|
||||
{n : Type w → Type w''} [Monad n] (lift : ⦃α : Type w⦄ → m α → n α)
|
||||
[Iterator α m β] (f : β → PostconditionT n γ)
|
||||
(it : IterM (α := α) m β) : IterM (α := Map α m n lift f) n γ :=
|
||||
toIterM ⟨it⟩ n γ
|
||||
.mk ⟨it⟩ n γ
|
||||
|
||||
/--
|
||||
*Note: This is a very general combinator that requires an advanced understanding of monads,
|
||||
@@ -119,14 +125,16 @@ def IterM.filterMapWithPostcondition {α β γ : Type w} {m : Type w → Type w'
|
||||
(it : IterM (α := α) m β) : IterM (α := FilterMap α m n (fun ⦃_⦄ => monadLift) f) n γ :=
|
||||
IterM.InternalCombinators.filterMap (fun ⦃_⦄ => monadLift) f it
|
||||
|
||||
namespace Iterators.Types
|
||||
|
||||
/--
|
||||
`it.PlausibleStep step` is the proposition that `step` is a possible next step from the
|
||||
`filterMap` iterator `it`. This is mostly internally relevant, except if one needs to manually
|
||||
prove termination (`Finite` or `Productive` instances, for example) of a `filterMap` iterator.
|
||||
-/
|
||||
inductive FilterMap.PlausibleStep {α β γ : Type w} {m : Type w → Type w'} {n : Type w → Type w''}
|
||||
{lift : ⦃α : Type w⦄ → m α → n α} {f : β → PostconditionT n (Option γ)} [Iterator α m β]
|
||||
(it : IterM (α := FilterMap α m n lift f) n γ) :
|
||||
inductive FilterMap.PlausibleStep {α β γ : Type w} {m : Type w → Type w'}
|
||||
{n : Type w → Type w''} {lift : ⦃α : Type w⦄ → m α → n α} {f : β → PostconditionT n (Option γ)}
|
||||
[Iterator α m β] (it : IterM (α := FilterMap α m n lift f) n γ) :
|
||||
IterStep (IterM (α := FilterMap α m n lift f) n γ) γ → Prop where
|
||||
| yieldNone : ∀ {it' out},
|
||||
it.internalState.inner.IsPlausibleStep (.yield it' out) →
|
||||
@@ -139,8 +147,8 @@ inductive FilterMap.PlausibleStep {α β γ : Type w} {m : Type w → Type w'} {
|
||||
PlausibleStep it (.skip (IterM.InternalCombinators.filterMap lift f it'))
|
||||
| done : it.internalState.inner.IsPlausibleStep .done → PlausibleStep it .done
|
||||
|
||||
instance FilterMap.instIterator {α β γ : Type w} {m : Type w → Type w'} {n : Type w → Type w''}
|
||||
{lift : ⦃α : Type w⦄ → m α → n α} {f : β → PostconditionT n (Option γ)}
|
||||
instance FilterMap.instIterator {α β γ : Type w} {m : Type w → Type w'}
|
||||
{n : Type w → Type w''} {lift : ⦃α : Type w⦄ → m α → n α} {f : β → PostconditionT n (Option γ)}
|
||||
[Iterator α m β] [Monad n] :
|
||||
Iterator (FilterMap α m n lift f) n γ where
|
||||
IsPlausibleStep := FilterMap.PlausibleStep (m := m) (n := n)
|
||||
@@ -155,9 +163,8 @@ instance FilterMap.instIterator {α β γ : Type w} {m : Type w → Type w'} {n
|
||||
| .skip it' h => pure <| .deflate <| .skip (it'.filterMapWithPostcondition f) (by exact .skip h)
|
||||
| .done h => pure <| .deflate <| .done (.done h)
|
||||
|
||||
instance {α β γ : Type w} {m : Type w → Type w'} {n : Type w → Type w''} [Monad n] [Iterator α m β]
|
||||
{lift : ⦃α : Type w⦄ → m α → n α}
|
||||
{f : β → PostconditionT n γ} :
|
||||
instance Map.instIterator {α β γ : Type w} {m : Type w → Type w'} {n : Type w → Type w''} [Monad n]
|
||||
[Iterator α m β] {lift : ⦃α : Type w⦄ → m α → n α} {f : β → PostconditionT n γ} :
|
||||
Iterator (Map α m n lift f) n γ :=
|
||||
inferInstanceAs <| Iterator (FilterMap α m n lift _) n γ
|
||||
|
||||
@@ -189,8 +196,8 @@ instance FilterMap.instFinite {α β γ : Type w} {m : Type w → Type w'}
|
||||
Finite.of_finitenessRelation FilterMap.instFinitenessRelation
|
||||
|
||||
@[no_expose]
|
||||
instance {α β γ : Type w} {m : Type w → Type w'} {n : Type w → Type w''} [Monad n] [Iterator α m β]
|
||||
{lift : ⦃α : Type w⦄ → m α → n α} {f : β → PostconditionT n γ} [Finite α m] :
|
||||
instance Map.instFinite {α β γ : Type w} {m : Type w → Type w'} {n : Type w → Type w''} [Monad n]
|
||||
[Iterator α m β] {lift : ⦃α : Type w⦄ → m α → n α} {f : β → PostconditionT n γ} [Finite α m] :
|
||||
Finite (Map α m n lift f) n :=
|
||||
Finite.of_finitenessRelation FilterMap.instFinitenessRelation
|
||||
|
||||
@@ -214,32 +221,18 @@ instance Map.instProductive {α β γ : Type w} {m : Type w → Type w'}
|
||||
Productive (Map α m n lift f) n :=
|
||||
Productive.of_productivenessRelation Map.instProductivenessRelation
|
||||
|
||||
instance {α β γ : Type w} {m : Type w → Type w'}
|
||||
instance FilterMap.instIteratorCollect {α β γ : Type w} {m : Type w → Type w'}
|
||||
{n : Type w → Type w''} {o : Type w → Type x} [Monad n] [Monad o] [Iterator α m β]
|
||||
{lift : ⦃α : Type w⦄ → m α → n α}
|
||||
{f : β → PostconditionT n (Option γ)} :
|
||||
IteratorCollect (FilterMap α m n lift f) n o :=
|
||||
.defaultImplementation
|
||||
|
||||
instance {α β γ : Type w} {m : Type w → Type w'}
|
||||
{n : Type w → Type w''} {o : Type w → Type x} [Monad n] [Monad o] [Iterator α m β]
|
||||
{lift : ⦃α : Type w⦄ → m α → n α}
|
||||
{f : β → PostconditionT n (Option γ)} [Finite α m] :
|
||||
IteratorCollectPartial (FilterMap α m n lift f) n o :=
|
||||
.defaultImplementation
|
||||
|
||||
instance FilterMap.instIteratorLoop {α β γ : Type w} {m : Type w → Type w'}
|
||||
{n : Type w → Type w''} {o : Type x → Type x'}
|
||||
[Monad n] [Monad o] [Iterator α m β] {lift : ⦃α : Type w⦄ → m α → n α}
|
||||
{f : β → PostconditionT n (Option γ)} [Finite α m] :
|
||||
IteratorLoop (FilterMap α m n lift f) n o :=
|
||||
.defaultImplementation
|
||||
|
||||
instance FilterMap.instIteratorLoopPartial {α β γ : Type w} {m : Type w → Type w'}
|
||||
{n : Type w → Type w''} {o : Type x → Type x'}
|
||||
[Monad n] [Monad o] [Iterator α m β] {lift : ⦃α : Type w⦄ → m α → n α}
|
||||
{f : β → PostconditionT n (Option γ)} :
|
||||
IteratorLoopPartial (FilterMap α m n lift f) n o :=
|
||||
IteratorLoop (FilterMap α m n lift f) n o :=
|
||||
.defaultImplementation
|
||||
|
||||
/--
|
||||
@@ -249,7 +242,7 @@ instance FilterMap.instIteratorLoopPartial {α β γ : Type w} {m : Type w → T
|
||||
instance Map.instIteratorCollect {α β γ : Type w} {m : Type w → Type w'}
|
||||
{n : Type w → Type w''} {o : Type w → Type x} [Monad n] [Monad o] [Iterator α m β]
|
||||
{lift₁ : ⦃α : Type w⦄ → m α → n α}
|
||||
{f : β → PostconditionT n γ} [IteratorCollect α m o] [Finite α m] :
|
||||
{f : β → PostconditionT n γ} [IteratorCollect α m o] :
|
||||
IteratorCollect (Map α m n lift₁ f) n o where
|
||||
toArrayMapped lift₂ _ g it :=
|
||||
letI : MonadLift m n := ⟨lift₁ (α := _)⟩
|
||||
@@ -259,18 +252,6 @@ instance Map.instIteratorCollect {α β γ : Type w} {m : Type w → Type w'}
|
||||
(fun x => do g (← (f x).operation))
|
||||
it.internalState.inner (m := m)
|
||||
|
||||
@[no_expose]
|
||||
instance Map.instIteratorCollectPartial {α β γ : Type w} {m : Type w → Type w'}
|
||||
{n : Type w → Type w''} {o : Type w → Type x} [Monad n] [Monad o] [Iterator α m β]
|
||||
{lift₁ : ⦃α : Type w⦄ → m α → n α}
|
||||
{f : β → PostconditionT n γ} [IteratorCollectPartial α m o] :
|
||||
IteratorCollectPartial (Map α m n lift₁ f) n o where
|
||||
toArrayMappedPartial lift₂ _ g it :=
|
||||
IteratorCollectPartial.toArrayMappedPartial
|
||||
(lift := fun ⦃_⦄ a => lift₂ (lift₁ a))
|
||||
(fun x => do g (← lift₂ (f x).operation))
|
||||
it.internalState.inner (m := m)
|
||||
|
||||
instance Map.instIteratorLoop {α β γ : Type w} {m : Type w → Type w'}
|
||||
{n : Type w → Type w''} {o : Type x → Type x'} [Monad n] [Monad o] [Iterator α m β]
|
||||
{lift : ⦃α : Type w⦄ → m α → n α}
|
||||
@@ -278,12 +259,7 @@ instance Map.instIteratorLoop {α β γ : Type w} {m : Type w → Type w'}
|
||||
IteratorLoop (Map α m n lift f) n o :=
|
||||
.defaultImplementation
|
||||
|
||||
instance Map.instIteratorLoopPartial {α β γ : Type w} {m : Type w → Type w'}
|
||||
{n : Type w → Type w''} {o : Type x → Type x'} [Monad n] [Monad o] [Iterator α m β]
|
||||
{lift : ⦃α : Type w⦄ → m α → n α}
|
||||
{f : β → PostconditionT n γ} :
|
||||
IteratorLoopPartial (Map α m n lift f) n o :=
|
||||
.defaultImplementation
|
||||
end Iterators.Types
|
||||
|
||||
/--
|
||||
*Note: This is a very general combinator that requires an advanced understanding of monads, dependent
|
||||
@@ -604,4 +580,4 @@ def IterM.filter {α β : Type w} {m : Type w → Type w'} [Iterator α m β] [M
|
||||
(f : β → Bool) (it : IterM (α := α) m β) :=
|
||||
(it.filterMap (fun b => if f b then some b else none) : IterM m β)
|
||||
|
||||
end Std.Iterators
|
||||
end Std
|
||||
|
||||
@@ -22,22 +22,23 @@ and so on. In other words, `it` flattens the iterator of iterators obtained by m
|
||||
`f`.
|
||||
-/
|
||||
|
||||
namespace Std.Iterators
|
||||
namespace Std
|
||||
open Iterators.Types
|
||||
|
||||
/-- Internal implementation detail of the `flatMap` combinator -/
|
||||
@[ext, unbox]
|
||||
public structure Flatten (α α₂ β : Type w) (m) where
|
||||
public structure Iterators.Types.Flatten (α α₂ β : Type w) (m) where
|
||||
it₁ : IterM (α := α) m (IterM (α := α₂) m β)
|
||||
it₂ : Option (IterM (α := α₂) m β)
|
||||
|
||||
/--
|
||||
Internal iterator combinator that is used to implement all `flatMap` variants
|
||||
-/
|
||||
@[always_inline]
|
||||
@[always_inline, inline]
|
||||
def IterM.flattenAfter {α α₂ β : Type w} {m : Type w → Type w'} [Monad m]
|
||||
[Iterator α m (IterM (α := α₂) m β)] [Iterator α₂ m β]
|
||||
(it₁ : IterM (α := α) m (IterM (α := α₂) m β)) (it₂ : Option (IterM (α := α₂) m β)) :=
|
||||
(toIterM (α := Flatten α α₂ β m) ⟨it₁, it₂⟩ m β : IterM m β)
|
||||
(.mk (α := Flatten α α₂ β m) ⟨it₁, it₂⟩ m β : IterM m β)
|
||||
|
||||
/--
|
||||
Let `it₁` and `it₂` be iterators and `f` a monadic function mapping `it₁`'s outputs to iterators
|
||||
@@ -75,7 +76,7 @@ iterator.
|
||||
|
||||
For each value emitted by the outer iterator `it₁`, this combinator calls `f`.
|
||||
-/
|
||||
@[always_inline]
|
||||
@[always_inline, inline]
|
||||
public def IterM.flatMapAfterM {α : Type w} {β : Type w} {α₂ : Type w}
|
||||
{γ : Type w} {m : Type w → Type w'} [Monad m] [Iterator α m β] [Iterator α₂ m γ]
|
||||
(f : β → m (IterM (α := α₂) m γ)) (it₁ : IterM (α := α) m β) (it₂ : Option (IterM (α := α₂) m γ)) :=
|
||||
@@ -114,7 +115,7 @@ This combinator incurs an additional O(1) cost with each output of `it` or an in
|
||||
|
||||
For each value emitted by the outer iterator `it`, this combinator calls `f`.
|
||||
-/
|
||||
@[always_inline, expose]
|
||||
@[always_inline, inline, expose]
|
||||
public def IterM.flatMapM {α : Type w} {β : Type w} {α₂ : Type w}
|
||||
{γ : Type w} {m : Type w → Type w'} [Monad m] [Iterator α m β] [Iterator α₂ m γ]
|
||||
(f : β → m (IterM (α := α₂) m γ)) (it : IterM (α := α) m β) :=
|
||||
@@ -156,7 +157,7 @@ iterator.
|
||||
|
||||
For each value emitted by the outer iterator `it₁`, this combinator calls `f`.
|
||||
-/
|
||||
@[always_inline]
|
||||
@[always_inline, inline]
|
||||
public def IterM.flatMapAfter {α : Type w} {β : Type w} {α₂ : Type w}
|
||||
{γ : Type w} {m : Type w → Type w'} [Monad m] [Iterator α m β] [Iterator α₂ m γ]
|
||||
(f : β → IterM (α := α₂) m γ) (it₁ : IterM (α := α) m β) (it₂ : Option (IterM (α := α₂) m γ)) :=
|
||||
@@ -195,29 +196,31 @@ This combinator incurs an additional O(1) cost with each output of `it` or an in
|
||||
|
||||
For each value emitted by the outer iterator `it`, this combinator calls `f`.
|
||||
-/
|
||||
@[always_inline, expose]
|
||||
@[always_inline, inline, expose]
|
||||
public def IterM.flatMap {α : Type w} {β : Type w} {α₂ : Type w}
|
||||
{γ : Type w} {m : Type w → Type w'} [Monad m] [Iterator α m β] [Iterator α₂ m γ]
|
||||
(f : β → IterM (α := α₂) m γ) (it : IterM (α := α) m β) :=
|
||||
(it.flatMapAfter f none : IterM m γ)
|
||||
|
||||
namespace Iterators.Types
|
||||
|
||||
variable {α α₂ β : Type w} {m : Type w → Type w'}
|
||||
|
||||
/-- The plausible-step predicate for `Flatten` iterators -/
|
||||
public inductive Flatten.IsPlausibleStep [Iterator α m (IterM (α := α₂) m β)] [Iterator α₂ m β] :
|
||||
(it : IterM (α := Flatten α α₂ β m) m β) → (step : IterStep (IterM (α := Flatten α α₂ β m) m β) β) → Prop where
|
||||
| outerYield : ∀ {it₁ it₁' it₂'}, it₁.IsPlausibleStep (.yield it₁' it₂') →
|
||||
IsPlausibleStep (toIterM ⟨it₁, none⟩ m β) (.skip (toIterM ⟨it₁', some it₂'⟩ m β))
|
||||
IsPlausibleStep (.mk ⟨it₁, none⟩ m β) (.skip (.mk ⟨it₁', some it₂'⟩ m β))
|
||||
| outerSkip : ∀ {it₁ it₁'}, it₁.IsPlausibleStep (.skip it₁') →
|
||||
IsPlausibleStep (toIterM ⟨it₁, none⟩ m β) (.skip (toIterM ⟨it₁', none⟩ m β))
|
||||
IsPlausibleStep (.mk ⟨it₁, none⟩ m β) (.skip (.mk ⟨it₁', none⟩ m β))
|
||||
| outerDone : ∀ {it₁}, it₁.IsPlausibleStep .done →
|
||||
IsPlausibleStep (toIterM ⟨it₁, none⟩ m β) .done
|
||||
IsPlausibleStep (.mk ⟨it₁, none⟩ m β) .done
|
||||
| innerYield : ∀ {it₁ it₂ it₂' b}, it₂.IsPlausibleStep (.yield it₂' b) →
|
||||
IsPlausibleStep (toIterM ⟨it₁, some it₂⟩ m β) (.yield (toIterM ⟨it₁, some it₂'⟩ m β) b)
|
||||
IsPlausibleStep (.mk ⟨it₁, some it₂⟩ m β) (.yield (.mk ⟨it₁, some it₂'⟩ m β) b)
|
||||
| innerSkip : ∀ {it₁ it₂ it₂'}, it₂.IsPlausibleStep (.skip it₂') →
|
||||
IsPlausibleStep (toIterM ⟨it₁, some it₂⟩ m β) (.skip (toIterM ⟨it₁, some it₂'⟩ m β))
|
||||
IsPlausibleStep (.mk ⟨it₁, some it₂⟩ m β) (.skip (.mk ⟨it₁, some it₂'⟩ m β))
|
||||
| innerDone : ∀ {it₁ it₂}, it₂.IsPlausibleStep .done →
|
||||
IsPlausibleStep (toIterM ⟨it₁, some it₂⟩ m β) (.skip (toIterM ⟨it₁, none⟩ m β))
|
||||
IsPlausibleStep (.mk ⟨it₁, some it₂⟩ m β) (.skip (.mk ⟨it₁, none⟩ m β))
|
||||
|
||||
public instance Flatten.instIterator [Monad m] [Iterator α m (IterM (α := α₂) m β)] [Iterator α₂ m β] :
|
||||
Iterator (Flatten α α₂ β m) m β where
|
||||
@@ -246,7 +249,7 @@ section Finite
|
||||
variable {α : Type w} {α₂ : Type w} {β : Type w} {m : Type w → Type w'}
|
||||
|
||||
variable (α m β) in
|
||||
def Rel [Monad m] [Iterator α m (IterM (α := α₂) m β)] [Iterator α₂ m β] [Finite α m] [Finite α₂ m] :
|
||||
def Flatten.Rel [Monad m] [Iterator α m (IterM (α := α₂) m β)] [Iterator α₂ m β] [Finite α m] [Finite α₂ m] :
|
||||
IterM (α := Flatten α α₂ β m) m β → IterM (α := Flatten α α₂ β m) m β → Prop :=
|
||||
InvImage
|
||||
(Prod.Lex
|
||||
@@ -271,7 +274,7 @@ theorem Flatten.rel_of_right₂ [Monad m] [Iterator α m (IterM (α := α₂) m
|
||||
Rel α β m ⟨it₁, none⟩ ⟨it₁, some it₂⟩ :=
|
||||
Prod.Lex.right _ True.intro
|
||||
|
||||
instance [Monad m] [Iterator α m (IterM (α := α₂) m β)] [Iterator α₂ m β]
|
||||
def Flatten.instFinitenessRelation [Monad m] [Iterator α m (IterM (α := α₂) m β)] [Iterator α₂ m β]
|
||||
[Finite α m] [Finite α₂ m] :
|
||||
FinitenessRelation (Flatten α α₂ β m) m where
|
||||
rel := Rel α β m
|
||||
@@ -299,9 +302,9 @@ instance [Monad m] [Iterator α m (IterM (α := α₂) m β)] [Iterator α₂ m
|
||||
apply Flatten.rel_of_right₂
|
||||
|
||||
@[no_expose]
|
||||
public instance [Monad m] [Iterator α m (IterM (α := α₂) m β)] [Iterator α₂ m β]
|
||||
public instance Flatten.instFinite [Monad m] [Iterator α m (IterM (α := α₂) m β)] [Iterator α₂ m β]
|
||||
[Finite α m] [Finite α₂ m] : Finite (Flatten α α₂ β m) m :=
|
||||
.of_finitenessRelation instFinitenessRelationFlattenOfIterMOfFinite
|
||||
.of_finitenessRelation instFinitenessRelation
|
||||
|
||||
end Finite
|
||||
|
||||
@@ -310,7 +313,7 @@ section Productive
|
||||
variable {α : Type w} {α₂ : Type w} {β : Type w} {m : Type w → Type w'}
|
||||
|
||||
variable (α m β) in
|
||||
def ProductiveRel [Monad m] [Iterator α m (IterM (α := α₂) m β)] [Iterator α₂ m β] [Finite α m]
|
||||
def Flatten.ProductiveRel [Monad m] [Iterator α m (IterM (α := α₂) m β)] [Iterator α₂ m β] [Finite α m]
|
||||
[Productive α₂ m] :
|
||||
IterM (α := Flatten α α₂ β m) m β → IterM (α := Flatten α α₂ β m) m β → Prop :=
|
||||
InvImage
|
||||
@@ -336,8 +339,8 @@ theorem Flatten.productiveRel_of_right₂ [Monad m] [Iterator α m (IterM (α :=
|
||||
ProductiveRel α β m ⟨it₁, none⟩ ⟨it₁, some it₂⟩ :=
|
||||
Prod.Lex.right _ True.intro
|
||||
|
||||
instance [Monad m] [Iterator α m (IterM (α := α₂) m β)] [Iterator α₂ m β]
|
||||
[Finite α m] [Productive α₂ m] :
|
||||
def Flatten.instProductivenessRelation [Monad m] [Iterator α m (IterM (α := α₂) m β)]
|
||||
[Iterator α₂ m β] [Finite α m] [Productive α₂ m] :
|
||||
ProductivenessRelation (Flatten α α₂ β m) m where
|
||||
rel := ProductiveRel α β m
|
||||
wf := by
|
||||
@@ -360,9 +363,9 @@ instance [Monad m] [Iterator α m (IterM (α := α₂) m β)] [Iterator α₂ m
|
||||
apply Flatten.productiveRel_of_right₂
|
||||
|
||||
@[no_expose]
|
||||
public instance [Monad m] [Iterator α m (IterM (α := α₂) m β)] [Iterator α₂ m β]
|
||||
public def Flatten.instProductive [Monad m] [Iterator α m (IterM (α := α₂) m β)] [Iterator α₂ m β]
|
||||
[Finite α m] [Productive α₂ m] : Productive (Flatten α α₂ β m) m :=
|
||||
.of_productivenessRelation instProductivenessRelationFlattenOfFiniteIterMOfProductive
|
||||
.of_productivenessRelation instProductivenessRelation
|
||||
|
||||
end Productive
|
||||
|
||||
@@ -370,16 +373,8 @@ public instance Flatten.instIteratorCollect [Monad m] [Monad n] [Iterator α m (
|
||||
[Iterator α₂ m β] : IteratorCollect (Flatten α α₂ β m) m n :=
|
||||
.defaultImplementation
|
||||
|
||||
public instance Flatten.instIteratorCollectPartial [Monad m] [Monad n] [Iterator α m (IterM (α := α₂) m β)]
|
||||
[Iterator α₂ m β] : IteratorCollectPartial (Flatten α α₂ β m) m n :=
|
||||
.defaultImplementation
|
||||
|
||||
public instance Flatten.instIteratorLoop [Monad m] [Monad n] [Iterator α m (IterM (α := α₂) m β)]
|
||||
[Iterator α₂ m β] : IteratorLoop (Flatten α α₂ β m) m n :=
|
||||
.defaultImplementation
|
||||
|
||||
public instance Flatten.instIteratorLoopPartial [Monad m] [Monad n] [Iterator α m (IterM (α := α₂) m β)]
|
||||
[Iterator α₂ m β] : IteratorLoopPartial (Flatten α α₂ β m) m n :=
|
||||
.defaultImplementation
|
||||
|
||||
end Std.Iterators
|
||||
end Std.Iterators.Types
|
||||
|
||||
@@ -17,7 +17,7 @@ public import Init.Data.Iterators.Internal.Termination
|
||||
This module provides the iterator combinator `IterM.take`.
|
||||
-/
|
||||
|
||||
namespace Std.Iterators
|
||||
namespace Std
|
||||
|
||||
variable {α : Type w} {m : Type w → Type w'} {β : Type w}
|
||||
|
||||
@@ -25,7 +25,7 @@ variable {α : Type w} {m : Type w → Type w'} {β : Type w}
|
||||
The internal state of the `IterM.take` iterator combinator.
|
||||
-/
|
||||
@[unbox]
|
||||
structure Take (α : Type w) (m : Type w → Type w') {β : Type w} [Iterator α m β] where
|
||||
structure Iterators.Types.Take (α : Type w) (m : Type w → Type w') {β : Type w} [Iterator α m β] where
|
||||
/--
|
||||
Internal implementation detail of the iterator library.
|
||||
Caution: For `take n`, `countdown` is `n + 1`.
|
||||
@@ -40,6 +40,8 @@ structure Take (α : Type w) (m : Type w → Type w') {β : Type w} [Iterator α
|
||||
-/
|
||||
finite : countdown > 0 ∨ Finite α m
|
||||
|
||||
open Std.Iterators Std.Iterators.Types
|
||||
|
||||
/--
|
||||
Given an iterator `it` and a natural number `n`, `it.take n` is an iterator that outputs
|
||||
up to the first `n` of `it`'s values in order and then terminates.
|
||||
@@ -65,7 +67,7 @@ This combinator incurs an additional O(1) cost with each output of `it`.
|
||||
-/
|
||||
@[always_inline, inline]
|
||||
def IterM.take [Iterator α m β] (n : Nat) (it : IterM (α := α) m β) :=
|
||||
toIterM (Take.mk (n + 1) it (Or.inl <| Nat.zero_lt_succ _)) m β
|
||||
IterM.mk (Take.mk (n + 1) it (Or.inl <| Nat.zero_lt_succ _)) m β
|
||||
|
||||
/--
|
||||
This combinator is only useful for advanced use cases.
|
||||
@@ -91,7 +93,7 @@ This combinator incurs an additional O(1) cost with each output of `it`.
|
||||
-/
|
||||
@[always_inline, inline]
|
||||
def IterM.toTake [Iterator α m β] [Finite α m] (it : IterM (α := α) m β) :=
|
||||
toIterM (Take.mk 0 it (Or.inr inferInstance)) m β
|
||||
IterM.mk (Take.mk 0 it (Or.inr inferInstance)) m β
|
||||
|
||||
theorem IterM.take.surjective_of_zero_lt {α : Type w} {m : Type w → Type w'} {β : Type w}
|
||||
[Iterator α m β] (it : IterM (α := Take α m) m β) (h : 0 < it.internalState.countdown) :
|
||||
@@ -100,6 +102,8 @@ theorem IterM.take.surjective_of_zero_lt {α : Type w} {m : Type w → Type w'}
|
||||
simp only [take, Nat.sub_add_cancel (m := 1) (n := it.internalState.countdown) (by omega)]
|
||||
rfl
|
||||
|
||||
namespace Iterators.Types
|
||||
|
||||
inductive Take.PlausibleStep [Iterator α m β] (it : IterM (α := Take α m) m β) :
|
||||
(step : IterStep (IterM (α := Take α m) m β) β) → Prop where
|
||||
| yield : ∀ {it' out}, it.internalState.inner.IsPlausibleStep (.yield it' out) →
|
||||
@@ -208,16 +212,8 @@ instance Take.instIteratorCollect {n : Type w → Type w'} [Monad m] [Monad n] [
|
||||
IteratorCollect (Take α m) m n :=
|
||||
.defaultImplementation
|
||||
|
||||
instance Take.instIteratorCollectPartial {n : Type w → Type w'} [Monad m] [Monad n] [Iterator α m β] :
|
||||
IteratorCollectPartial (Take α m) m n :=
|
||||
.defaultImplementation
|
||||
|
||||
instance Take.instIteratorLoop {n : Type x → Type x'} [Monad m] [Monad n] [Iterator α m β] :
|
||||
IteratorLoop (Take α m) m n :=
|
||||
.defaultImplementation
|
||||
|
||||
instance Take.instIteratorLoopPartial [Monad m] [Monad n] [Iterator α m β] :
|
||||
IteratorLoopPartial (Take α m) m n :=
|
||||
.defaultImplementation
|
||||
|
||||
end Std.Iterators
|
||||
end Std.Iterators.Types
|
||||
|
||||
@@ -11,11 +11,12 @@ public import Init.Data.Iterators.Consumers.Monadic
|
||||
|
||||
public section
|
||||
|
||||
namespace Std.Iterators
|
||||
namespace Std
|
||||
|
||||
universe v u v' u'
|
||||
|
||||
section ULiftT
|
||||
namespace Iterators
|
||||
|
||||
/-- `ULiftT.{v, u}` shrinks a monad on `Type max u v` to a monad on `Type u`. -/
|
||||
@[expose] -- for codegen
|
||||
@@ -60,11 +61,14 @@ theorem ULiftT.run_map {n : Type max u v → Type v'} [Monad n] {α β : Type u}
|
||||
(f <$> x).run = x.run >>= (fun a => pure <| .up (f a.down)) :=
|
||||
(rfl)
|
||||
|
||||
end Iterators
|
||||
end ULiftT
|
||||
|
||||
namespace Iterators.Types
|
||||
|
||||
/-- Internal state of the `uLift` iterator combinator. Do not depend on its internals. -/
|
||||
@[unbox]
|
||||
structure Types.ULiftIterator (α : Type u) (m : Type u → Type u') (n : Type max u v → Type v')
|
||||
structure ULiftIterator (α : Type u) (m : Type u → Type u') (n : Type max u v → Type v')
|
||||
(β : Type u) (lift : ∀ ⦃γ : Type u⦄, m γ → ULiftT n γ) : Type max u v where
|
||||
inner : IterM (α := α) m β
|
||||
|
||||
@@ -75,14 +79,14 @@ variable {α : Type u} {m : Type u → Type u'} {n : Type max u v → Type v'}
|
||||
Transforms a step of the base iterator into a step of the `uLift` iterator.
|
||||
-/
|
||||
@[always_inline, inline, expose]
|
||||
def Types.ULiftIterator.Monadic.modifyStep (step : IterStep (IterM (α := α) m β) β) :
|
||||
def ULiftIterator.Monadic.modifyStep (step : IterStep (IterM (α := α) m β) β) :
|
||||
IterStep (IterM (α := ULiftIterator.{v} α m n β lift) n (ULift.{v} β)) (ULift.{v} β) :=
|
||||
match step with
|
||||
| .yield it' out => .yield ⟨⟨it'⟩⟩ (.up out)
|
||||
| .skip it' => .skip ⟨⟨it'⟩⟩
|
||||
| .done => .done
|
||||
|
||||
instance Types.ULiftIterator.instIterator [Iterator α m β] [Monad n] :
|
||||
instance ULiftIterator.instIterator [Iterator α m β] [Monad n] :
|
||||
Iterator (ULiftIterator α m n β lift) n (ULift β) where
|
||||
IsPlausibleStep it step :=
|
||||
∃ step', it.internalState.inner.IsPlausibleStep step' ∧
|
||||
@@ -93,7 +97,7 @@ instance Types.ULiftIterator.instIterator [Iterator α m β] [Monad n] :
|
||||
where finally
|
||||
case hp => exact ⟨step.inflate.val, step.inflate.property, rfl⟩
|
||||
|
||||
def Types.ULiftIterator.instFinitenessRelation [Iterator α m β] [Finite α m] [Monad n] :
|
||||
private def ULiftIterator.instFinitenessRelation [Iterator α m β] [Finite α m] [Monad n] :
|
||||
FinitenessRelation (ULiftIterator α m n β lift) n where
|
||||
rel := InvImage WellFoundedRelation.rel (fun it => it.internalState.inner.finitelyManySteps)
|
||||
wf := InvImage.wf _ WellFoundedRelation.wf
|
||||
@@ -105,11 +109,11 @@ def Types.ULiftIterator.instFinitenessRelation [Iterator α m β] [Finite α m]
|
||||
· apply IterM.TerminationMeasures.Finite.rel_of_skip
|
||||
exact hp
|
||||
|
||||
instance Types.ULiftIterator.instFinite [Iterator α m β] [Finite α m] [Monad n] :
|
||||
instance ULiftIterator.instFinite [Iterator α m β] [Finite α m] [Monad n] :
|
||||
Finite (ULiftIterator α m n β lift) n :=
|
||||
.of_finitenessRelation instFinitenessRelation
|
||||
|
||||
def Types.ULiftIterator.instProductivenessRelation [Iterator α m β] [Productive α m] [Monad n] :
|
||||
private def ULiftIterator.instProductivenessRelation [Iterator α m β] [Productive α m] [Monad n] :
|
||||
ProductivenessRelation (ULiftIterator α m n β lift) n where
|
||||
rel := InvImage WellFoundedRelation.rel (fun it => it.internalState.inner.finitelyManySkips)
|
||||
wf := InvImage.wf _ WellFoundedRelation.wf
|
||||
@@ -119,26 +123,22 @@ def Types.ULiftIterator.instProductivenessRelation [Iterator α m β] [Productiv
|
||||
apply IterM.TerminationMeasures.Productive.rel_of_skip
|
||||
exact hp
|
||||
|
||||
instance Types.ULiftIterator.instProductive [Iterator α m β] [Productive α m] [Monad n] :
|
||||
instance ULiftIterator.instProductive [Iterator α m β] [Productive α m] [Monad n] :
|
||||
Productive (ULiftIterator α m n β lift) n :=
|
||||
.of_productivenessRelation instProductivenessRelation
|
||||
|
||||
instance Types.ULiftIterator.instIteratorLoop {o : Type x → Type x'} [Monad n] [Monad o]
|
||||
instance ULiftIterator.instIteratorLoop {o : Type x → Type x'} [Monad n] [Monad o]
|
||||
[Iterator α m β] :
|
||||
IteratorLoop (ULiftIterator α m n β lift) n o :=
|
||||
.defaultImplementation
|
||||
|
||||
instance Types.ULiftIterator.instIteratorLoopPartial {o : Type x → Type x'} [Monad n] [Monad o] [Iterator α m β] :
|
||||
IteratorLoopPartial (ULiftIterator α m n β lift) n o :=
|
||||
.defaultImplementation
|
||||
|
||||
instance Types.ULiftIterator.instIteratorCollect [Monad n] [Monad o] [Iterator α m β] :
|
||||
instance ULiftIterator.instIteratorCollect [Monad n] [Monad o] [Iterator α m β] :
|
||||
IteratorCollect (ULiftIterator α m n β lift) n o :=
|
||||
.defaultImplementation
|
||||
|
||||
instance Types.ULiftIterator.instIteratorCollectPartial {o} [Monad n] [Monad o] [Iterator α m β] :
|
||||
IteratorCollectPartial (ULiftIterator α m n β lift) n o :=
|
||||
.defaultImplementation
|
||||
end Iterators.Types
|
||||
|
||||
open Std.Iterators Std.Iterators.Types
|
||||
|
||||
/--
|
||||
Transforms an `m`-monadic iterator with values in `β` into an `n`-monadic iterator with
|
||||
@@ -157,9 +157,9 @@ it.uLift n ---.up a----.up b---.up c--.up d---⊥
|
||||
* `Productive`: only if the original iterator is productive
|
||||
-/
|
||||
@[always_inline, inline, expose]
|
||||
def IterM.uLift (it : IterM (α := α) m β) (n : Type max u v → Type v')
|
||||
[lift : MonadLiftT m (ULiftT n)] :
|
||||
IterM (α := Types.ULiftIterator α m n β (fun _ => lift.monadLift)) n (ULift β) :=
|
||||
def IterM.uLift {α β : Type u} {m : Type u → Type u'} (it : IterM (α := α) m β)
|
||||
(n : Type max u v → Type v') [lift : MonadLiftT m (ULiftT n)] :
|
||||
IterM (α := ULiftIterator α m n β (fun _ => lift.monadLift)) n (ULift β) :=
|
||||
⟨⟨it⟩⟩
|
||||
|
||||
end Std.Iterators
|
||||
end Std
|
||||
|
||||
@@ -10,7 +10,8 @@ public import Init.Data.Iterators.Combinators.Monadic.Take
|
||||
|
||||
@[expose] public section
|
||||
|
||||
namespace Std.Iterators
|
||||
namespace Std
|
||||
open Std.Iterators Std.Iterators.Types
|
||||
|
||||
/--
|
||||
Given an iterator `it` and a natural number `n`, `it.take n` is an iterator that outputs
|
||||
@@ -67,4 +68,4 @@ def Iter.toTake {α : Type w} {β : Type w} [Iterator α Id β] [Finite α Id] (
|
||||
Iter (α := Take α Id) β :=
|
||||
it.toIterM.toTake.toIter
|
||||
|
||||
end Std.Iterators
|
||||
end Std
|
||||
|
||||
@@ -10,7 +10,8 @@ public import Init.Data.Iterators.Combinators.Monadic.ULift
|
||||
|
||||
public section
|
||||
|
||||
namespace Std.Iterators
|
||||
namespace Std
|
||||
open Std.Iterators Std.Iterators.Types
|
||||
|
||||
universe v u v' u'
|
||||
|
||||
@@ -20,10 +21,10 @@ variable {α : Type u} {β : Type u}
|
||||
Transforms a step of the base iterator into a step of the `uLift` iterator.
|
||||
-/
|
||||
@[always_inline, inline]
|
||||
def Types.ULiftIterator.modifyStep (step : IterStep (Iter (α := α) β) β) :
|
||||
def Iterators.Types.ULiftIterator.modifyStep (step : IterStep (Iter (α := α) β) β) :
|
||||
IterStep (Iter (α := ULiftIterator.{v} α Id Id β (fun _ => monadLift)) (ULift.{v} β))
|
||||
(ULift.{v} β) :=
|
||||
(Monadic.modifyStep (step.mapIterator Iter.toIterM)).mapIterator IterM.toIter
|
||||
(ULiftIterator.Monadic.modifyStep (step.mapIterator Iter.toIterM)).mapIterator IterM.toIter
|
||||
|
||||
/--
|
||||
Transforms an iterator with values in `β` into one with values in `ULift β`.
|
||||
@@ -48,4 +49,4 @@ def Iter.uLift (it : Iter (α := α) β) :
|
||||
Iter (α := Types.ULiftIterator.{v} α Id Id β (fun _ => monadLift)) (ULift β) :=
|
||||
(it.toIterM.uLift Id).toIter
|
||||
|
||||
end Std.Iterators
|
||||
end Std
|
||||
|
||||
@@ -11,5 +11,6 @@ public import Init.Data.Iterators.Consumers.Access
|
||||
public import Init.Data.Iterators.Consumers.Collect
|
||||
public import Init.Data.Iterators.Consumers.Loop
|
||||
public import Init.Data.Iterators.Consumers.Partial
|
||||
public import Init.Data.Iterators.Consumers.Total
|
||||
|
||||
public import Init.Data.Iterators.Consumers.Stream
|
||||
|
||||
@@ -11,7 +11,8 @@ public import Init.Data.Iterators.Consumers.Monadic.Access
|
||||
|
||||
@[expose] public section
|
||||
|
||||
namespace Std.Iterators
|
||||
namespace Std
|
||||
open Std.Iterators
|
||||
|
||||
/--
|
||||
If possible, takes `n` steps with the iterator `it` and
|
||||
@@ -62,4 +63,4 @@ def Iter.atIdx? {α β} [Iterator α Id β] [Productive α Id] [IteratorAccess
|
||||
| .skip _ => none
|
||||
| .done => none
|
||||
|
||||
end Std.Iterators
|
||||
end Std
|
||||
|
||||
@@ -7,6 +7,7 @@ module
|
||||
|
||||
prelude
|
||||
public import Init.Data.Iterators.Consumers.Partial
|
||||
public import Init.Data.Iterators.Consumers.Total
|
||||
public import Init.Data.Iterators.Consumers.Monadic.Collect
|
||||
|
||||
@[expose] public section
|
||||
@@ -21,40 +22,114 @@ Concretely, the following operations are provided:
|
||||
* `Iter.toListRev`, collecting the values in a list in reverse order but more efficiently
|
||||
* `Iter.toArray`, collecting the values in an array
|
||||
|
||||
Some operations are implemented using the `IteratorCollect` and `IteratorCollectPartial`
|
||||
typeclasses.
|
||||
Some operations are implemented using the `IteratorCollect` type class.
|
||||
-/
|
||||
|
||||
namespace Std.Iterators
|
||||
namespace Std
|
||||
open Std.Iterators
|
||||
|
||||
@[always_inline, inline, inherit_doc IterM.toArray]
|
||||
/--
|
||||
Traverses the given iterator and stores the emitted values in an array.
|
||||
|
||||
If the iterator is not finite, this function might run forever. The variant
|
||||
`it.ensureTermination.toArray` always terminates after finitely many steps.
|
||||
-/
|
||||
@[always_inline, inline]
|
||||
def Iter.toArray {α : Type w} {β : Type w}
|
||||
[Iterator α Id β] [Finite α Id] [IteratorCollect α Id Id] (it : Iter (α := α) β) : Array β :=
|
||||
[Iterator α Id β] [IteratorCollect α Id Id] (it : Iter (α := α) β) : Array β :=
|
||||
it.toIterM.toArray.run
|
||||
|
||||
@[always_inline, inline, inherit_doc IterM.Partial.toArray]
|
||||
def Iter.Partial.toArray {α : Type w} {β : Type w}
|
||||
[Iterator α Id β] [IteratorCollectPartial α Id Id] (it : Iter.Partial (α := α) β) : Array β :=
|
||||
it.it.toIterM.allowNontermination.toArray.run
|
||||
/--
|
||||
Traverses the given iterator and stores the emitted values in an array.
|
||||
|
||||
@[always_inline, inline, inherit_doc IterM.toListRev]
|
||||
This function is deprecated. Instead of `it.allowNontermination.toArray`, use `it.toArray`.
|
||||
-/
|
||||
@[always_inline, inline, deprecated Iter.toArray (since := "2025-12-04")]
|
||||
def Iter.Partial.toArray {α : Type w} {β : Type w}
|
||||
[Iterator α Id β] [IteratorCollect α Id Id] (it : Iter.Partial (α := α) β) : Array β :=
|
||||
it.it.toArray
|
||||
|
||||
/--
|
||||
Traverses the given iterator and stores the emitted values in an array.
|
||||
|
||||
This variant terminates after finitely many steps and requires a proof that the iterator is
|
||||
finite. If such a proof is not available, consider using `Iter.toArray`.
|
||||
-/
|
||||
@[always_inline, inline]
|
||||
def Iter.Total.toArray {α : Type w} {β : Type w}
|
||||
[Iterator α Id β] [Finite α Id] [IteratorCollect α Id Id] (it : Iter.Total (α := α) β) :
|
||||
Array β :=
|
||||
it.it.toArray
|
||||
|
||||
/--
|
||||
Traverses the given iterator and stores the emitted values in reverse order in a list. Because
|
||||
lists are prepend-only, this `toListRev` is usually more efficient that `toList`.
|
||||
|
||||
If the iterator is not finite, this function might run forever. The variant
|
||||
`it.ensureTermination.toListRev` always terminates after finitely many steps.
|
||||
-/
|
||||
@[always_inline, inline]
|
||||
def Iter.toListRev {α : Type w} {β : Type w}
|
||||
[Iterator α Id β] [Finite α Id] (it : Iter (α := α) β) : List β :=
|
||||
[Iterator α Id β] (it : Iter (α := α) β) : List β :=
|
||||
it.toIterM.toListRev.run
|
||||
|
||||
@[always_inline, inline, inherit_doc IterM.Partial.toListRev]
|
||||
/--
|
||||
Traverses the given iterator and stores the emitted values in reverse order in a list. Because
|
||||
lists are prepend-only, this `toListRev` is usually more efficient that `toList`.
|
||||
|
||||
This function is deprecated. Instead of `it.allowNontermination.toListRev`, use `it.toListRev`.
|
||||
-/
|
||||
@[always_inline, inline, deprecated Iter.toListRev (since := "2025-12-04")]
|
||||
def Iter.Partial.toListRev {α : Type w} {β : Type w}
|
||||
[Iterator α Id β] (it : Iter.Partial (α := α) β) : List β :=
|
||||
it.it.toIterM.allowNontermination.toListRev.run
|
||||
it.it.toListRev
|
||||
|
||||
@[always_inline, inline, inherit_doc IterM.toList]
|
||||
/--
|
||||
Traverses the given iterator and stores the emitted values in reverse order in a list. Because
|
||||
lists are prepend-only, this `toListRev` is usually more efficient that `toList`.
|
||||
|
||||
This variant terminates after finitely many steps and requires a proof that the iterator is
|
||||
finite. If such a proof is not available, consider using `Iter.toListRev`.
|
||||
-/
|
||||
@[always_inline, inline]
|
||||
def Iter.Total.toListRev {α : Type w} {β : Type w}
|
||||
[Iterator α Id β] [Finite α Id] (it : Iter.Total (α := α) β) : List β :=
|
||||
it.it.toListRev
|
||||
|
||||
/--
|
||||
Traverses the given iterator and stores the emitted values in a list. Because
|
||||
lists are prepend-only, `toListRev` is usually more efficient that `toList`.
|
||||
|
||||
If the iterator is not finite, this function might run forever. The variant
|
||||
`it.ensureTermination.toList` always terminates after finitely many steps.
|
||||
-/
|
||||
@[always_inline, inline]
|
||||
def Iter.toList {α : Type w} {β : Type w}
|
||||
[Iterator α Id β] [Finite α Id] [IteratorCollect α Id Id] (it : Iter (α := α) β) : List β :=
|
||||
[Iterator α Id β] [IteratorCollect α Id Id] (it : Iter (α := α) β) : List β :=
|
||||
it.toIterM.toList.run
|
||||
|
||||
@[always_inline, inline, inherit_doc IterM.Partial.toList]
|
||||
def Iter.Partial.toList {α : Type w} {β : Type w}
|
||||
[Iterator α Id β] [IteratorCollectPartial α Id Id] (it : Iter.Partial (α := α) β) : List β :=
|
||||
it.it.toIterM.allowNontermination.toList.run
|
||||
/--
|
||||
Traverses the given iterator and stores the emitted values in a list. Because
|
||||
lists are prepend-only, `toListRev` is usually more efficient that `toList`.
|
||||
|
||||
end Std.Iterators
|
||||
This function is deprecated. Instead of `it.allowNontermination.toList`, use `it.toList`.
|
||||
-/
|
||||
@[always_inline, deprecated Iter.toList (since := "2025-12-04")]
|
||||
def Iter.Partial.toList {α : Type w} {β : Type w}
|
||||
[Iterator α Id β] [IteratorCollect α Id Id] (it : Iter.Partial (α := α) β) : List β :=
|
||||
it.it.toList
|
||||
|
||||
/--
|
||||
Traverses the given iterator and stores the emitted values in a list. Because
|
||||
lists are prepend-only, `toListRev` is usually more efficient that `toList`.
|
||||
|
||||
This variant terminates after finitely many steps and requires a proof that the iterator is
|
||||
finite. If such a proof is not available, consider using `Iter.toList`.
|
||||
-/
|
||||
@[always_inline, inline]
|
||||
def Iter.Total.toList {α : Type w} {β : Type w}
|
||||
[Iterator α Id β] [Finite α Id] [IteratorCollect α Id Id] (it : Iter.Total (α := α) β) :
|
||||
List β :=
|
||||
it.it.toList
|
||||
|
||||
end Std
|
||||
|
||||
@@ -23,10 +23,11 @@ function in every iteration. Concretely, the following operations are provided:
|
||||
* `Iter.fold`, the analogue of `List.foldl`
|
||||
* `Iter.foldM`, the analogue of `List.foldlM`
|
||||
|
||||
These operations are implemented using the `IteratorLoop` and `IteratorLoopPartial` typeclasses.
|
||||
These operations are implemented using the `IteratorLoop` type class.
|
||||
-/
|
||||
|
||||
namespace Std.Iterators
|
||||
namespace Std
|
||||
open Std.Iterators
|
||||
|
||||
/--
|
||||
A `ForIn'` instance for iterators. Its generic membership relation is not easy to use,
|
||||
@@ -35,7 +36,7 @@ or future library improvements will make it more comfortable.
|
||||
-/
|
||||
@[always_inline, inline]
|
||||
def Iter.instForIn' {α : Type w} {β : Type w} {n : Type x → Type x'} [Monad n]
|
||||
[Iterator α Id β] [Finite α Id] [IteratorLoop α Id n] :
|
||||
[Iterator α Id β] [IteratorLoop α Id n] :
|
||||
ForIn' n (Iter (α := α) β) β ⟨fun it out => it.IsPlausibleIndirectOutput out⟩ where
|
||||
forIn' it init f :=
|
||||
IteratorLoop.finiteForIn' (fun _ _ f c => f c.run) |>.forIn' it.toIterM init
|
||||
@@ -43,7 +44,7 @@ def Iter.instForIn' {α : Type w} {β : Type w} {n : Type x → Type x'} [Monad
|
||||
f out (Iter.isPlausibleIndirectOutput_iff_isPlausibleIndirectOutput_toIterM.mpr h) acc
|
||||
|
||||
instance (α : Type w) (β : Type w) (n : Type x → Type x') [Monad n]
|
||||
[Iterator α Id β] [Finite α Id] [IteratorLoop α Id n] :
|
||||
[Iterator α Id β] [IteratorLoop α Id n] :
|
||||
ForIn n (Iter (α := α) β) β :=
|
||||
haveI : ForIn' n (Iter (α := α) β) β _ := Iter.instForIn'
|
||||
instForInOfForIn'
|
||||
@@ -53,44 +54,58 @@ An implementation of `for h : ... in ... do ...` notation for partial iterators.
|
||||
-/
|
||||
@[always_inline, inline]
|
||||
def Iter.Partial.instForIn' {α : Type w} {β : Type w} {n : Type x → Type x'} [Monad n]
|
||||
[Iterator α Id β] [IteratorLoopPartial α Id n] :
|
||||
[Iterator α Id β] [IteratorLoop α Id n] :
|
||||
ForIn' n (Iter.Partial (α := α) β) β ⟨fun it out => it.it.IsPlausibleIndirectOutput out⟩ where
|
||||
forIn' it init f :=
|
||||
IteratorLoopPartial.forInPartial (α := α) (m := Id) (n := n) (fun _ _ f c => f c.run)
|
||||
it.it.toIterM init
|
||||
fun out h acc =>
|
||||
f out (Iter.isPlausibleIndirectOutput_iff_isPlausibleIndirectOutput_toIterM.mpr h) acc
|
||||
haveI := @Iter.instForIn'
|
||||
forIn' it.it init f
|
||||
|
||||
instance (α : Type w) (β : Type w) (n : Type x → Type x') [Monad n]
|
||||
[Iterator α Id β] [IteratorLoopPartial α Id n] :
|
||||
[Iterator α Id β] [IteratorLoop α Id n] :
|
||||
ForIn n (Iter.Partial (α := α) β) β :=
|
||||
haveI : ForIn' n (Iter.Partial (α := α) β) β _ := Iter.Partial.instForIn'
|
||||
instForInOfForIn'
|
||||
|
||||
/--
|
||||
A `ForIn'` instance for iterators that is guaranteed to terminate after finitely many steps.
|
||||
It is not marked as an instance because the membership predicate is difficult to work with.
|
||||
-/
|
||||
@[always_inline, inline]
|
||||
def Iter.Total.instForIn' {α : Type w} {β : Type w} {n : Type x → Type x'} [Monad n]
|
||||
[Iterator α Id β] [IteratorLoop α Id n] [Finite α Id] :
|
||||
ForIn' n (Iter.Total (α := α) β) β ⟨fun it out => it.it.IsPlausibleIndirectOutput out⟩ where
|
||||
forIn' it init f := Iter.instForIn'.forIn' it.it init f
|
||||
|
||||
instance (α : Type w) (β : Type w) (n : Type x → Type x') [Monad n]
|
||||
[Iterator α Id β] [IteratorLoop α Id n] [Finite α Id] :
|
||||
ForIn n (Iter.Total (α := α) β) β :=
|
||||
haveI : ForIn' n (Iter.Total (α := α) β) β _ := Iter.Total.instForIn'
|
||||
instForInOfForIn'
|
||||
|
||||
instance {m : Type x → Type x'}
|
||||
{α : Type w} {β : Type w} [Iterator α Id β] [Finite α Id] [IteratorLoop α Id m] [Monad m] :
|
||||
{α : Type w} {β : Type w} [Iterator α Id β] [IteratorLoop α Id m] [Monad m] :
|
||||
ForM m (Iter (α := α) β) β where
|
||||
forM it f := forIn it PUnit.unit (fun out _ => do f out; return .yield .unit)
|
||||
|
||||
instance {m : Type x → Type x'}
|
||||
{α : Type w} {β : Type w} [Iterator α Id β] [Finite α Id] [IteratorLoopPartial α Id m] [Monad m] :
|
||||
{α : Type w} {β : Type w} [Iterator α Id β] [IteratorLoop α Id m] [Monad m] :
|
||||
ForM m (Iter.Partial (α := α) β) β where
|
||||
forM it f := forIn it PUnit.unit (fun out _ => do f out; return .yield .unit)
|
||||
|
||||
instance {m : Type x → Type x'}
|
||||
{α : Type w} {β : Type w} [Monad m] [Iterator α Id β] [IteratorLoop α Id m] [Finite α Id] :
|
||||
ForM m (Iter.Total (α := α) β) β where
|
||||
forM it f := forIn it PUnit.unit (fun out _ => do f out; return .yield .unit)
|
||||
|
||||
/--
|
||||
Folds a monadic function over an iterator from the left, accumulating a value starting with `init`.
|
||||
The accumulated value is combined with the each element of the list in order, using `f`.
|
||||
|
||||
It is equivalent to `it.toList.foldlM`.
|
||||
|
||||
This function requires a `Finite` instance proving that the iterator will finish after a finite
|
||||
number of steps. If the iterator is not finite or such an instance is not available, consider using
|
||||
`it.allowNontermination.foldM` instead of `it.foldM`. However, it is not possible to formally
|
||||
verify the behavior of the partial variant.
|
||||
-/
|
||||
@[always_inline, inline]
|
||||
def Iter.foldM {m : Type x → Type x'} [Monad m]
|
||||
{α : Type w} {β : Type w} {γ : Type x} [Iterator α Id β] [Finite α Id]
|
||||
{α : Type w} {β : Type w} {γ : Type x} [Iterator α Id β]
|
||||
[IteratorLoop α Id m] (f : γ → β → m γ)
|
||||
(init : γ) (it : Iter (α := α) β) : m γ :=
|
||||
ForIn.forIn it init (fun x acc => ForInStep.yield <$> f acc x)
|
||||
@@ -101,29 +116,39 @@ The accumulated value is combined with the each element of the list in order, us
|
||||
|
||||
It is equivalent to `it.toList.foldlM`.
|
||||
|
||||
This is a partial, potentially nonterminating, function. It is not possible to formally verify
|
||||
its behavior. If the iterator has a `Finite` instance, consider using `IterM.foldM` instead.
|
||||
This function is deprecated. Instead of `it.allowNontermination.foldM`, use `it.foldM`.
|
||||
-/
|
||||
@[always_inline, inline]
|
||||
@[always_inline, inline, deprecated Iter.foldM (since := "2025-12-04")]
|
||||
def Iter.Partial.foldM {m : Type x → Type x'} [Monad m]
|
||||
{α : Type w} {β : Type w} {γ : Type x} [Iterator α Id β]
|
||||
[IteratorLoopPartial α Id m] (f : γ → β → m γ)
|
||||
[IteratorLoop α Id m] (f : γ → β → m γ)
|
||||
(init : γ) (it : Iter.Partial (α := α) β) : m γ :=
|
||||
ForIn.forIn it init (fun x acc => ForInStep.yield <$> f acc x)
|
||||
it.it.foldM (init := init) f
|
||||
|
||||
/--
|
||||
Folds a monadic function over an iterator from the left, accumulating a value starting with `init`.
|
||||
The accumulated value is combined with the each element of the list in order, using `f`.
|
||||
|
||||
It is equivalent to `it.toList.foldlM`.
|
||||
|
||||
This variant terminates after finitely many steps and requires a proof that the iterator is
|
||||
finite. If such a proof is not available, consider using `Iter.foldM`.
|
||||
-/
|
||||
@[always_inline, inline]
|
||||
def Iter.Total.foldM {m : Type x → Type x'} [Monad m]
|
||||
{α : Type w} {β : Type w} {γ : Type x} [Iterator α Id β]
|
||||
[IteratorLoop α Id m] [Finite α Id] (f : γ → β → m γ)
|
||||
(init : γ) (it : Iter.Total (α := α) β) : m γ :=
|
||||
it.it.foldM (init := init) f
|
||||
|
||||
/--
|
||||
Folds a function over an iterator from the left, accumulating a value starting with `init`.
|
||||
The accumulated value is combined with the each element of the list in order, using `f`.
|
||||
|
||||
It is equivalent to `it.toList.foldl`.
|
||||
|
||||
This function requires a `Finite` instance proving that the iterator will finish after a finite
|
||||
number of steps. If the iterator is not finite or such an instance is not available, consider using
|
||||
`it.allowNontermination.fold` instead of `it.fold`. However, it is not possible to formally
|
||||
verify the behavior of the partial variant.
|
||||
-/
|
||||
@[always_inline, inline]
|
||||
def Iter.fold {α : Type w} {β : Type w} {γ : Type x} [Iterator α Id β] [Finite α Id]
|
||||
def Iter.fold {α : Type w} {β : Type w} {γ : Type x} [Iterator α Id β]
|
||||
[IteratorLoop α Id Id] (f : γ → β → γ)
|
||||
(init : γ) (it : Iter (α := α) β) : γ :=
|
||||
ForIn.forIn (m := Id) it init (fun x acc => ForInStep.yield (f acc x))
|
||||
@@ -134,14 +159,28 @@ The accumulated value is combined with the each element of the list in order, us
|
||||
|
||||
It is equivalent to `it.toList.foldl`.
|
||||
|
||||
This is a partial, potentially nonterminating, function. It is not possible to formally verify
|
||||
its behavior. If the iterator has a `Finite` instance, consider using `IterM.fold` instead.
|
||||
This function is deprecated. Instead of `it.allowNontermination.fold`, use `it.fold`.
|
||||
-/
|
||||
@[always_inline, inline, deprecated Iter.fold (since := "2025-12-04")]
|
||||
def Iter.Partial.fold {α : Type w} {β : Type w} {γ : Type x} [Iterator α Id β]
|
||||
[IteratorLoop α Id Id] (f : γ → β → γ)
|
||||
(init : γ) (it : Iter.Partial (α := α) β) : γ :=
|
||||
it.it.fold (init := init) f
|
||||
|
||||
/--
|
||||
Folds a function over an iterator from the left, accumulating a value starting with `init`.
|
||||
The accumulated value is combined with the each element of the list in order, using `f`.
|
||||
|
||||
It is equivalent to `it.toList.foldl`.
|
||||
|
||||
This variant terminates after finitely many steps and requires a proof that the iterator is
|
||||
finite. If such a proof is not available, consider using `Iter.fold`.
|
||||
-/
|
||||
@[always_inline, inline]
|
||||
def Iter.Partial.fold {α : Type w} {β : Type w} {γ : Type x} [Iterator α Id β]
|
||||
[IteratorLoopPartial α Id Id] (f : γ → β → γ)
|
||||
(init : γ) (it : Iter.Partial (α := α) β) : γ :=
|
||||
ForIn.forIn (m := Id) it init (fun x acc => ForInStep.yield (f acc x))
|
||||
def Iter.Total.fold {α : Type w} {β : Type w} {γ : Type x} [Iterator α Id β]
|
||||
[IteratorLoop α Id Id] [Finite α Id] (f : γ → β → γ)
|
||||
(init : γ) (it : Iter.Total (α := α) β) : γ :=
|
||||
it.it.fold (init := init) f
|
||||
|
||||
set_option doc.verso true in
|
||||
/--
|
||||
@@ -151,9 +190,9 @@ any element emitted by the iterator {name}`it`.
|
||||
{lit}`O(|xs|)`. Short-circuits upon encountering the first match. The elements in {name}`it` are
|
||||
examined in order of iteration.
|
||||
-/
|
||||
@[specialize]
|
||||
@[always_inline]
|
||||
def Iter.anyM {α β : Type w} {m : Type → Type w'} [Monad m]
|
||||
[Iterator α Id β] [IteratorLoop α Id m] [Finite α Id]
|
||||
[Iterator α Id β] [IteratorLoop α Id m]
|
||||
(p : β → m Bool) (it : Iter (α := α) β) : m Bool :=
|
||||
ForIn.forIn it false (fun x _ => do
|
||||
if ← p x then
|
||||
@@ -161,6 +200,23 @@ def Iter.anyM {α β : Type w} {m : Type → Type w'} [Monad m]
|
||||
else
|
||||
return .yield false)
|
||||
|
||||
set_option doc.verso true in
|
||||
/--
|
||||
Returns {lean}`true` if the monadic predicate {name}`p` returns {lean}`true` for
|
||||
any element emitted by the iterator {name}`it`.
|
||||
|
||||
{lit}`O(|xs|)`. Short-circuits upon encountering the first match. The elements in {name}`it` are
|
||||
examined in order of iteration.
|
||||
|
||||
This variant terminates after finitely many steps and requires a proof that the iterator is
|
||||
finite. If such a proof is not available, consider using {name}`Iter.anyM`.
|
||||
-/
|
||||
@[always_inline, inline]
|
||||
def Iter.Total.anyM {α β : Type w} {m : Type → Type w'} [Monad m]
|
||||
[Iterator α Id β] [IteratorLoop α Id m] [Finite α Id]
|
||||
(p : β → m Bool) (it : Iter.Total (α := α) β) : m Bool :=
|
||||
it.it.anyM p
|
||||
|
||||
set_option doc.verso true in
|
||||
/--
|
||||
Returns {lean}`true` if the pure predicate {name}`p` returns {lean}`true` for
|
||||
@@ -171,21 +227,38 @@ examined in order of iteration.
|
||||
-/
|
||||
@[inline]
|
||||
def Iter.any {α β : Type w}
|
||||
[Iterator α Id β] [IteratorLoop α Id Id] [Finite α Id]
|
||||
[Iterator α Id β] [IteratorLoop α Id Id]
|
||||
(p : β → Bool) (it : Iter (α := α) β) : Bool :=
|
||||
(it.anyM (fun x => pure (f := Id) (p x))).run
|
||||
|
||||
set_option doc.verso true in
|
||||
/--
|
||||
Returns {lean}`true` if the monadic predicate {name}`p` returns {lean}`true` for
|
||||
all elements emitted by the iterator {name}`it`.
|
||||
Returns {lean}`true` if the pure predicate {name}`p` returns {lean}`true` for
|
||||
any element emitted by the iterator {name}`it`.
|
||||
|
||||
{lit}`O(|xs|)`. Short-circuits upon encountering the first mismatch. The elements in {name}`it` are
|
||||
{lit}`O(|xs|)`. Short-circuits upon encountering the first match. The elements in {name}`it` are
|
||||
examined in order of iteration.
|
||||
|
||||
This variant terminates after finitely many steps and requires a proof that the iterator is
|
||||
finite. If such a proof is not available, consider using {name}`Iter.any`.
|
||||
-/
|
||||
@[inline]
|
||||
def Iter.Total.any {α β : Type w}
|
||||
[Iterator α Id β] [IteratorLoop α Id Id] [Finite α Id]
|
||||
(p : β → Bool) (it : Iter.Total (α := α) β) : Bool :=
|
||||
it.it.any p
|
||||
|
||||
set_option doc.verso true in
|
||||
/--
|
||||
Returns {lean}`true` if the monadic predicate {name}`p` returns {lean}`true` for
|
||||
all element emitted by the iterator {name}`it`.
|
||||
|
||||
{lit}`O(|xs|)`. Short-circuits upon encountering the first match. The elements in {name}`it` are
|
||||
examined in order of iteration.
|
||||
-/
|
||||
@[specialize]
|
||||
@[always_inline, inline]
|
||||
def Iter.allM {α β : Type w} {m : Type → Type w'} [Monad m]
|
||||
[Iterator α Id β] [IteratorLoop α Id m] [Finite α Id]
|
||||
[Iterator α Id β] [IteratorLoop α Id m]
|
||||
(p : β → m Bool) (it : Iter (α := α) β) : m Bool :=
|
||||
ForIn.forIn it true (fun x _ => do
|
||||
if ← p x then
|
||||
@@ -195,36 +268,82 @@ def Iter.allM {α β : Type w} {m : Type → Type w'} [Monad m]
|
||||
|
||||
set_option doc.verso true in
|
||||
/--
|
||||
Returns {lean}`true` if the pure predicate {name}`p` returns {lean}`true` for
|
||||
all elements emitted by the iterator {name}`it`.
|
||||
Returns {lean}`true` if the monadic predicate {name}`p` returns {lean}`true` for
|
||||
all element emitted by the iterator {name}`it`.
|
||||
|
||||
{lit}`O(|xs|)`. Short-circuits upon encountering the first mismatch. The elements in {name}`it` are
|
||||
{lit}`O(|xs|)`. Short-circuits upon encountering the first match. The elements in {name}`it` are
|
||||
examined in order of iteration.
|
||||
|
||||
This variant terminates after finitely mall steps and requires a proof that the iterator is
|
||||
finite. If such a proof is not available, consider using {name}`Iter.allM`.
|
||||
-/
|
||||
@[always_inline, inline]
|
||||
def Iter.Total.allM {α β : Type w} {m : Type → Type w'} [Monad m]
|
||||
[Iterator α Id β] [IteratorLoop α Id m] [Finite α Id]
|
||||
(p : β → m Bool) (it : Iter.Total (α := α) β) : m Bool :=
|
||||
it.it.allM p
|
||||
|
||||
set_option doc.verso true in
|
||||
/--
|
||||
Returns {lean}`true` if the pure predicate {name}`p` returns {lean}`true` for
|
||||
all element emitted by the iterator {name}`it`.
|
||||
|
||||
{lit}`O(|xs|)`. Short-circuits upon encountering the first match. The elements in {name}`it` are
|
||||
examined in order of iteration.
|
||||
-/
|
||||
@[inline]
|
||||
def Iter.all {α β : Type w}
|
||||
[Iterator α Id β] [IteratorLoop α Id Id] [Finite α Id]
|
||||
[Iterator α Id β] [IteratorLoop α Id Id]
|
||||
(p : β → Bool) (it : Iter (α := α) β) : Bool :=
|
||||
(it.allM (fun x => pure (f := Id) (p x))).run
|
||||
|
||||
set_option doc.verso true in
|
||||
/--
|
||||
Steps through the iterator until the monadic function `f` returns `some` for an element, at which
|
||||
point iteration stops and the result of `f` is returned. If the iterator is completely consumed
|
||||
without `f` returning `some`, then the result is `none`.
|
||||
Returns {lean}`true` if the pure predicate {name}`p` returns {lean}`true` for
|
||||
all element emitted by the iterator {name}`it`.
|
||||
|
||||
{lit}`O(|xs|)`. Short-circuits upon encountering the first match. The elements in {name}`it` are
|
||||
examined in order of iteration.
|
||||
|
||||
This variant terminates after finitely mall steps and requires a proof that the iterator is
|
||||
finite. If such a proof is not available, consider using {name}`Iter.all`.
|
||||
-/
|
||||
@[inline]
|
||||
def Iter.Total.all {α β : Type w}
|
||||
[Iterator α Id β] [IteratorLoop α Id Id] [Finite α Id]
|
||||
(p : β → Bool) (it : Iter.Total (α := α) β) : Bool :=
|
||||
it.it.all p
|
||||
|
||||
/--
|
||||
Returns the first non-`none` result of applying the monadic function `f` to each output
|
||||
of the iterator, in order. Returns `none` if `f` returns `none` for all outputs.
|
||||
|
||||
`O(|it|)`. Short-circuits when `f` returns `some _`. The outputs of `it` are
|
||||
examined in order of iteration.
|
||||
|
||||
If the iterator is not finite, this function might run forever. The variant
|
||||
`it.ensureTermination.findSomeM?` always terminates after finitely many steps.
|
||||
|
||||
Example:
|
||||
```lean example
|
||||
#eval [7, 6, 5, 8, 1, 2, 6].iter.findSomeM? fun i => do
|
||||
if i < 5 then
|
||||
return some (i * 10)
|
||||
if i ≤ 6 then
|
||||
IO.println s!"Almost! {i}"
|
||||
return none
|
||||
```
|
||||
```output
|
||||
Almost! 6
|
||||
Almost! 5
|
||||
```
|
||||
```output
|
||||
some 10
|
||||
```
|
||||
-/
|
||||
@[inline]
|
||||
def Iter.findSomeM? {α β : Type w} {γ : Type x} {m : Type x → Type w'} [Monad m] [Iterator α Id β]
|
||||
[IteratorLoop α Id m] [Finite α Id] (it : Iter (α := α) β) (f : β → m (Option γ)) :
|
||||
m (Option γ) :=
|
||||
ForIn.forIn it none (fun x _ => do
|
||||
match ← f x with
|
||||
| none => return .yield none
|
||||
| some fx => return .done (some fx))
|
||||
|
||||
@[inline, inherit_doc Iter.findSomeM?]
|
||||
def Iter.Partial.findSomeM? {α β : Type w} {γ : Type x} {m : Type x → Type w'} [Monad m]
|
||||
[Iterator α Id β] [IteratorLoopPartial α Id m] (it : Iter.Partial (α := α) β)
|
||||
(f : β → m (Option γ)) :
|
||||
[IteratorLoop α Id m] (it : Iter (α := α) β) (f : β → m (Option γ)) :
|
||||
m (Option γ) :=
|
||||
ForIn.forIn it none (fun x _ => do
|
||||
match ← f x with
|
||||
@@ -232,52 +351,284 @@ def Iter.Partial.findSomeM? {α β : Type w} {γ : Type x} {m : Type x → Type
|
||||
| some fx => return .done (some fx))
|
||||
|
||||
/--
|
||||
Steps through the iterator until `f` returns `some` for an element, at which point iteration stops
|
||||
and the result of `f` is returned. If the iterator is completely consumed without `f` returning
|
||||
`some`, then the result is `none`.
|
||||
Returns the first non-`none` result of applying the monadic function `f` to each output
|
||||
of the iterator, in order. Returns `none` if `f` returns `none` for all outputs.
|
||||
|
||||
`O(|it|)`. Short-circuits when `f` returns `some _`. The outputs of `it` are
|
||||
examined in order of iteration.
|
||||
|
||||
This function is deprecated. Instead of `it.allowNontermination.findSomeM?`, use `it.findSomeM?`.
|
||||
|
||||
Example:
|
||||
```lean example
|
||||
#eval [7, 6, 5, 8, 1, 2, 6].iter.findSomeM? fun i => do
|
||||
if i < 5 then
|
||||
return some (i * 10)
|
||||
if i ≤ 6 then
|
||||
IO.println s!"Almost! {i}"
|
||||
return none
|
||||
```
|
||||
```output
|
||||
Almost! 6
|
||||
Almost! 5
|
||||
```
|
||||
```output
|
||||
some 10
|
||||
```
|
||||
-/
|
||||
@[inline, deprecated Iter.findSomeM? (since := "2025-12-04")]
|
||||
def Iter.Partial.findSomeM? {α β : Type w} {γ : Type x} {m : Type x → Type w'} [Monad m]
|
||||
[Iterator α Id β] [IteratorLoop α Id m] (it : Iter.Partial (α := α) β)
|
||||
(f : β → m (Option γ)) :
|
||||
m (Option γ) :=
|
||||
it.it.findSomeM? f
|
||||
|
||||
/--
|
||||
Returns the first non-`none` result of applying the monadic function `f` to each output
|
||||
of the iterator, in order. Returns `none` if `f` returns `none` for all outputs.
|
||||
|
||||
`O(|it|)`. Short-circuits when `f` returns `some _`. The outputs of `it` are
|
||||
examined in order of iteration.
|
||||
|
||||
This variant terminates after finitely many steps and requires a proof that the iterator is
|
||||
finite. If such a proof is not available, consider using `Iter.findSomeM?`.
|
||||
|
||||
Example:
|
||||
```lean example
|
||||
#eval [7, 6, 5, 8, 1, 2, 6].iter.findSomeM? fun i => do
|
||||
if i < 5 then
|
||||
return some (i * 10)
|
||||
if i ≤ 6 then
|
||||
IO.println s!"Almost! {i}"
|
||||
return none
|
||||
```
|
||||
```output
|
||||
Almost! 6
|
||||
Almost! 5
|
||||
```
|
||||
```output
|
||||
some 10
|
||||
```
|
||||
-/
|
||||
@[inline]
|
||||
def Iter.Total.findSomeM? {α β : Type w} {γ : Type x} {m : Type x → Type w'} [Monad m]
|
||||
[Iterator α Id β] [IteratorLoop α Id m] [Finite α Id] (it : Iter.Total (α := α) β)
|
||||
(f : β → m (Option γ)) :
|
||||
m (Option γ) :=
|
||||
it.it.findSomeM? f
|
||||
|
||||
/--
|
||||
Returns the first non-`none` result of applying `f` to each output of the iterator, in order.
|
||||
Returns `none` if `f` returns `none` for all outputs.
|
||||
|
||||
`O(|it|)`. Short-circuits when `f` returns `some _`.The outputs of `it` are examined in order of
|
||||
iteration.
|
||||
|
||||
If the iterator is not finite, this function might run forever. The variant
|
||||
`it.ensureTermination.findSome?` always terminates after finitely many steps.
|
||||
|
||||
Examples:
|
||||
* `[7, 6, 5, 8, 1, 2, 6].iter.findSome? (fun x => if x < 5 then some (10 * x) else none) = some 10`
|
||||
* `[7, 6, 5, 8, 1, 2, 6].iter.findSome? (fun x => if x < 1 then some (10 * x) else none) = none`
|
||||
-/
|
||||
@[inline]
|
||||
def Iter.findSome? {α β : Type w} {γ : Type x} [Iterator α Id β]
|
||||
[IteratorLoop α Id Id] [Finite α Id] (it : Iter (α := α) β) (f : β → Option γ) :
|
||||
Option γ :=
|
||||
Id.run (it.findSomeM? (pure <| f ·))
|
||||
|
||||
@[inline, inherit_doc Iter.findSome?]
|
||||
def Iter.Partial.findSome? {α β : Type w} {γ : Type x} [Iterator α Id β]
|
||||
[IteratorLoopPartial α Id Id] (it : Iter.Partial (α := α) β) (f : β → Option γ) :
|
||||
[IteratorLoop α Id Id] (it : Iter (α := α) β) (f : β → Option γ) :
|
||||
Option γ :=
|
||||
Id.run (it.findSomeM? (pure <| f ·))
|
||||
|
||||
/--
|
||||
Steps through the iterator until an element satisfies the monadic predicate `f`, at which point
|
||||
iteration stops and the element is returned. If no element satisfies `f`, then the result is
|
||||
`none`.
|
||||
Returns the first non-`none` result of applying `f` to each output of the iterator, in order.
|
||||
Returns `none` if `f` returns `none` for all outputs.
|
||||
|
||||
`O(|it|)`. Short-circuits when `f` returns `some _`.The outputs of `it` are examined in order of
|
||||
iteration.
|
||||
|
||||
This function is deprecated. Instead of `it.allowNontermination.findSome?`, use `it.findSome?`.
|
||||
|
||||
Examples:
|
||||
* `[7, 6, 5, 8, 1, 2, 6].iter.allowNontermination.findSome? (fun x => if x < 5 then some (10 * x) else none) = some 10`
|
||||
* `[7, 6, 5, 8, 1, 2, 6].iter.allowNontermination.findSome? (fun x => if x < 1 then some (10 * x) else none) = none`
|
||||
-/
|
||||
@[inline, deprecated Iter.findSome? (since := "2025-12-04")]
|
||||
def Iter.Partial.findSome? {α β : Type w} {γ : Type x} [Iterator α Id β]
|
||||
[IteratorLoop α Id Id] (it : Iter.Partial (α := α) β) (f : β → Option γ) :
|
||||
Option γ :=
|
||||
it.it.findSome? f
|
||||
|
||||
/--
|
||||
Returns the first non-`none` result of applying `f` to each output of the iterator, in order.
|
||||
Returns `none` if `f` returns `none` for all outputs.
|
||||
|
||||
`O(|it|)`. Short-circuits when `f` returns `some _`.The outputs of `it` are examined in order of
|
||||
iteration.
|
||||
|
||||
This variant terminates after finitely many steps and requires a proof that the iterator is
|
||||
finite. If such a proof is not available, consider using `Iter.findSome?`.
|
||||
|
||||
Examples:
|
||||
* `[7, 6, 5, 8, 1, 2, 6].iter.ensureTermination.findSome? (fun x => if x < 5 then some (10 * x) else none) = some 10`
|
||||
* `[7, 6, 5, 8, 1, 2, 6].iter.ensureTermination.findSome? (fun x => if x < 1 then some (10 * x) else none) = none`
|
||||
-/
|
||||
@[inline]
|
||||
def Iter.Total.findSome? {α β : Type w} {γ : Type x} [Iterator α Id β]
|
||||
[IteratorLoop α Id Id] [Finite α Id] (it : Iter.Total (α := α) β) (f : β → Option γ) :
|
||||
Option γ :=
|
||||
it.it.findSome? f
|
||||
|
||||
/--
|
||||
Returns the first output of the iterator for which the monadic predicate `p` returns `true`, or
|
||||
`none` if no such element is found.
|
||||
|
||||
`O(|it|)`. Short-circuits when `f` returns `true`. The outputs of `it` are examined in order of
|
||||
iteration.
|
||||
|
||||
If the iterator is not finite, this function might run forever. The variant
|
||||
`it.ensureTermination.findM?` always terminates after finitely many steps.
|
||||
|
||||
Example:
|
||||
```lean example
|
||||
#eval [7, 6, 5, 8, 1, 2, 6].iter.findM? fun i => do
|
||||
if i < 5 then
|
||||
return true
|
||||
if i ≤ 6 then
|
||||
IO.println s!"Almost! {i}"
|
||||
return false
|
||||
```
|
||||
```output
|
||||
Almost! 6
|
||||
Almost! 5
|
||||
```
|
||||
```output
|
||||
some 1
|
||||
```
|
||||
-/
|
||||
@[inline]
|
||||
def Iter.findM? {α β : Type w} {m : Type w → Type w'} [Monad m] [Iterator α Id β]
|
||||
[IteratorLoop α Id m] [Finite α Id] (it : Iter (α := α) β) (f : β → m (ULift Bool)) :
|
||||
m (Option β) :=
|
||||
it.findSomeM? (fun x => return if (← f x).down then some x else none)
|
||||
|
||||
@[inline, inherit_doc Iter.findM?]
|
||||
def Iter.Partial.findM? {α β : Type w} {m : Type w → Type w'} [Monad m] [Iterator α Id β]
|
||||
[IteratorLoopPartial α Id m] (it : Iter.Partial (α := α) β) (f : β → m (ULift Bool)) :
|
||||
[IteratorLoop α Id m] (it : Iter (α := α) β) (f : β → m (ULift Bool)) :
|
||||
m (Option β) :=
|
||||
it.findSomeM? (fun x => return if (← f x).down then some x else none)
|
||||
|
||||
/--
|
||||
Steps through the iterator until an element satisfies `f`, at which point iteration stops and the
|
||||
element is returned. If no element satisfies `f`, then the result is `none`.
|
||||
Returns the first output of the iterator for which the monadic predicate `p` returns `true`, or
|
||||
`none` if no such element is found.
|
||||
|
||||
`O(|it|)`. Short-circuits when `f` returns `true`. The outputs of `it` are examined in order of
|
||||
iteration.
|
||||
|
||||
This function is deprecated. Instead of `it.ensureTermination.findM?`, use `it.findM?`.
|
||||
|
||||
Example:
|
||||
```lean example
|
||||
#eval [7, 6, 5, 8, 1, 2, 6].iter.findM? fun i => do
|
||||
if i < 5 then
|
||||
return true
|
||||
if i ≤ 6 then
|
||||
IO.println s!"Almost! {i}"
|
||||
return false
|
||||
```
|
||||
```output
|
||||
Almost! 6
|
||||
Almost! 5
|
||||
```
|
||||
```output
|
||||
some 1
|
||||
```
|
||||
-/
|
||||
@[inline, deprecated Iter.findM? (since := "2025-12-04")]
|
||||
def Iter.Partial.findM? {α β : Type w} {m : Type w → Type w'} [Monad m] [Iterator α Id β]
|
||||
[IteratorLoop α Id m] (it : Iter.Partial (α := α) β) (f : β → m (ULift Bool)) :
|
||||
m (Option β) :=
|
||||
it.it.findM? f
|
||||
|
||||
/--
|
||||
Returns the first output of the iterator for which the monadic predicate `p` returns `true`, or
|
||||
`none` if no such element is found.
|
||||
|
||||
`O(|it|)`. Short-circuits when `f` returns `true`. The outputs of `it` are examined in order of
|
||||
iteration.
|
||||
|
||||
This variant requires terminates after finitely many steps and requires a proof that the iterator is
|
||||
finite. If such a proof is not available, consider using `Iter.findM?`.
|
||||
|
||||
Example:
|
||||
```lean example
|
||||
#eval [7, 6, 5, 8, 1, 2, 6].iter.findM? fun i => do
|
||||
if i < 5 then
|
||||
return true
|
||||
if i ≤ 6 then
|
||||
IO.println s!"Almost! {i}"
|
||||
return false
|
||||
```
|
||||
```output
|
||||
Almost! 6
|
||||
Almost! 5
|
||||
```
|
||||
```output
|
||||
some 1
|
||||
```
|
||||
-/
|
||||
@[inline]
|
||||
def Iter.Total.findM? {α β : Type w} {m : Type w → Type w'} [Monad m] [Iterator α Id β]
|
||||
[IteratorLoop α Id m] [Finite α Id] (it : Iter.Total (α := α) β) (f : β → m (ULift Bool)) :
|
||||
m (Option β) :=
|
||||
it.it.findM? f
|
||||
|
||||
/--
|
||||
Returns the first output of the iterator for which the predicate `p` returns `true`, or `none` if
|
||||
no such output is found.
|
||||
|
||||
`O(|it|)`. Short-circuits upon encountering the first match. The elements in `it` are examined in
|
||||
order of iteration.
|
||||
|
||||
If the iterator is not finite, this function might run forever. The variant
|
||||
`it.ensureTermination.find?` always terminates after finitely many steps.
|
||||
|
||||
Examples:
|
||||
* `[7, 6, 5, 8, 1, 2, 6].iter.find? (· < 5) = some 1`
|
||||
* `[7, 6, 5, 8, 1, 2, 6].iter.find? (· < 1) = none`
|
||||
-/
|
||||
@[inline]
|
||||
def Iter.find? {α β : Type w} [Iterator α Id β] [IteratorLoop α Id Id]
|
||||
[Finite α Id] (it : Iter (α := α) β) (f : β → Bool) : Option β :=
|
||||
(it : Iter (α := α) β) (f : β → Bool) : Option β :=
|
||||
Id.run (it.findM? (pure <| .up <| f ·))
|
||||
|
||||
@[inline, inherit_doc Iter.find?]
|
||||
def Iter.Partial.find? {α β : Type w} [Iterator α Id β] [IteratorLoopPartial α Id Id]
|
||||
/--
|
||||
Returns the first output of the iterator for which the predicate `p` returns `true`, or `none` if
|
||||
no such output is found.
|
||||
|
||||
`O(|it|)`. Short-circuits upon encountering the first match. The elements in `it` are examined in
|
||||
order of iteration.
|
||||
|
||||
This function is deprecated. Instead of `it.allowNontermination.find?`, use `it.find?`.
|
||||
|
||||
Examples:
|
||||
* `[7, 6, 5, 8, 1, 2, 6].iter.allowNontermination.find? (· < 5) = some 1`
|
||||
* `[7, 6, 5, 8, 1, 2, 6].iter.allowNontermination.find? (· < 1) = none`
|
||||
-/
|
||||
@[inline, deprecated Iter.find? (since := "2025-12-04")]
|
||||
def Iter.Partial.find? {α β : Type w} [Iterator α Id β] [IteratorLoop α Id Id]
|
||||
(it : Iter.Partial (α := α) β) (f : β → Bool) : Option β :=
|
||||
Id.run (it.findM? (pure <| .up <| f ·))
|
||||
it.it.find? f
|
||||
|
||||
/--
|
||||
Returns the first output of the iterator for which the predicate `p` returns `true`, or `none` if
|
||||
no such output is found.
|
||||
|
||||
`O(|it|)`. Short-circuits upon encountering the first match. The elements in `it` are examined in
|
||||
order of iteration.
|
||||
|
||||
This variant terminates after finitely many steps and requires a proof that the iterator is
|
||||
finite. If such a proof is not available, consider using `Iter.find?`.
|
||||
|
||||
Examples:
|
||||
* `[7, 6, 5, 8, 1, 2, 6].iter.find? (· < 5) = some 1`
|
||||
* `[7, 6, 5, 8, 1, 2, 6].iter.find? (· < 1) = none`
|
||||
-/
|
||||
@[inline]
|
||||
def Iter.Total.find? {α β : Type w} [Iterator α Id β] [IteratorLoop α Id Id] [Finite α Id]
|
||||
(it : Iter.Total (α := α) β) (f : β → Bool) : Option β :=
|
||||
it.it.find? f
|
||||
|
||||
/--
|
||||
Steps through the whole iterator, counting the number of outputs emitted.
|
||||
@@ -287,7 +638,7 @@ Steps through the whole iterator, counting the number of outputs emitted.
|
||||
This function's runtime is linear in the number of steps taken by the iterator.
|
||||
-/
|
||||
@[always_inline, inline, expose]
|
||||
def Iter.count {α : Type w} {β : Type w} [Iterator α Id β] [Finite α Id] [IteratorLoop α Id Id]
|
||||
def Iter.count {α : Type w} {β : Type w} [Iterator α Id β] [IteratorLoop α Id Id]
|
||||
(it : Iter (α := α) β) : Nat :=
|
||||
it.toIterM.count.run.down
|
||||
|
||||
@@ -299,7 +650,7 @@ Steps through the whole iterator, counting the number of outputs emitted.
|
||||
This function's runtime is linear in the number of steps taken by the iterator.
|
||||
-/
|
||||
@[always_inline, inline, expose, deprecated Iter.count (since := "2025-10-29")]
|
||||
def Iter.size {α : Type w} {β : Type w} [Iterator α Id β] [Finite α Id] [IteratorLoop α Id Id]
|
||||
def Iter.size {α : Type w} {β : Type w} [Iterator α Id β] [IteratorLoop α Id Id]
|
||||
(it : Iter (α := α) β) : Nat :=
|
||||
it.count
|
||||
|
||||
@@ -310,10 +661,10 @@ Steps through the whole iterator, counting the number of outputs emitted.
|
||||
|
||||
This function's runtime is linear in the number of steps taken by the iterator.
|
||||
-/
|
||||
@[always_inline, inline, expose]
|
||||
def Iter.Partial.count {α : Type w} {β : Type w} [Iterator α Id β] [IteratorLoopPartial α Id Id]
|
||||
@[always_inline, inline, expose, deprecated Iter.count (since := "2025-12-04")]
|
||||
def Iter.Partial.count {α : Type w} {β : Type w} [Iterator α Id β] [IteratorLoop α Id Id]
|
||||
(it : Iter.Partial (α := α) β) : Nat :=
|
||||
it.it.toIterM.allowNontermination.count.run.down
|
||||
it.it.toIterM.count.run.down
|
||||
|
||||
/--
|
||||
Steps through the whole iterator, counting the number of outputs emitted.
|
||||
@@ -322,9 +673,9 @@ Steps through the whole iterator, counting the number of outputs emitted.
|
||||
|
||||
This function's runtime is linear in the number of steps taken by the iterator.
|
||||
-/
|
||||
@[always_inline, inline, expose, deprecated Iter.Partial.count (since := "2025-10-29")]
|
||||
def Iter.Partial.size {α : Type w} {β : Type w} [Iterator α Id β] [IteratorLoopPartial α Id Id]
|
||||
@[always_inline, inline, expose, deprecated Iter.count (since := "2025-10-29")]
|
||||
def Iter.Partial.size {α : Type w} {β : Type w} [Iterator α Id β] [IteratorLoop α Id Id]
|
||||
(it : Iter.Partial (α := α) β) : Nat :=
|
||||
it.count
|
||||
it.it.count
|
||||
|
||||
end Std.Iterators
|
||||
end Std
|
||||
|
||||
@@ -10,7 +10,8 @@ public import Init.Data.Iterators.Basic
|
||||
|
||||
public section
|
||||
|
||||
namespace Std.Iterators
|
||||
namespace Std
|
||||
open Std.Iterators
|
||||
|
||||
/--
|
||||
`it.IsPlausibleNthOutputStep n step` is the proposition that according to the
|
||||
@@ -105,4 +106,4 @@ def IterM.atIdx? [Iterator α m β] [IteratorAccess α m] [Monad m] (it : IterM
|
||||
| .skip _ => return none
|
||||
| .done => return none
|
||||
|
||||
end Std.Iterators
|
||||
end Std
|
||||
|
||||
@@ -7,7 +7,9 @@ module
|
||||
|
||||
prelude
|
||||
public import Init.Data.Iterators.Consumers.Monadic.Partial
|
||||
public import Init.Data.Iterators.Consumers.Monadic.Total
|
||||
public import Init.Data.Iterators.Internal.LawfulMonadLiftFunction
|
||||
public import Init.WFExtrinsicFix
|
||||
|
||||
@[expose] public section
|
||||
|
||||
@@ -22,13 +24,13 @@ Concretely, the following operations are provided:
|
||||
* `IterM.toArray`, collecting the values in an array
|
||||
|
||||
Some producers and combinators provide specialized implementations. These are captured by the
|
||||
`IteratorCollect` and `IteratorCollectPartial` typeclasses. They should be implemented by all
|
||||
types of iterators. A default implementation is provided. The typeclass `LawfulIteratorCollect`
|
||||
asserts that an `IteratorCollect` instance equals the default implementation.
|
||||
`IteratorCollect` type class. They should be implemented by all types of iterators. A default
|
||||
implementation is provided. The typeclass `LawfulIteratorCollect` asserts that an `IteratorCollect`
|
||||
instance equals the default implementation.
|
||||
-/
|
||||
|
||||
namespace Std.Iterators
|
||||
open Std.Internal
|
||||
namespace Std
|
||||
open Std.Internal Std.Iterators
|
||||
|
||||
section Typeclasses
|
||||
|
||||
@@ -51,66 +53,58 @@ class IteratorCollect (α : Type w) (m : Type w → Type w') (n : Type w → Typ
|
||||
Maps the emitted values of an iterator using the given function and collects the results in an
|
||||
`Array`. This is an internal implementation detail. Consider using `it.map f |>.toArray` instead.
|
||||
-/
|
||||
toArrayMapped [Finite α m] :
|
||||
(lift : ⦃δ : Type w⦄ → m δ → n δ) → {γ : Type w} → (β → n γ) → IterM (α := α) m β → n (Array γ)
|
||||
|
||||
/--
|
||||
`IteratorCollectPartial α m` provides efficient implementations of collectors for `α`-based
|
||||
iterators. Right now, it is limited to a potentially optimized partial `toArray` implementation.
|
||||
|
||||
This class is experimental and users of the iterator API should not explicitly depend on it.
|
||||
They can, however, assume that consumers that require an instance will work for all iterators
|
||||
provided by the standard library.
|
||||
-/
|
||||
class IteratorCollectPartial (α : Type w) (m : Type w → Type w') (n : Type w → Type w'')
|
||||
{β : Type w} [Iterator α m β] where
|
||||
/--
|
||||
Maps the emitted values of an iterator using the given function and collects the results in an
|
||||
`Array`. This is an internal implementation detail.
|
||||
Consider using `it.map f |>.allowNontermination.toArray` instead.
|
||||
-/
|
||||
toArrayMappedPartial :
|
||||
toArrayMapped :
|
||||
(lift : ⦃δ : Type w⦄ → m δ → n δ) → {γ : Type w} → (β → n γ) → IterM (α := α) m β → n (Array γ)
|
||||
|
||||
end Typeclasses
|
||||
|
||||
section ToArray
|
||||
|
||||
def IterM.DefaultConsumers.toArrayMapped.RecursionRel {α β : Type w} {m : Type w → Type w'}
|
||||
[Iterator α m β] {γ : Type w} (x' x : (_ : IterM (α := α) m β) ×' Array γ) : Prop :=
|
||||
(∃ out, x.1.IsPlausibleStep (.yield x'.1 out) ∧ ∃ fx, x'.2 = x.2.push fx) ∨
|
||||
(x.1.IsPlausibleStep (.skip x'.1) ∧ x'.2 = x.2)
|
||||
|
||||
/--
|
||||
This is an internal function used in `IteratorCollect.defaultImplementation`.
|
||||
|
||||
It iterates over an iterator and applies `f` whenever a value is emitted before inserting the result
|
||||
of `f` into an array.
|
||||
-/
|
||||
@[always_inline, inline]
|
||||
@[always_inline, no_expose]
|
||||
def IterM.DefaultConsumers.toArrayMapped {α β : Type w} {m : Type w → Type w'}
|
||||
{n : Type w → Type w''} [Monad n] [Iterator α m β] [Finite α m]
|
||||
{n : Type w → Type w''} [Monad n] [Iterator α m β]
|
||||
(lift : ⦃α : Type w⦄ → m α → n α) {γ : Type w} (f : β → n γ)
|
||||
(it : IterM (α := α) m β) : n (Array γ) :=
|
||||
letI : MonadLift m n := ⟨lift (α := _)⟩
|
||||
go it #[]
|
||||
where
|
||||
@[specialize]
|
||||
go [Monad n] [Finite α m] (it : IterM (α := α) m β) a := letI : MonadLift m n := ⟨lift (α := _)⟩; do
|
||||
match (← it.step).inflate with
|
||||
| .yield it' b _ => go it' (a.push (← f b))
|
||||
| .skip it' _ => go it' a
|
||||
| .done _ => return a
|
||||
termination_by it.finitelyManySteps
|
||||
@[always_inline]
|
||||
go it (acc : Array γ) : n (Array γ) :=
|
||||
letI : MonadLift m n := ⟨lift (α := _)⟩
|
||||
WellFounded.extrinsicFix₂ (C₂ := fun _ _ => n (Array γ)) (InvImage TerminationMeasures.Finite.Rel (·.1.finitelyManySteps!))
|
||||
(fun (it : IterM (α := α) m β) acc recur => do
|
||||
match (← it.step).inflate with
|
||||
| .yield it' out h =>
|
||||
recur it' (acc.push (← f out)) (by exact TerminationMeasures.Finite.rel_of_yield ‹_›)
|
||||
| .skip it' h => recur it' acc (by exact TerminationMeasures.Finite.rel_of_skip ‹_›)
|
||||
| .done _ => return acc) it acc
|
||||
|
||||
/--
|
||||
This is the default implementation of the `IteratorLoop` class.
|
||||
This is the default implementation of the `IteratorCollect` class.
|
||||
It simply iterates through the iterator using `IterM.step`, incrementally building up the desired
|
||||
data structure. For certain iterators, more efficient implementations are possible and should be
|
||||
used instead.
|
||||
-/
|
||||
@[always_inline, inline]
|
||||
@[always_inline]
|
||||
def IteratorCollect.defaultImplementation {α β : Type w} {m : Type w → Type w'}
|
||||
{n : Type w → Type w''} [Monad n] [Iterator α m β] :
|
||||
IteratorCollect α m n where
|
||||
toArrayMapped := IterM.DefaultConsumers.toArrayMapped
|
||||
|
||||
/--
|
||||
Asserts that a given `IteratorCollect` instance is equal to `IteratorCollect.defaultImplementation`.
|
||||
Asserts that a given `IteratorCollect` instance is equal to `IteratorCollect.defaultImplementation`
|
||||
*if the underlying iterator is finite*.
|
||||
(Even though equal, the given instance might be vastly more efficient.)
|
||||
-/
|
||||
class LawfulIteratorCollect (α : Type w) (m : Type w → Type w') (n : Type w → Type w'')
|
||||
@@ -128,69 +122,45 @@ theorem LawfulIteratorCollect.toArrayMapped_eq {α β γ : Type w} {m : Type w
|
||||
IterM.DefaultConsumers.toArrayMapped lift f it (m := m) := by
|
||||
rw [lawful_toArrayMapped]; rfl
|
||||
|
||||
instance (α β : Type w) (m : Type w → Type w') (n : Type w → Type w'') [Monad n]
|
||||
[Iterator α m β] [Monad m] [Iterator α m β] [Finite α m] :
|
||||
instance instLawfulIteratorCollectDefaultImplementation (α β : Type w) (m : Type w → Type w')
|
||||
(n : Type w → Type w'') [Monad n] [Iterator α m β] [Monad m] [Iterator α m β] [Finite α m] :
|
||||
haveI : IteratorCollect α m n := .defaultImplementation
|
||||
LawfulIteratorCollect α m n :=
|
||||
letI : IteratorCollect α m n := .defaultImplementation
|
||||
⟨fun _ => rfl⟩
|
||||
|
||||
/--
|
||||
This is an internal function used in `IteratorCollectPartial.defaultImplementation`.
|
||||
|
||||
It iterates over an iterator and applies `f` whenever a value is emitted before inserting the result
|
||||
of `f` into an array.
|
||||
-/
|
||||
@[always_inline, inline]
|
||||
partial def IterM.DefaultConsumers.toArrayMappedPartial {α β : Type w} {m : Type w → Type w'}
|
||||
{n : Type w → Type w''} [Monad n] [Iterator α m β]
|
||||
(lift : {α : Type w} → m α → n α) {γ : Type w} (f : β → n γ)
|
||||
(it : IterM (α := α) m β) : n (Array γ) :=
|
||||
go it #[]
|
||||
where
|
||||
@[specialize]
|
||||
go [Monad n] (it : IterM (α := α) m β) a := letI : MonadLift m n := ⟨lift⟩; do
|
||||
match (← it.step).inflate with
|
||||
| .yield it' b _ => go it' (a.push (← f b))
|
||||
| .skip it' _ => go it' a
|
||||
| .done _ => return a
|
||||
|
||||
/--
|
||||
This is the default implementation of the `IteratorLoopPartial` class.
|
||||
It simply iterates through the iterator using `IterM.step`, incrementally building up the desired
|
||||
data structure. For certain iterators, more efficient implementations are possible and should be
|
||||
used instead.
|
||||
-/
|
||||
@[always_inline, inline]
|
||||
def IteratorCollectPartial.defaultImplementation {α β : Type w} {m : Type w → Type w'}
|
||||
{n : Type w → Type w''} [Monad n] [Iterator α m β] :
|
||||
IteratorCollectPartial α m n where
|
||||
toArrayMappedPartial := IterM.DefaultConsumers.toArrayMappedPartial
|
||||
|
||||
/--
|
||||
Traverses the given iterator and stores the emitted values in an array.
|
||||
|
||||
This function requires a `Finite` instance proving that the iterator will finish after a finite
|
||||
number of steps. If the iterator is not finite or such an instance is not available, consider using
|
||||
`it.allowNontermination.toArray` instead of `it.toArray`. However, it is not possible to formally
|
||||
verify the behavior of the partial variant.
|
||||
If the iterator is not finite, this function might run forever. The variant
|
||||
`it.ensureTermination.toArray` always terminates after finitely many steps.
|
||||
-/
|
||||
@[always_inline, inline]
|
||||
def IterM.toArray {α β : Type w} {m : Type w → Type w'} [Monad m]
|
||||
[Iterator α m β] [Finite α m] [IteratorCollect α m m]
|
||||
(it : IterM (α := α) m β) : m (Array β) :=
|
||||
def IterM.toArray {α β : Type w} {m : Type w → Type w'} [Monad m] [Iterator α m β]
|
||||
[IteratorCollect α m m] (it : IterM (α := α) m β) : m (Array β) :=
|
||||
IteratorCollect.toArrayMapped (fun ⦃_⦄ => id) pure it
|
||||
|
||||
/--
|
||||
Traverses the given iterator and stores the emitted values in an array.
|
||||
|
||||
This is a partial, potentially nonterminating, function. It is not possible to formally verify
|
||||
its behavior. If the iterator has a `Finite` instance, consider using `IterM.toArray` instead.
|
||||
This function is deprecated. Instead of `it.allowNontermination.toArray`, use `it.toArray`.
|
||||
-/
|
||||
@[always_inline, inline, deprecated IterM.toArray (since := "2025-10-23")]
|
||||
def IterM.Partial.toArray {α : Type w} {m : Type w → Type w'} {β : Type w} [Monad m]
|
||||
[Iterator α m β] (it : IterM.Partial (α := α) m β) [IteratorCollect α m m] : m (Array β) :=
|
||||
it.it.toArray
|
||||
|
||||
/--
|
||||
Traverses the given iterator and stores the emitted values in an array.
|
||||
|
||||
This variant terminates after finitely many steps and requires a proof that the iterator is
|
||||
finite. If such a proof is not available, consider using `IterM.toArray`.
|
||||
-/
|
||||
@[always_inline, inline]
|
||||
def IterM.Partial.toArray {α : Type w} {m : Type w → Type w'} {β : Type w} [Monad m]
|
||||
[Iterator α m β] (it : IterM.Partial (α := α) m β) [IteratorCollectPartial α m m] : m (Array β) :=
|
||||
IteratorCollectPartial.toArrayMappedPartial (fun ⦃_⦄ => id) pure it.it
|
||||
def IterM.Total.toArray {α : Type w} {m : Type w → Type w'} {β : Type w} [Monad m]
|
||||
[Iterator α m β] [Finite α m] (it : IterM.Total (α := α) m β) [IteratorCollect α m m] :
|
||||
m (Array β) :=
|
||||
it.it.toArray
|
||||
|
||||
end ToArray
|
||||
|
||||
@@ -198,67 +168,82 @@ end ToArray
|
||||
Traverses the given iterator and stores the emitted values in reverse order in a list. Because
|
||||
lists are prepend-only, this `toListRev` is usually more efficient that `toList`.
|
||||
|
||||
This function requires a `Finite` instance proving that the iterator will finish after a finite
|
||||
number of steps. If the iterator is not finite or such an instance is not available, consider using
|
||||
`it.allowNontermination.toListRev` instead of `it.toListRev`. However, it is not possible to
|
||||
formally verify the behavior of the partial variant.
|
||||
If the iterator is not finite, this function might run forever. The variant
|
||||
`it.ensureTermination.toListRev` always terminates after finitely many steps.
|
||||
-/
|
||||
@[inline]
|
||||
@[always_inline, inline]
|
||||
def IterM.toListRev {α : Type w} {m : Type w → Type w'} [Monad m] {β : Type w}
|
||||
[Iterator α m β] [Finite α m] (it : IterM (α := α) m β) : m (List β) :=
|
||||
[Iterator α m β] (it : IterM (α := α) m β) : m (List β) :=
|
||||
go it []
|
||||
where
|
||||
go [Finite α m] it bs := do
|
||||
match (← it.step).inflate with
|
||||
| .yield it' b _ => go it' (b :: bs)
|
||||
| .skip it' _ => go it' bs
|
||||
| .done _ => return bs
|
||||
termination_by it.finitelyManySteps
|
||||
@[always_inline, inline]
|
||||
go (it : IterM m β) acc :=
|
||||
WellFounded.extrinsicFix₂ (InvImage TerminationMeasures.Finite.Rel (·.1.finitelyManySteps!))
|
||||
(fun it acc recur => do
|
||||
match (← it.step).inflate with
|
||||
| .yield it' out h => recur it' (out :: acc) (TerminationMeasures.Finite.rel_of_yield h)
|
||||
| .skip it' h => recur it' acc (TerminationMeasures.Finite.rel_of_skip h)
|
||||
| .done _ => return acc) it acc
|
||||
|
||||
/--
|
||||
Traverses the given iterator and stores the emitted values in reverse order in a list. Because
|
||||
lists are prepend-only, this `toListRev` is usually more efficient that `toList`.
|
||||
|
||||
This is a partial, potentially nonterminating, function. It is not possible to formally verify
|
||||
its behavior. If the iterator has a `Finite` instance, consider using `IterM.toListRev` instead.
|
||||
This function is deprecated. Instead of `it.allowNontermination.toListRev`, use `it.toListRev`.
|
||||
-/
|
||||
@[always_inline, inline]
|
||||
@[always_inline, inline, deprecated IterM.toListRev (since := "2025-10-23")]
|
||||
partial def IterM.Partial.toListRev {α : Type w} {m : Type w → Type w'} [Monad m] {β : Type w}
|
||||
[Iterator α m β] (it : IterM.Partial (α := α) m β) : m (List β) :=
|
||||
go it.it []
|
||||
where
|
||||
@[specialize]
|
||||
go it bs := do
|
||||
match (← it.step).inflate with
|
||||
| .yield it' b _ => go it' (b :: bs)
|
||||
| .skip it' _ => go it' bs
|
||||
| .done _ => return bs
|
||||
it.it.toListRev
|
||||
|
||||
/--
|
||||
Traverses the given iterator and stores the emitted values in reverse order in a list. Because
|
||||
lists are prepend-only, this `toListRev` is usually more efficient that `toList`.
|
||||
|
||||
This variant terminates after finitely many steps and requires a proof that the iterator is
|
||||
finite. If such a proof is not available, consider using `IterM.toListRev`.
|
||||
-/
|
||||
@[always_inline, inline]
|
||||
def IterM.Total.toListRev {α : Type w} {m : Type w → Type w'} {β : Type w} [Monad m]
|
||||
[Iterator α m β] [Finite α m] (it : IterM.Total (α := α) m β) :
|
||||
m (List β) :=
|
||||
it.it.toListRev
|
||||
|
||||
/--
|
||||
Traverses the given iterator and stores the emitted values in a list. Because
|
||||
lists are prepend-only, `toListRev` is usually more efficient that `toList`.
|
||||
|
||||
This function requires a `Finite` instance proving that the iterator will finish after a finite
|
||||
number of steps. If the iterator is not finite or such an instance is not available, consider using
|
||||
`it.allowNontermination.toList` instead of `it.toList`. However, it is not possible to
|
||||
formally verify the behavior of the partial variant.
|
||||
If the iterator is not finite, this function might run forever. The variant
|
||||
`it.ensureTermination.toList` always terminates after finitely many steps.
|
||||
-/
|
||||
@[always_inline, inline]
|
||||
def IterM.toList {α : Type w} {m : Type w → Type w'} [Monad m] {β : Type w}
|
||||
[Iterator α m β] [Finite α m] [IteratorCollect α m m] (it : IterM (α := α) m β) : m (List β) :=
|
||||
[Iterator α m β] [IteratorCollect α m m] (it : IterM (α := α) m β) : m (List β) :=
|
||||
Array.toList <$> IterM.toArray it
|
||||
|
||||
/--
|
||||
Traverses the given iterator and stores the emitted values in a list. Because
|
||||
lists are prepend-only, `toListRev` is usually more efficient that `toList`.
|
||||
|
||||
This is a partial, potentially nonterminating, function. It is not possible to formally verify
|
||||
its behavior. If the iterator has a `Finite` instance, consider using `IterM.toList` instead.
|
||||
This function is deprecated. Instead of `it.allowNontermination.toList`, use `it.toList`.
|
||||
-/
|
||||
@[always_inline, inline, deprecated IterM.toList (since := "2025-10-23")]
|
||||
def IterM.Partial.toList {α : Type w} {m : Type w → Type w'} [Monad m] {β : Type w}
|
||||
[Iterator α m β] (it : IterM.Partial (α := α) m β) [IteratorCollect α m m] :
|
||||
m (List β) :=
|
||||
Array.toList <$> it.it.toArray
|
||||
|
||||
/--
|
||||
Traverses the given iterator and stores the emitted values in a list. Because
|
||||
lists are prepend-only, `toListRev` is usually more efficient that `toList`.
|
||||
|
||||
This variant terminates after finitely many steps and requires a proof that the iterator is
|
||||
finite. If such a proof is not available, consider using `IterM.toList`.
|
||||
-/
|
||||
@[always_inline, inline]
|
||||
def IterM.Partial.toList {α : Type w} {m : Type w → Type w'} [Monad m] {β : Type w}
|
||||
[Iterator α m β] (it : IterM.Partial (α := α) m β) [IteratorCollectPartial α m m] :
|
||||
def IterM.Total.toList {α : Type w} {m : Type w → Type w'} {β : Type w} [Monad m]
|
||||
[Iterator α m β] [Finite α m] (it : IterM.Total (α := α) m β) [IteratorCollect α m m] :
|
||||
m (List β) :=
|
||||
Array.toList <$> it.toArray
|
||||
it.it.toList
|
||||
|
||||
end Std.Iterators
|
||||
end Std
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -10,7 +10,7 @@ public import Init.Data.Iterators.Basic
|
||||
|
||||
public section
|
||||
|
||||
namespace Std.Iterators
|
||||
namespace Std
|
||||
|
||||
/--
|
||||
A wrapper around an iterator that provides partial consumers. See `IterM.allowNontermination`.
|
||||
@@ -29,4 +29,4 @@ def IterM.allowNontermination {α : Type w} {m : Type w → Type w'} {β : Type
|
||||
(it : IterM (α := α) m β) : IterM.Partial (α := α) m β :=
|
||||
⟨it⟩
|
||||
|
||||
end Std.Iterators
|
||||
end Std
|
||||
|
||||
36
src/Init/Data/Iterators/Consumers/Monadic/Total.lean
Normal file
36
src/Init/Data/Iterators/Consumers/Monadic/Total.lean
Normal file
@@ -0,0 +1,36 @@
|
||||
/-
|
||||
Copyright (c) 2025 Lean FRO, LLC. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Paul Reichert
|
||||
-/
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Data.Iterators.Basic
|
||||
|
||||
set_option doc.verso true
|
||||
|
||||
public section
|
||||
|
||||
namespace Std
|
||||
|
||||
structure IterM.Total {α : Type w} (m : Type w → Type w') (β : Type w) where
|
||||
it : IterM (α := α) m β
|
||||
|
||||
/--
|
||||
For an iterator {name}`it`, {lean}`it.ensureTermination` provides variants of consumers that always
|
||||
terminate.
|
||||
-/
|
||||
@[always_inline, inline]
|
||||
def IterM.ensureTermination {α : Type w} {β : Type w} {m : Type w → Type w'}
|
||||
(it : IterM (α := α) m β) :
|
||||
IterM.Total (α := α) m β :=
|
||||
⟨it⟩
|
||||
|
||||
/--
|
||||
A wrapper around an iterator that provides strictly terminating consumers. See
|
||||
{name}`IterM.ensureTermination`.
|
||||
-/
|
||||
add_decl_doc IterM.Total
|
||||
|
||||
end Std
|
||||
@@ -10,7 +10,7 @@ public import Init.Data.Iterators.Basic
|
||||
|
||||
public section
|
||||
|
||||
namespace Std.Iterators
|
||||
namespace Std
|
||||
|
||||
/--
|
||||
A wrapper around an iterator that provides partial consumers. See `Iter.allowNontermination`.
|
||||
@@ -29,4 +29,4 @@ def Iter.allowNontermination {α : Type w} {β : Type w}
|
||||
(it : Iter (α := α) β) : Iter.Partial (α := α) β :=
|
||||
⟨it⟩
|
||||
|
||||
end Std.Iterators
|
||||
end Std
|
||||
|
||||
@@ -11,7 +11,8 @@ public import Init.Data.Iterators.Consumers.Access
|
||||
|
||||
public section
|
||||
|
||||
namespace Std.Iterators
|
||||
namespace Std
|
||||
open Std.Iterators
|
||||
|
||||
instance {α β} [Iterator α Id β] [Productive α Id] [IteratorAccess α Id] :
|
||||
Stream (Iter (α := α) β) β where
|
||||
@@ -24,4 +25,4 @@ instance {α β} [Iterator α Id β] [Productive α Id] [IteratorAccess α Id] :
|
||||
revert h
|
||||
exact IterM.not_isPlausibleNthOutputStep_yield
|
||||
|
||||
end Std.Iterators
|
||||
end Std
|
||||
|
||||
36
src/Init/Data/Iterators/Consumers/Total.lean
Normal file
36
src/Init/Data/Iterators/Consumers/Total.lean
Normal file
@@ -0,0 +1,36 @@
|
||||
/-
|
||||
Copyright (c) 2025 Lean FRO, LLC. All rights reserved.
|
||||
Released under Apache 2.0 license as described in the file LICENSE.
|
||||
Authors: Paul Reichert
|
||||
-/
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Data.Iterators.Basic
|
||||
|
||||
set_option doc.verso true
|
||||
|
||||
public section
|
||||
|
||||
namespace Std
|
||||
|
||||
structure Iter.Total {α : Type w} (β : Type w) where
|
||||
it : Iter (α := α) β
|
||||
|
||||
/--
|
||||
For an iterator {name}`it`, {lean}`it.ensureTermination` provides variants of consumers that always
|
||||
terminate.
|
||||
-/
|
||||
@[always_inline, inline]
|
||||
def Iter.ensureTermination {α : Type w} {β : Type w}
|
||||
(it : Iter (α := α) β) :
|
||||
Iter.Total (α := α) β :=
|
||||
⟨it⟩
|
||||
|
||||
/--
|
||||
A wrapper around an iterator that provides strictly terminating consumers. See
|
||||
{name}`Iter.ensureTermination`.
|
||||
-/
|
||||
add_decl_doc Iter.Total
|
||||
|
||||
end Std
|
||||
@@ -10,7 +10,8 @@ public import Init.Data.Iterators.Basic
|
||||
|
||||
public section
|
||||
|
||||
namespace Std.Iterators
|
||||
namespace Std
|
||||
open Std.Iterators
|
||||
|
||||
/--
|
||||
Induction principle for finite iterators: One can define a function `f` that maps every
|
||||
@@ -46,4 +47,4 @@ def Iter.inductSkips {α β} [Iterator α Id β] [Productive α Id]
|
||||
step it (fun {it'} _ => inductSkips motive step it')
|
||||
termination_by it.finitelyManySkips
|
||||
|
||||
end Std.Iterators
|
||||
end Std
|
||||
|
||||
@@ -16,7 +16,8 @@ public import Init.Data.Array.Attach
|
||||
|
||||
public section
|
||||
|
||||
namespace Std.Iterators
|
||||
namespace Std
|
||||
open Std.Iterators
|
||||
|
||||
theorem Iter.unattach_eq_toIter_unattach_toIterM [Iterator α Id β] {it : Iter (α := α) β} {hP} :
|
||||
it.attachWith P hP =
|
||||
@@ -93,4 +94,4 @@ theorem Iter.count_attachWith [Iterator α Id β]
|
||||
rw [← Iter.length_toList_eq_count, toList_attachWith]
|
||||
simp
|
||||
|
||||
end Std.Iterators
|
||||
end Std
|
||||
|
||||
@@ -12,7 +12,8 @@ public import Init.Data.Iterators.Combinators.FilterMap
|
||||
|
||||
public section
|
||||
|
||||
namespace Std.Iterators
|
||||
namespace Std
|
||||
open Std.Iterators
|
||||
|
||||
variable {α β γ : Type w} [Iterator α Id β] {it : Iter (α := α) β}
|
||||
{m : Type w → Type w'} {n : Type w → Type w''}
|
||||
@@ -791,4 +792,4 @@ theorem Iter.all_map {α β β' : Type w}
|
||||
· simp [ihs ‹_›]
|
||||
· simp
|
||||
|
||||
end Std.Iterators
|
||||
end Std
|
||||
|
||||
@@ -11,8 +11,10 @@ public import Init.Data.Iterators.Combinators.FlatMap
|
||||
import all Init.Data.Iterators.Combinators.FlatMap
|
||||
public import Init.Data.Iterators.Lemmas.Combinators.Monadic.FlatMap
|
||||
|
||||
namespace Std.Iterators
|
||||
open Std.Internal
|
||||
namespace Std
|
||||
open Std.Internal Std.Iterators
|
||||
|
||||
namespace Iterators.Types
|
||||
|
||||
public theorem Flatten.IsPlausibleStep.outerYield_flatMapM_pure {α : Type w} {β : Type w} {α₂ : Type w}
|
||||
{γ : Type w} {m : Type w → Type w'} [Monad m] [LawfulMonad m] [Iterator α Id β] [Iterator α₂ m γ]
|
||||
@@ -99,6 +101,8 @@ public theorem Flatten.IsPlausibleStep.innerDone_flatMap_pure {α : Type w} {β
|
||||
(it₁.flatMapAfter f (some it₂)).IsPlausibleStep (.skip (it₁.flatMapAfter f none)) :=
|
||||
innerDone_flatMap h
|
||||
|
||||
end Iterators.Types
|
||||
|
||||
public theorem Iter.step_flatMapAfterM {α : Type w} {β : Type w} {α₂ : Type w}
|
||||
{γ : Type w} {m : Type w → Type w'} [Monad m] [LawfulMonad m] [Iterator α Id β] [Iterator α₂ m γ]
|
||||
{f : β → m (IterM (α := α₂) m γ)} {it₁ : Iter (α := α) β} {it₂ : Option (IterM (α := α₂) m γ)} :
|
||||
@@ -263,4 +267,4 @@ public theorem Iter.toArray_flatMap {α α₂ β γ : Type w} [Iterator α Id β
|
||||
(it₁.flatMap f).toArray = (it₁.map fun b => (f b).toArray).toArray.flatten := by
|
||||
simp [flatMap, toArray_flatMapAfter]
|
||||
|
||||
end Std.Iterators
|
||||
end Std
|
||||
|
||||
@@ -13,13 +13,14 @@ public import Init.Data.Iterators.Lemmas.Consumers.Monadic.Loop
|
||||
|
||||
public section
|
||||
|
||||
namespace Std.Iterators
|
||||
namespace Std
|
||||
open Std.Iterators Std.Iterators.Types
|
||||
|
||||
variable {α : Type w} {m : Type w → Type w'} {β : Type w} {P : β → Prop}
|
||||
|
||||
theorem IterM.step_attachWith [Iterator α m β] [Monad m] {it : IterM (α := α) m β} {hP} :
|
||||
(it.attachWith P hP).step =
|
||||
(fun s => .deflate ⟨Types.Attach.Monadic.modifyStep (it.attachWith P hP) s.inflate, s.inflate, rfl⟩) <$> it.step :=
|
||||
(fun s => .deflate ⟨Attach.Monadic.modifyStep (it.attachWith P hP) s.inflate, s.inflate, rfl⟩) <$> it.step :=
|
||||
rfl
|
||||
|
||||
@[simp]
|
||||
@@ -70,4 +71,4 @@ theorem IterM.count_attachWith [Iterator α m β] [Monad m] [Monad n]
|
||||
← map_unattach_toList_attachWith (it := it) (P := P) (hP := hP)]
|
||||
simp only [Functor.map_map, List.length_unattach]
|
||||
|
||||
end Std.Iterators
|
||||
end Std
|
||||
|
||||
@@ -12,8 +12,8 @@ import all Init.Data.Iterators.Consumers.Monadic.Collect
|
||||
|
||||
public section
|
||||
|
||||
namespace Std.Iterators
|
||||
open Std.Internal
|
||||
namespace Std
|
||||
open Std.Internal Std.Iterators Std.Iterators.Types
|
||||
|
||||
section Step
|
||||
|
||||
@@ -234,7 +234,8 @@ end Step
|
||||
section Lawful
|
||||
|
||||
@[no_expose]
|
||||
instance {α β γ : Type w} {m : Type w → Type w'} {n : Type w → Type w''} {o : Type w → Type x}
|
||||
instance Iterators.Types.Map.instLawfulIteratorCollect {α β γ : Type w} {m : Type w → Type w'}
|
||||
{n : Type w → Type w''} {o : Type w → Type x}
|
||||
[Monad m] [Monad n] [Monad o] [LawfulMonad n] [LawfulMonad o] [Iterator α m β] [Finite α m]
|
||||
[IteratorCollect α m o] [LawfulIteratorCollect α m o]
|
||||
{lift : ⦃δ : Type w⦄ -> m δ → n δ} {f : β → PostconditionT n γ} [LawfulMonadLiftFunction lift] :
|
||||
@@ -247,9 +248,8 @@ instance {α β γ : Type w} {m : Type w → Type w'} {n : Type w → Type w''}
|
||||
have : it = IterM.mapWithPostcondition _ it.internalState.inner := by rfl
|
||||
generalize it.internalState.inner = it at *
|
||||
cases this
|
||||
simp only [LawfulIteratorCollect.toArrayMapped_eq]
|
||||
simp only [IteratorCollect.toArrayMapped]
|
||||
rw [LawfulIteratorCollect.toArrayMapped_eq]
|
||||
simp only [LawfulIteratorCollect.toArrayMapped_eq]
|
||||
induction it using IterM.inductSteps with | step it ih_yield ih_skip
|
||||
rw [IterM.DefaultConsumers.toArrayMapped_eq_match_step]
|
||||
rw [IterM.DefaultConsumers.toArrayMapped_eq_match_step]
|
||||
@@ -484,17 +484,12 @@ theorem IterM.toList_map {α β β' : Type w} {m : Type w → Type w'} [Monad m]
|
||||
let t' := type_of% (it.filterMap (some ∘ f))
|
||||
congr
|
||||
· simp [Map]
|
||||
· simp [instIteratorMap, inferInstanceAs]
|
||||
· simp [Map.instIterator, inferInstanceAs]
|
||||
congr
|
||||
simp
|
||||
· refine heq_of_eqRec_eq ?_ rfl
|
||||
congr
|
||||
· congr
|
||||
simp only [Map, PostconditionT.map_pure, Function.comp_apply]
|
||||
simp only [instIteratorMap, inferInstanceAs, Function.comp_apply]
|
||||
congr
|
||||
simp
|
||||
· simp [Map]
|
||||
· simp only [instIteratorMap, inferInstanceAs, Function.comp_apply]
|
||||
· simp only [Map.instIterator, inferInstanceAs, Function.comp_apply]
|
||||
congr
|
||||
simp
|
||||
· simp only [map, mapWithPostcondition, InternalCombinators.map, Function.comp_apply, filterMap,
|
||||
@@ -1268,4 +1263,4 @@ theorem IterM.all_map {α β β' : Type w} {m : Type w → Type w'}
|
||||
|
||||
end AnyAll
|
||||
|
||||
end Std.Iterators
|
||||
end Std
|
||||
|
||||
@@ -11,8 +11,8 @@ import Init.Data.Iterators.Lemmas.Combinators.Monadic.FilterMap
|
||||
public import Init.Data.Iterators.Combinators.Monadic.FlatMap
|
||||
import all Init.Data.Iterators.Combinators.Monadic.FlatMap
|
||||
|
||||
namespace Std.Iterators
|
||||
open Std.Internal
|
||||
namespace Std
|
||||
open Std.Internal Std.Iterators
|
||||
|
||||
theorem IterM.step_flattenAfter {α α₂ β : Type w} {m : Type w → Type w'} [Monad m]
|
||||
[Iterator α m (IterM (α := α₂) m β)] [Iterator α₂ m β]
|
||||
@@ -32,7 +32,9 @@ theorem IterM.step_flattenAfter {α α₂ β : Type w} {m : Type w → Type w'}
|
||||
cases it₂
|
||||
all_goals
|
||||
· apply bind_congr; intro step
|
||||
cases step.inflate using PlausibleIterStep.casesOn <;> simp [IterM.flattenAfter, toIterM]
|
||||
cases step.inflate using PlausibleIterStep.casesOn <;> simp [IterM.flattenAfter, IterM.mk]
|
||||
|
||||
namespace Iterators.Types
|
||||
|
||||
public theorem Flatten.IsPlausibleStep.outerYield_flatMapM {α : Type w} {β : Type w} {α₂ : Type w}
|
||||
{γ : Type w} {m : Type w → Type w'} [Monad m] [LawfulMonad m] [Iterator α m β] [Iterator α₂ m γ]
|
||||
@@ -118,6 +120,8 @@ public theorem Flatten.IsPlausibleStep.innerDone_flatMap {α : Type w} {β : Typ
|
||||
(it₁.flatMapAfter f (some it₂)).IsPlausibleStep (.skip (it₁.flatMapAfter f none)) :=
|
||||
.innerDone h
|
||||
|
||||
end Iterators.Types
|
||||
|
||||
public theorem IterM.step_flatMapAfterM {α : Type w} {β : Type w} {α₂ : Type w}
|
||||
{γ : Type w} {m : Type w → Type w'} [Monad m] [LawfulMonad m] [Iterator α m β] [Iterator α₂ m γ]
|
||||
{f : β → m (IterM (α := α₂) m γ)} {it₁ : IterM (α := α) m β} {it₂ : Option (IterM (α := α₂) m γ)} :
|
||||
@@ -341,4 +345,4 @@ public theorem IterM.toArray_flatMap {α α₂ β γ : Type w} {m : Type w → T
|
||||
(it₁.flatMap f).toArray = Array.flatten <$> (it₁.mapM fun b => (f b).toArray).toArray := by
|
||||
simp [flatMap, toArray_flatMapAfter]
|
||||
|
||||
end Std.Iterators
|
||||
end Std
|
||||
|
||||
@@ -11,7 +11,10 @@ public import Init.Data.Iterators.Lemmas.Consumers.Monadic
|
||||
|
||||
@[expose] public section
|
||||
|
||||
namespace Std.Iterators
|
||||
namespace Std
|
||||
open Std.Iterators Std.Iterators.Types
|
||||
|
||||
namespace Iterators.Types
|
||||
|
||||
theorem Take.isPlausibleStep_take_yield [Monad m] [Iterator α m β] {n : Nat}
|
||||
{it : IterM (α := α) m β} (h : it.IsPlausibleStep (.yield it' out)) :
|
||||
@@ -23,6 +26,8 @@ theorem Take.isPlausibleStep_take_skip [Monad m] [Iterator α m β] {n : Nat}
|
||||
(it.take (n + 1)).IsPlausibleStep (.skip (it'.take (n + 1))) :=
|
||||
(.skip h (by simp [IterM.take]))
|
||||
|
||||
end Iterators.Types
|
||||
|
||||
theorem IterM.step_take {α m β} [Monad m] [Iterator α m β] {n : Nat}
|
||||
{it : IterM (α := α) m β} :
|
||||
(it.take n).step = (match n with
|
||||
@@ -74,4 +79,4 @@ theorem IterM.toList_toTake {α m β} [Monad m] [LawfulMonad m] [Iterator α m
|
||||
· simp [ihs ‹_›]
|
||||
· simp
|
||||
|
||||
end Std.Iterators
|
||||
end Std
|
||||
|
||||
@@ -12,7 +12,8 @@ public import Init.Data.Iterators.Lemmas.Consumers.Monadic.Loop
|
||||
|
||||
public section
|
||||
|
||||
namespace Std.Iterators
|
||||
namespace Std
|
||||
open Std.Iterators
|
||||
|
||||
variable {α : Type u} {m : Type u → Type u'} {n : Type max u v → Type v'}
|
||||
{β : Type u}
|
||||
@@ -80,4 +81,4 @@ theorem IterM.count_uLift [Iterator α m β] [Monad m] [Monad n] {it : IterM (α
|
||||
· simp [ihs ‹_›]
|
||||
· simp
|
||||
|
||||
end Std.Iterators
|
||||
end Std
|
||||
|
||||
@@ -12,7 +12,8 @@ public import Init.Data.Iterators.Lemmas.Consumers
|
||||
|
||||
@[expose] public section
|
||||
|
||||
namespace Std.Iterators
|
||||
namespace Std
|
||||
open Std.Iterators Std.Iterators.Types
|
||||
|
||||
theorem Iter.take_eq_toIter_take_toIterM {α β} [Iterator α Id β] {n : Nat}
|
||||
{it : Iter (α := α) β} :
|
||||
@@ -118,4 +119,4 @@ theorem Iter.toList_toTake {α β} [Iterator α Id β] [Finite α Id]
|
||||
it.toTake.toList = it.toList := by
|
||||
simp [toTake_eq_toIter_toTake_toIterM, toList_eq_toList_toIterM]
|
||||
|
||||
end Std.Iterators
|
||||
end Std
|
||||
|
||||
@@ -14,7 +14,8 @@ public import Init.Data.Iterators.Lemmas.Consumers.Loop
|
||||
|
||||
public section
|
||||
|
||||
namespace Std.Iterators
|
||||
namespace Std
|
||||
open Std.Iterators
|
||||
|
||||
variable {α : Type u} {β : Type u}
|
||||
|
||||
@@ -66,4 +67,4 @@ theorem Iter.count_uLift [Iterator α Id β] {it : Iter (α := α) β}
|
||||
rw [IterM.count_uLift]
|
||||
simp [monadLift]
|
||||
|
||||
end Std.Iterators
|
||||
end Std
|
||||
|
||||
@@ -11,10 +11,13 @@ public import Init.Data.Iterators.Lemmas.Consumers.Monadic.Collect
|
||||
public import Init.Data.Iterators.Consumers.Access
|
||||
import all Init.Data.Iterators.Consumers.Access
|
||||
import all Init.Data.Iterators.Consumers.Collect
|
||||
import all Init.Data.Iterators.Consumers.Total
|
||||
import all Init.Data.Iterators.Consumers.Monadic.Total
|
||||
|
||||
public section
|
||||
|
||||
namespace Std.Iterators
|
||||
namespace Std
|
||||
open Std.Iterators
|
||||
|
||||
theorem Iter.toArray_eq_toArray_toIterM {α β} [Iterator α Id β] [Finite α Id] [IteratorCollect α Id Id]
|
||||
[LawfulIteratorCollect α Id Id] {it : Iter (α := α) β} :
|
||||
@@ -31,6 +34,23 @@ theorem Iter.toListRev_eq_toListRev_toIterM {α β} [Iterator α Id β] [Finite
|
||||
it.toListRev = it.toIterM.toListRev.run :=
|
||||
(rfl)
|
||||
|
||||
@[simp]
|
||||
theorem Iter.toArray_ensureTermination {α β} [Iterator α Id β] [Finite α Id] [IteratorCollect α Id Id]
|
||||
[LawfulIteratorCollect α Id Id] {it : Iter (α := α) β} :
|
||||
it.ensureTermination.toArray = it.toArray :=
|
||||
(rfl)
|
||||
|
||||
@[simp]
|
||||
theorem Iter.toList_ensureTermination {α β} [Iterator α Id β] [Finite α Id] [IteratorCollect α Id Id]
|
||||
[LawfulIteratorCollect α Id Id] {it : Iter (α := α) β} :
|
||||
it.ensureTermination.toList = it.toList :=
|
||||
(rfl)
|
||||
|
||||
@[simp]
|
||||
theorem Iter.toListRev_ensureTermination_eq_toListRev {α β} [Iterator α Id β] [Finite α Id]
|
||||
{it : Iter (α := α) β} : it.ensureTermination.toListRev = it.toListRev :=
|
||||
(rfl)
|
||||
|
||||
@[simp]
|
||||
theorem IterM.toList_toIter {α β} [Iterator α Id β] [Finite α Id] [IteratorCollect α Id Id]
|
||||
{it : IterM (α := α) Id β} :
|
||||
@@ -49,12 +69,22 @@ theorem Iter.toList_toArray {α β} [Iterator α Id β] [Finite α Id] [Iterator
|
||||
it.toArray.toList = it.toList := by
|
||||
simp [toArray_eq_toArray_toIterM, toList_eq_toList_toIterM, ← IterM.toList_toArray]
|
||||
|
||||
theorem Iter.toList_toArray_ensureTermination {α β} [Iterator α Id β] [Finite α Id]
|
||||
[IteratorCollect α Id Id] [LawfulIteratorCollect α Id Id] {it : Iter (α := α) β} :
|
||||
it.ensureTermination.toArray.toList = it.toList := by
|
||||
simp
|
||||
|
||||
@[simp]
|
||||
theorem Iter.toArray_toList {α β} [Iterator α Id β] [Finite α Id] [IteratorCollect α Id Id]
|
||||
[LawfulIteratorCollect α Id Id] {it : Iter (α := α) β} :
|
||||
it.toList.toArray = it.toArray := by
|
||||
simp [toArray_eq_toArray_toIterM, toList_eq_toList_toIterM, ← IterM.toArray_toList]
|
||||
|
||||
theorem Iter.toArray_toList_ensureTermination {α β} [Iterator α Id β] [Finite α Id]
|
||||
[IteratorCollect α Id Id] [LawfulIteratorCollect α Id Id] {it : Iter (α := α) β} :
|
||||
it.ensureTermination.toList.toArray = it.toArray := by
|
||||
simp
|
||||
|
||||
@[simp]
|
||||
theorem Iter.reverse_toListRev [Iterator α Id β] [Finite α Id]
|
||||
[IteratorCollect α Id Id] [LawfulIteratorCollect α Id Id]
|
||||
@@ -62,11 +92,21 @@ theorem Iter.reverse_toListRev [Iterator α Id β] [Finite α Id]
|
||||
it.toListRev.reverse = it.toList := by
|
||||
simp [toListRev_eq_toListRev_toIterM, toList_eq_toList_toIterM, ← IterM.reverse_toListRev]
|
||||
|
||||
theorem Iter.reverse_toListRev_ensureTermination [Iterator α Id β] [Finite α Id]
|
||||
[IteratorCollect α Id Id] [LawfulIteratorCollect α Id Id] {it : Iter (α := α) β} :
|
||||
it.ensureTermination.toListRev.reverse = it.toList := by
|
||||
simp
|
||||
|
||||
theorem Iter.toListRev_eq {α β} [Iterator α Id β] [Finite α Id] [IteratorCollect α Id Id]
|
||||
[LawfulIteratorCollect α Id Id] {it : Iter (α := α) β} :
|
||||
it.toListRev = it.toList.reverse := by
|
||||
simp [Iter.toListRev_eq_toListRev_toIterM, Iter.toList_eq_toList_toIterM, IterM.toListRev_eq]
|
||||
|
||||
theorem Iter.toListRev_ensureTermination {α β} [Iterator α Id β] [Finite α Id]
|
||||
[IteratorCollect α Id Id] [LawfulIteratorCollect α Id Id] {it : Iter (α := α) β} :
|
||||
it.ensureTermination.toListRev = it.toList.reverse := by
|
||||
simp [toListRev_eq]
|
||||
|
||||
theorem Iter.toArray_eq_match_step {α β} [Iterator α Id β] [Finite α Id] [IteratorCollect α Id Id]
|
||||
[LawfulIteratorCollect α Id Id] {it : Iter (α := α) β} :
|
||||
it.toArray = match it.step.val with
|
||||
@@ -78,6 +118,14 @@ theorem Iter.toArray_eq_match_step {α β} [Iterator α Id β] [Finite α Id] [I
|
||||
generalize it.toIterM.step.run = step
|
||||
cases step.inflate using PlausibleIterStep.casesOn <;> simp
|
||||
|
||||
theorem Iter.toArray_ensureTermination_eq_match_step {α β} [Iterator α Id β] [Finite α Id] [IteratorCollect α Id Id]
|
||||
[LawfulIteratorCollect α Id Id] {it : Iter (α := α) β} :
|
||||
it.ensureTermination.toArray = match it.step.val with
|
||||
| .yield it' out => #[out] ++ it'.toArray
|
||||
| .skip it' => it'.toArray
|
||||
| .done => #[] := by
|
||||
rw [toArray_ensureTermination, toArray_eq_match_step]
|
||||
|
||||
theorem Iter.toList_eq_match_step {α β} [Iterator α Id β] [Finite α Id] [IteratorCollect α Id Id]
|
||||
[LawfulIteratorCollect α Id Id] {it : Iter (α := α) β} :
|
||||
it.toList = match it.step.val with
|
||||
@@ -87,6 +135,14 @@ theorem Iter.toList_eq_match_step {α β} [Iterator α Id β] [Finite α Id] [It
|
||||
rw [← Iter.toList_toArray, Iter.toArray_eq_match_step]
|
||||
split <;> simp [Iter.toList_toArray]
|
||||
|
||||
theorem Iter.toList_ensureTermination_eq_match_step {α β} [Iterator α Id β] [Finite α Id] [IteratorCollect α Id Id]
|
||||
[LawfulIteratorCollect α Id Id] {it : Iter (α := α) β} :
|
||||
it.ensureTermination.toList = match it.step.val with
|
||||
| .yield it' out => out :: it'.toList
|
||||
| .skip it' => it'.toList
|
||||
| .done => [] := by
|
||||
rw [toList_ensureTermination, toList_eq_match_step]
|
||||
|
||||
theorem Iter.toListRev_eq_match_step {α β} [Iterator α Id β] [Finite α Id] {it : Iter (α := α) β} :
|
||||
it.toListRev = match it.step.val with
|
||||
| .yield it' out => it'.toListRev ++ [out]
|
||||
@@ -96,6 +152,13 @@ theorem Iter.toListRev_eq_match_step {α β} [Iterator α Id β] [Finite α Id]
|
||||
generalize it.toIterM.step.run = step
|
||||
cases step.inflate using PlausibleIterStep.casesOn <;> simp
|
||||
|
||||
theorem Iter.toListRev_ensureTermination_eq_match_step {α β} [Iterator α Id β] [Finite α Id] {it : Iter (α := α) β} :
|
||||
it.ensureTermination.toListRev = match it.step.val with
|
||||
| .yield it' out => it'.toListRev ++ [out]
|
||||
| .skip it' => it'.toListRev
|
||||
| .done => [] := by
|
||||
rw [toListRev_ensureTermination_eq_toListRev, toListRev_eq_match_step]
|
||||
|
||||
theorem Iter.getElem?_toList_eq_atIdxSlow? {α β}
|
||||
[Iterator α Id β] [Finite α Id] [IteratorCollect α Id Id] [LawfulIteratorCollect α Id Id]
|
||||
{it : Iter (α := α) β} {k : Nat} :
|
||||
@@ -156,4 +219,4 @@ theorem Iter.isPlausibleIndirectOutput_of_mem_toArray
|
||||
rw [← Array.mem_toList_iff] at h
|
||||
simpa [toList_toArray] using h
|
||||
|
||||
end Std.Iterators
|
||||
end Std
|
||||
|
||||
@@ -15,7 +15,8 @@ import Init.Data.Array.Monadic
|
||||
|
||||
public section
|
||||
|
||||
namespace Std.Iterators
|
||||
namespace Std
|
||||
open Std.Iterators
|
||||
|
||||
theorem Iter.forIn'_eq {α β : Type w} [Iterator α Id β] [Finite α Id]
|
||||
{m : Type x → Type x'} [Monad m] [LawfulMonad m] [IteratorLoop α Id m] [hl : LawfulIteratorLoop α Id m]
|
||||
@@ -23,22 +24,22 @@ theorem Iter.forIn'_eq {α β : Type w} [Iterator α Id β] [Finite α Id]
|
||||
{f : (b : β) → it.IsPlausibleIndirectOutput b → γ → m (ForInStep γ)} :
|
||||
letI : ForIn' m (Iter (α := α) β) β _ := Iter.instForIn'
|
||||
ForIn'.forIn' it init f =
|
||||
IterM.DefaultConsumers.forIn' (fun _ _ f x => f x.run) γ (fun _ _ _ => True)
|
||||
IteratorLoop.wellFounded_of_finite it.toIterM init _ (fun _ => id)
|
||||
(fun out h acc => (⟨·, .intro⟩) <$>
|
||||
f out (Iter.isPlausibleIndirectOutput_iff_isPlausibleIndirectOutput_toIterM.mpr h) acc) := by
|
||||
simp [instForIn', ForIn'.forIn', IteratorLoop.finiteForIn', hl.lawful (fun γ δ f x => f x.run),
|
||||
IteratorLoop.defaultImplementation]
|
||||
IterM.DefaultConsumers.forIn' (n := m) (fun _ _ f x => f x.run) γ (fun _ _ _ => True)
|
||||
it.toIterM init _ (fun _ => id)
|
||||
(fun out h acc => return ⟨← f out (Iter.isPlausibleIndirectOutput_iff_isPlausibleIndirectOutput_toIterM.mpr h) acc, trivial⟩) := by
|
||||
simp only [instForIn', ForIn'.forIn', IteratorLoop.finiteForIn']
|
||||
have : ∀ a b c, f a b c = (Subtype.val <$> (⟨·, trivial⟩) <$> f a b c) := by simp
|
||||
simp +singlePass only [this]
|
||||
rw [hl.lawful (fun _ _ f x => f x.run) (wf := IteratorLoop.wellFounded_of_finite)]
|
||||
simp [IteratorLoop.defaultImplementation]
|
||||
|
||||
theorem Iter.forIn_eq {α β : Type w} [Iterator α Id β] [Finite α Id]
|
||||
{m : Type x → Type x'} [Monad m] [LawfulMonad m] [IteratorLoop α Id m]
|
||||
[hl : LawfulIteratorLoop α Id m] {γ : Type x} {it : Iter (α := α) β} {init : γ}
|
||||
{f : (b : β) → γ → m (ForInStep γ)} :
|
||||
ForIn.forIn it init f =
|
||||
IterM.DefaultConsumers.forIn' (fun _ _ f c => f c.run) γ (fun _ _ _ => True)
|
||||
IteratorLoop.wellFounded_of_finite it.toIterM init _ (fun _ => id)
|
||||
(fun out _ acc => (⟨·, .intro⟩) <$>
|
||||
f out acc) := by
|
||||
IterM.DefaultConsumers.forIn' (n := m) (fun _ _ f c => f c.run) γ (fun _ _ _ => True)
|
||||
it.toIterM init _ (fun _ => id) (fun out _ acc => return ⟨← f out acc, trivial⟩) := by
|
||||
simp [ForIn.forIn, forIn'_eq, -forIn'_eq_forIn]
|
||||
|
||||
@[congr] theorem Iter.forIn'_congr {α β : Type w} {m : Type w → Type w'} [Monad m]
|
||||
@@ -106,20 +107,24 @@ theorem Iter.forIn'_eq_match_step {α β : Type w} [Iterator α Id β]
|
||||
fun out h' acc => f out (.indirect ⟨_, rfl, h⟩ h') acc
|
||||
| .done _ => return init) := by
|
||||
simp only [forIn'_eq]
|
||||
rw [IterM.DefaultConsumers.forIn'_eq_match_step]
|
||||
simp only [bind_map_left, Iter.step]
|
||||
rw [IterM.DefaultConsumers.forIn'_eq_match_step (fun _ _ _ => True)
|
||||
IteratorLoop.wellFounded_of_finite]
|
||||
simp only [Iter.step]
|
||||
cases it.toIterM.step.run.inflate using PlausibleIterStep.casesOn
|
||||
· simp only [IterM.Step.toPure_yield, PlausibleIterStep.yield, toIter_toIterM, toIterM_toIter]
|
||||
· simp only [IterM.Step.toPure_yield, PlausibleIterStep.yield, toIter_toIterM, toIterM_toIter,
|
||||
bind_assoc]
|
||||
apply bind_congr
|
||||
intro forInStep
|
||||
cases forInStep
|
||||
· simp
|
||||
· simp only
|
||||
apply IterM.DefaultConsumers.forIn'_eq_forIn'
|
||||
intros; congr
|
||||
· simp only [pure_bind]
|
||||
apply IterM.DefaultConsumers.forIn'_eq_forIn' (fun _ _ _ => True)
|
||||
IteratorLoop.wellFounded_of_finite
|
||||
· simp
|
||||
· simp only
|
||||
apply IterM.DefaultConsumers.forIn'_eq_forIn'
|
||||
intros; congr
|
||||
apply IterM.DefaultConsumers.forIn'_eq_forIn' (fun _ _ _ => True)
|
||||
IteratorLoop.wellFounded_of_finite
|
||||
· simp
|
||||
· simp
|
||||
|
||||
theorem Iter.forIn_eq_match_step {α β : Type w} [Iterator α Id β]
|
||||
@@ -934,4 +939,4 @@ theorem Iter.findM?_pure {α β : Type w} {m : Type w → Type w'} [Monad m]
|
||||
· simp [ihs ‹_›]
|
||||
· simp
|
||||
|
||||
end Std.Iterators
|
||||
end Std
|
||||
|
||||
@@ -10,29 +10,49 @@ public import Init.Data.Array.Lemmas
|
||||
public import Init.Data.Iterators.Lemmas.Monadic.Basic
|
||||
public import Init.Data.Iterators.Consumers.Monadic.Collect
|
||||
import all Init.Data.Iterators.Consumers.Monadic.Collect
|
||||
import all Init.Data.Iterators.Consumers.Monadic.Total
|
||||
import all Init.WFExtrinsicFix
|
||||
|
||||
public section
|
||||
|
||||
namespace Std.Iterators
|
||||
namespace Std
|
||||
open Std.Iterators Std.Internal
|
||||
|
||||
variable {α β γ : Type w} {m : Type w → Type w'} {n : Type w → Type w''}
|
||||
{lift : ⦃δ : Type w⦄ → m δ → n δ} {f : β → n γ} {it : IterM (α := α) m β}
|
||||
|
||||
theorem IterM.DefaultConsumers.toArrayMapped.go.aux₁ [Monad n] [LawfulMonad n] [Iterator α m β]
|
||||
[Finite α m] {b : γ} {bs : Array γ} :
|
||||
private theorem IterM.DefaultConsumers.toArrayMapped.go_eq [Monad n]
|
||||
[Iterator α m β] [LawfulMonad n] [Finite α m] {acc : Array γ} :
|
||||
letI : MonadLift m n := ⟨lift (δ := _)⟩
|
||||
go lift f it acc (m := m) = (do
|
||||
match (← it.step).inflate.val with
|
||||
| .yield it' out => go lift f it' (acc.push (← f out))
|
||||
| .skip it' => go lift f it' acc
|
||||
| .done => return acc) := by
|
||||
letI : MonadLift m n := ⟨lift (δ := _)⟩
|
||||
rw [toArrayMapped.go, WellFounded.extrinsicFix₂_eq_apply]
|
||||
· simp only
|
||||
apply bind_congr; intro step
|
||||
cases step.inflate using PlausibleIterStep.casesOn
|
||||
· apply bind_congr; intro fx
|
||||
simp [go]
|
||||
· simp [go]
|
||||
· simp
|
||||
· simp only [show (IterM.finitelyManySteps! = IterM.finitelyManySteps) by rfl]
|
||||
apply InvImage.wf
|
||||
exact WellFoundedRelation.wf
|
||||
|
||||
private theorem IterM.DefaultConsumers.toArrayMapped.go.aux₁ [Monad n] [LawfulMonad n]
|
||||
[Iterator α m β] [Finite α m] {b : γ} {bs : Array γ} :
|
||||
IterM.DefaultConsumers.toArrayMapped.go lift f it (#[b] ++ bs) (m := m) =
|
||||
(#[b] ++ ·) <$> IterM.DefaultConsumers.toArrayMapped.go lift f it bs (m := m) := by
|
||||
induction it, bs using IterM.DefaultConsumers.toArrayMapped.go.induct with | _ it bs ih₁ ih₂
|
||||
rw [go, map_eq_pure_bind, go, bind_assoc]
|
||||
apply bind_congr
|
||||
intro step
|
||||
split
|
||||
· simp [ih₁ _ _ ‹_›]
|
||||
· simp [ih₂ _ ‹_›]
|
||||
· simp
|
||||
induction it using IterM.inductSteps generalizing bs with | step it ihy ihs
|
||||
rw [go_eq, map_eq_pure_bind, go_eq, bind_assoc]
|
||||
apply bind_congr; intro step
|
||||
cases step.inflate using PlausibleIterStep.casesOn <;> simp (discharger := assumption) [ihy, ihs]
|
||||
|
||||
theorem IterM.DefaultConsumers.toArrayMapped.go.aux₂ [Monad n] [LawfulMonad n] [Iterator α m β]
|
||||
[Finite α m] {acc : Array γ} :
|
||||
private theorem IterM.DefaultConsumers.toArrayMapped.go.aux₂ [Monad n] [LawfulMonad n]
|
||||
[Iterator α m β] [Finite α m] {acc : Array γ} :
|
||||
IterM.DefaultConsumers.toArrayMapped.go lift f it acc (m := m) =
|
||||
(acc ++ ·) <$> IterM.DefaultConsumers.toArrayMapped lift f it (m := m) := by
|
||||
rw [← Array.toArray_toList (xs := acc)]
|
||||
@@ -51,12 +71,18 @@ theorem IterM.DefaultConsumers.toArrayMapped_eq_match_step [Monad n] [LawfulMona
|
||||
return #[← f out] ++ (← IterM.DefaultConsumers.toArrayMapped lift f it' (m := m))
|
||||
| .skip it' => IterM.DefaultConsumers.toArrayMapped lift f it' (m := m)
|
||||
| .done => return #[]) := by
|
||||
rw [IterM.DefaultConsumers.toArrayMapped, IterM.DefaultConsumers.toArrayMapped.go]
|
||||
rw [IterM.DefaultConsumers.toArrayMapped, IterM.DefaultConsumers.toArrayMapped.go_eq]
|
||||
apply bind_congr
|
||||
intro step
|
||||
cases step.inflate using PlausibleIterStep.casesOn <;>
|
||||
simp [IterM.DefaultConsumers.toArrayMapped.go.aux₂]
|
||||
|
||||
@[simp]
|
||||
theorem IterM.toArray_ensureTermination [Monad m] [Iterator α m β] [Finite α m]
|
||||
[IteratorCollect α m m] {it : IterM (α := α) m β} :
|
||||
it.ensureTermination.toArray = it.toArray :=
|
||||
(rfl)
|
||||
|
||||
theorem IterM.toArray_eq_match_step [Monad m] [LawfulMonad m] [Iterator α m β] [Finite α m]
|
||||
[IteratorCollect α m m] [LawfulIteratorCollect α m m] :
|
||||
it.toArray = (do
|
||||
@@ -68,18 +94,43 @@ theorem IterM.toArray_eq_match_step [Monad m] [LawfulMonad m] [Iterator α m β]
|
||||
rw [IterM.DefaultConsumers.toArrayMapped_eq_match_step]
|
||||
simp [bind_pure_comp, pure_bind]
|
||||
|
||||
theorem IterM.toArray_ensureTermination_eq_match_step [Monad m] [LawfulMonad m] [Iterator α m β]
|
||||
[Finite α m] [IteratorCollect α m m] [LawfulIteratorCollect α m m] :
|
||||
it.ensureTermination.toArray = (do
|
||||
match (← it.step).inflate.val with
|
||||
| .yield it' out => return #[out] ++ (← it'.toArray)
|
||||
| .skip it' => it'.toArray
|
||||
| .done => return #[]) := by
|
||||
rw [toArray_ensureTermination, toArray_eq_match_step]
|
||||
|
||||
@[simp]
|
||||
theorem IterM.toList_ensureTermination [Monad m] [Iterator α m β] [Finite α m]
|
||||
[IteratorCollect α m m] {it : IterM (α := α) m β} :
|
||||
it.ensureTermination.toList = it.toList :=
|
||||
(rfl)
|
||||
|
||||
@[simp]
|
||||
theorem IterM.toList_toArray [Monad m] [Iterator α m β] [Finite α m] [IteratorCollect α m m]
|
||||
{it : IterM (α := α) m β} :
|
||||
Array.toList <$> it.toArray = it.toList := by
|
||||
simp [IterM.toList]
|
||||
|
||||
theorem IterM.toList_toArray_ensureTermination [Monad m] [Iterator α m β] [Finite α m]
|
||||
[IteratorCollect α m m] {it : IterM (α := α) m β} :
|
||||
Array.toList <$> it.ensureTermination.toArray = it.toList := by
|
||||
simp
|
||||
|
||||
@[simp]
|
||||
theorem IterM.toArray_toList [Monad m] [LawfulMonad m] [Iterator α m β] [Finite α m]
|
||||
[IteratorCollect α m m] {it : IterM (α := α) m β} :
|
||||
List.toArray <$> it.toList = it.toArray := by
|
||||
simp [IterM.toList, -toList_toArray]
|
||||
|
||||
theorem IterM.toArray_toList_ensureTermination [Monad m] [LawfulMonad m] [Iterator α m β] [Finite α m]
|
||||
[IteratorCollect α m m] {it : IterM (α := α) m β} :
|
||||
List.toArray <$> it.ensureTermination.toList = it.toArray := by
|
||||
rw [toList_ensureTermination, toArray_toList]
|
||||
|
||||
theorem IterM.toList_eq_match_step [Monad m] [LawfulMonad m] [Iterator α m β] [Finite α m]
|
||||
[IteratorCollect α m m] [LawfulIteratorCollect α m m] {it : IterM (α := α) m β} :
|
||||
it.toList = (do
|
||||
@@ -93,17 +144,49 @@ theorem IterM.toList_eq_match_step [Monad m] [LawfulMonad m] [Iterator α m β]
|
||||
intro step
|
||||
split <;> simp
|
||||
|
||||
theorem IterM.toListRev.go.aux₁ [Monad m] [LawfulMonad m] [Iterator α m β] [Finite α m]
|
||||
theorem IterM.toList_ensureTermination_eq_match_step [Monad m] [LawfulMonad m] [Iterator α m β]
|
||||
[Finite α m] [IteratorCollect α m m] [LawfulIteratorCollect α m m] {it : IterM (α := α) m β} :
|
||||
it.ensureTermination.toList = (do
|
||||
match (← it.step).inflate.val with
|
||||
| .yield it' out => return out :: (← it'.toList)
|
||||
| .skip it' => it'.toList
|
||||
| .done => return []) := by
|
||||
rw [toList_ensureTermination, toList_eq_match_step]
|
||||
|
||||
@[simp]
|
||||
theorem IterM.toListRev_ensureTermination_eq_toListRev [Monad m] [Iterator α m β] [Finite α m]
|
||||
{it : IterM (α := α) m β} :
|
||||
it.ensureTermination.toListRev = it.toListRev :=
|
||||
(rfl)
|
||||
|
||||
private theorem IterM.toListRev.go_eq [Monad m] [LawfulMonad m] [Iterator α m β] [Finite α m]
|
||||
{it : IterM (α := α) m β} {bs : List β} :
|
||||
go it bs = (do
|
||||
match (← it.step).inflate.val with
|
||||
| .yield it' out => go it' (out :: bs)
|
||||
| .skip it' => go it' bs
|
||||
| .done => return bs) := by
|
||||
rw [go, WellFounded.extrinsicFix₂_eq_apply]
|
||||
· apply bind_congr; intro step
|
||||
cases step.inflate using PlausibleIterStep.casesOn <;> simp [go]
|
||||
· simp only [show (IterM.finitelyManySteps! = IterM.finitelyManySteps) by rfl]
|
||||
apply InvImage.wf
|
||||
exact WellFoundedRelation.wf
|
||||
|
||||
private theorem IterM.toListRev.go.aux₁ [Monad m] [LawfulMonad m] [Iterator α m β] [Finite α m]
|
||||
{it : IterM (α := α) m β} {b : β} {bs : List β} :
|
||||
IterM.toListRev.go it (bs ++ [b]) = (· ++ [b]) <$> IterM.toListRev.go it bs:= by
|
||||
induction it, bs using IterM.toListRev.go.induct with | _ it bs ih₁ ih₂
|
||||
rw [go, go, map_eq_pure_bind, bind_assoc]
|
||||
induction it using IterM.inductSteps generalizing bs with | step it ihy ihs
|
||||
rw [go_eq, go_eq, map_eq_pure_bind, bind_assoc]
|
||||
apply bind_congr
|
||||
intro step
|
||||
simp only [List.cons_append] at ih₁
|
||||
split <;> simp [*]
|
||||
cases step.inflate using PlausibleIterStep.casesOn
|
||||
· simpa using ihy ‹_› (bs := _ :: bs)
|
||||
· simpa using ihs ‹_›
|
||||
· simp
|
||||
|
||||
theorem IterM.toListRev.go.aux₂ [Monad m] [LawfulMonad m] [Iterator α m β] [Finite α m]
|
||||
|
||||
private theorem IterM.toListRev.go.aux₂ [Monad m] [LawfulMonad m] [Iterator α m β] [Finite α m]
|
||||
{it : IterM (α := α) m β} {acc : List β} :
|
||||
IterM.toListRev.go it acc = (· ++ acc) <$> it.toListRev := by
|
||||
rw [← List.reverse_reverse (as := acc)]
|
||||
@@ -120,11 +203,21 @@ theorem IterM.toListRev_eq_match_step [Monad m] [LawfulMonad m] [Iterator α m
|
||||
| .skip it' => it'.toListRev
|
||||
| .done => return []) := by
|
||||
simp [IterM.toListRev]
|
||||
rw [toListRev.go]
|
||||
rw [toListRev.go_eq]
|
||||
apply bind_congr
|
||||
intro step
|
||||
cases step.inflate using PlausibleIterStep.casesOn <;> simp [IterM.toListRev.go.aux₂]
|
||||
|
||||
theorem IterM.toListRev_ensureTermination_eq_match_step [Monad m] [LawfulMonad m] [Iterator α m β]
|
||||
[Finite α m] {it : IterM (α := α) m β} :
|
||||
it.ensureTermination.toListRev = (do
|
||||
match (← it.step).inflate.val with
|
||||
| .yield it' out => return (← it'.toListRev) ++ [out]
|
||||
| .skip it' => it'.toListRev
|
||||
| .done => return []) := by
|
||||
rw [toListRev_ensureTermination_eq_toListRev, toListRev_eq_match_step]
|
||||
|
||||
@[simp]
|
||||
theorem IterM.reverse_toListRev [Monad m] [LawfulMonad m] [Iterator α m β] [Finite α m]
|
||||
[IteratorCollect α m m] [LawfulIteratorCollect α m m]
|
||||
{it : IterM (α := α) m β} :
|
||||
@@ -137,19 +230,31 @@ theorem IterM.reverse_toListRev [Monad m] [LawfulMonad m] [Iterator α m β] [Fi
|
||||
intro step
|
||||
cases step.inflate using PlausibleIterStep.casesOn <;> simp (discharger := assumption) [ihy, ihs]
|
||||
|
||||
@[simp]
|
||||
theorem IterM.reverse_toListRev_ensureTermination [Monad m] [LawfulMonad m] [Iterator α m β]
|
||||
[Finite α m] [IteratorCollect α m m] [LawfulIteratorCollect α m m]
|
||||
{it : IterM (α := α) m β} :
|
||||
List.reverse <$> it.ensureTermination.toListRev = it.toList := by
|
||||
rw [toListRev_ensureTermination_eq_toListRev, reverse_toListRev]
|
||||
|
||||
theorem IterM.toListRev_eq [Monad m] [LawfulMonad m] [Iterator α m β] [Finite α m]
|
||||
[IteratorCollect α m m] [LawfulIteratorCollect α m m]
|
||||
{it : IterM (α := α) m β} :
|
||||
it.toListRev = List.reverse <$> it.toList := by
|
||||
rw [← IterM.reverse_toListRev]
|
||||
simp
|
||||
simp [← IterM.reverse_toListRev]
|
||||
|
||||
theorem IterM.toListRev_ensureTermination [Monad m] [LawfulMonad m] [Iterator α m β] [Finite α m]
|
||||
[IteratorCollect α m m] [LawfulIteratorCollect α m m]
|
||||
{it : IterM (α := α) m β} :
|
||||
it.ensureTermination.toListRev = List.reverse <$> it.toList := by
|
||||
simp [← IterM.reverse_toListRev]
|
||||
|
||||
theorem LawfulIteratorCollect.toArray_eq {α β : Type w} {m : Type w → Type w'}
|
||||
[Monad m] [Iterator α m β] [Finite α m] [IteratorCollect α m m]
|
||||
[hl : LawfulIteratorCollect α m m]
|
||||
{it : IterM (α := α) m β} :
|
||||
it.toArray = (letI : IteratorCollect α m m := .defaultImplementation; it.toArray) := by
|
||||
simp only [IterM.toArray, toArrayMapped_eq]
|
||||
simp [IterM.toArray, toArrayMapped_eq, IteratorCollect.defaultImplementation]
|
||||
|
||||
theorem LawfulIteratorCollect.toList_eq {α β : Type w} {m : Type w → Type w'}
|
||||
[Monad m] [Iterator α m β] [Finite α m] [IteratorCollect α m m]
|
||||
@@ -158,4 +263,4 @@ theorem LawfulIteratorCollect.toList_eq {α β : Type w} {m : Type w → Type w'
|
||||
it.toList = (letI : IteratorCollect α m m := .defaultImplementation; it.toList) := by
|
||||
simp [IterM.toList, toArray_eq, -IterM.toList_toArray]
|
||||
|
||||
end Std.Iterators
|
||||
end Std
|
||||
|
||||
@@ -12,32 +12,79 @@ import all Init.Data.Iterators.Consumers.Monadic.Loop
|
||||
|
||||
public section
|
||||
|
||||
namespace Std.Iterators
|
||||
namespace Std
|
||||
open Std.Iterators
|
||||
|
||||
theorem IterM.DefaultConsumers.forIn'_eq_match_step {α β : Type w} {m : Type w → Type w'}
|
||||
[Iterator α m β]
|
||||
{n : Type x → Type x'} [Monad n]
|
||||
[Iterator α m β] {n : Type x → Type x'} [Monad n] [LawfulMonad n]
|
||||
{lift : ∀ γ δ, (γ → n δ) → m γ → n δ} {γ : Type x}
|
||||
{plausible_forInStep : β → γ → ForInStep γ → Prop}
|
||||
{wf : IteratorLoop.WellFounded α m plausible_forInStep}
|
||||
{it : IterM (α := α) m β} {init : γ}
|
||||
{P hP} {f : (b : β) → P b → (c : γ) → n (Subtype (plausible_forInStep b c))} :
|
||||
IterM.DefaultConsumers.forIn' lift γ plausible_forInStep wf it init P hP f =
|
||||
{P hP}
|
||||
(PlausibleForInStep : β → γ → ForInStep γ → Prop)
|
||||
{f : (b : β) → P b → (c : γ) → n (Subtype (PlausibleForInStep b c))}
|
||||
(wf : IteratorLoop.WellFounded α m PlausibleForInStep) :
|
||||
IterM.DefaultConsumers.forIn' lift γ PlausibleForInStep it init P hP f =
|
||||
(lift _ _ · it.step) (fun s =>
|
||||
match s.inflate with
|
||||
| .yield it' out h => do
|
||||
match ← f out (hP _ <| .direct ⟨_, h⟩) init with
|
||||
| ⟨.yield c, _⟩ =>
|
||||
IterM.DefaultConsumers.forIn' lift _ plausible_forInStep wf it' c P
|
||||
IterM.DefaultConsumers.forIn' lift _ PlausibleForInStep it' c P
|
||||
(fun _ h' => hP _ <| .indirect ⟨_, rfl, h⟩ h') f
|
||||
| ⟨.done c, _⟩ => return c
|
||||
| .skip it' h =>
|
||||
IterM.DefaultConsumers.forIn' lift _ plausible_forInStep wf it' init P
|
||||
IterM.DefaultConsumers.forIn' lift _ PlausibleForInStep it' init P
|
||||
(fun _ h' => hP _ <| .indirect ⟨_, rfl, h⟩ h') f
|
||||
| .done _ => return init) := by
|
||||
rw [forIn']
|
||||
congr; ext step
|
||||
cases step.inflate using PlausibleIterStep.casesOn <;> rfl
|
||||
haveI : Nonempty γ := ⟨init⟩
|
||||
rw [forIn', WellFounded.extrinsicFix₃_eq_apply]
|
||||
· congr; ext step
|
||||
cases step.inflate using PlausibleIterStep.casesOn
|
||||
· simp only
|
||||
apply bind_congr; intro step
|
||||
split <;> simp [forIn']
|
||||
· simp [forIn']
|
||||
· simp
|
||||
· apply InvImage.wf
|
||||
exact wf
|
||||
|
||||
theorem IterM.DefaultConsumers.forIn'_eq_wf {m : Type w → Type w'} {α : Type w} {β : Type w}
|
||||
[Iterator α m β]
|
||||
{n : Type x → Type x'} [Monad n] [LawfulMonad n]
|
||||
{lift : ∀ γ δ, (γ → n δ) → m γ → n δ} {γ : Type x}
|
||||
(Pl : β → γ → ForInStep γ → Prop)
|
||||
(wf : IteratorLoop.WellFounded α m Pl)
|
||||
{it : IterM (α := α) m β} {init : γ}
|
||||
{P : β → Prop} {hP : ∀ b, it.IsPlausibleIndirectOutput b → P b}
|
||||
(f : (b : β) → P b → (c : γ) → n (Subtype (Pl b c))) :
|
||||
forIn' lift γ Pl it init P hP f =
|
||||
forIn'.wf lift γ Pl wf it init P hP f := by
|
||||
haveI : Nonempty γ := ⟨init⟩
|
||||
rw [forIn', WellFounded.extrinsicFix₃_eq_fix]; rotate_left
|
||||
· apply InvImage.wf
|
||||
exact wf
|
||||
· fun_induction forIn'.wf lift γ Pl wf it init P hP f
|
||||
rename_i ihy ihs
|
||||
rw [WellFounded.fix_eq]
|
||||
congr 1; ext step
|
||||
cases step.inflate using PlausibleIterStep.casesOn
|
||||
· apply bind_congr; intro forInStep
|
||||
match forInStep with
|
||||
| ⟨.yield c, h⟩ => simp (discharger := assumption) [ihy]
|
||||
| ⟨.done c, h⟩ => simp
|
||||
· simp (discharger := assumption) [ihs]
|
||||
· simp
|
||||
|
||||
theorem IterM.DefaultConsumers.forIn'_eq_wf_of_finite {m : Type w → Type w'} {α : Type w}
|
||||
{β : Type w} [Iterator α m β] [Finite α m]
|
||||
{n : Type x → Type x'} [Monad n] [LawfulMonad n]
|
||||
{lift : ∀ γ δ, (γ → n δ) → m γ → n δ} {γ : Type x}
|
||||
{it : IterM (α := α) m β} {init : γ}
|
||||
{P : β → Prop} {hP : ∀ b, it.IsPlausibleIndirectOutput b → P b}
|
||||
(f : (b : β) → P b → (c : γ) → n (Subtype (fun _ => True))) :
|
||||
forIn' lift γ (fun _ _ _ => True) it init P hP f =
|
||||
forIn'.wf lift γ (fun _ _ _ => True) IteratorLoop.wellFounded_of_finite it init P hP f := by
|
||||
apply forIn'_eq_wf
|
||||
|
||||
theorem IterM.forIn'_eq {α β : Type w} {m : Type w → Type w'} [Iterator α m β] [Finite α m]
|
||||
{n : Type w → Type w''} [Monad m] [Monad n] [LawfulMonad n] [IteratorLoop α m n]
|
||||
@@ -45,11 +92,12 @@ theorem IterM.forIn'_eq {α β : Type w} {m : Type w → Type w'} [Iterator α m
|
||||
[MonadLiftT m n] [LawfulMonadLiftT m n] {γ : Type w} {it : IterM (α := α) m β} {init : γ}
|
||||
{f : (b : β) → it.IsPlausibleIndirectOutput b → γ → n (ForInStep γ)} :
|
||||
letI : ForIn' n (IterM (α := α) m β) β _ := IterM.instForIn'
|
||||
ForIn'.forIn' it init f = IterM.DefaultConsumers.forIn' (n := n)
|
||||
(fun _ _ f x => monadLift x >>= f) γ (fun _ _ _ => True)
|
||||
IteratorLoop.wellFounded_of_finite it init _ (fun _ => id) ((⟨·, .intro⟩) <$> f · · ·) := by
|
||||
simp [instForIn', ForIn'.forIn', IteratorLoop.finiteForIn',
|
||||
hl.lawful (fun _ _ f x => monadLift x >>= f), IteratorLoop.defaultImplementation]
|
||||
ForIn'.forIn' (α := β) (m := n) it init f = IterM.DefaultConsumers.forIn' (n := n)
|
||||
(fun _ _ f x => monadLift x >>= f) γ (fun _ _ _ => True) it init _ (fun _ => id) (return ⟨← f · · ·, trivial⟩) := by
|
||||
simp only [instForIn', ForIn'.forIn', IteratorLoop.finiteForIn']
|
||||
have : f = (Subtype.val <$> (⟨·, trivial⟩) <$> f · · ·) := by simp
|
||||
rw [this, hl.lawful (fun _ _ f x => monadLift x >>= f) (wf := IteratorLoop.wellFounded_of_finite)]
|
||||
simp [IteratorLoop.defaultImplementation]
|
||||
|
||||
theorem IterM.forIn_eq {α β : Type w} {m : Type w → Type w'} [Iterator α m β] [Finite α m]
|
||||
{n : Type w → Type w''} [Monad m] [Monad n] [LawfulMonad n] [IteratorLoop α m n]
|
||||
@@ -57,13 +105,13 @@ theorem IterM.forIn_eq {α β : Type w} {m : Type w → Type w'} [Iterator α m
|
||||
[MonadLiftT m n] [LawfulMonadLiftT m n] {γ : Type w} {it : IterM (α := α) m β} {init : γ}
|
||||
{f : β → γ → n (ForInStep γ)} :
|
||||
ForIn.forIn it init f = IterM.DefaultConsumers.forIn' (n := n)
|
||||
(fun _ _ f x => monadLift x >>= f) γ (fun _ _ _ => True)
|
||||
IteratorLoop.wellFounded_of_finite it init _ (fun _ => id) (fun out _ acc => (⟨·, .intro⟩) <$> f out acc) := by
|
||||
(fun _ _ f x => monadLift x >>= f) γ (fun _ _ _ => True) it init _ (fun _ => id)
|
||||
(fun out _ acc => return ⟨← f out acc, trivial⟩) := by
|
||||
simp only [ForIn.forIn, forIn'_eq]
|
||||
|
||||
@[congr] theorem IterM.forIn'_congr {α β : Type w} {m : Type w → Type w'}
|
||||
{n : Type w → Type w''} [Monad n] [Monad m]
|
||||
[Iterator α m β] [Finite α m] [IteratorLoop α m n] [MonadLiftT m n]
|
||||
[Iterator α m β] [IteratorLoop α m n] [MonadLiftT m n]
|
||||
{ita itb : IterM (α := α) m β} (w : ita = itb)
|
||||
{b b' : γ} (hb : b = b')
|
||||
{f : (a' : β) → _ → γ → n (ForInStep γ)}
|
||||
@@ -78,7 +126,7 @@ theorem IterM.forIn_eq {α β : Type w} {m : Type w → Type w'} [Iterator α m
|
||||
|
||||
@[congr] theorem IterM.forIn_congr {α β : Type w} {m : Type w → Type w'}
|
||||
{n : Type w → Type w''} [Monad n] [Monad m]
|
||||
[Iterator α m β] [Finite α m] [IteratorLoop α m n] [MonadLiftT m n]
|
||||
[Iterator α m β] [IteratorLoop α m n] [MonadLiftT m n]
|
||||
{ita itb : IterM (α := α) m β} (w : ita = itb)
|
||||
{b b' : γ} (hb : b = b')
|
||||
{f : (a' : β) → γ → n (ForInStep γ)}
|
||||
@@ -89,6 +137,36 @@ theorem IterM.forIn_eq {α β : Type w} {m : Type w → Type w'} [Iterator α m
|
||||
simp only [← funext_iff] at h
|
||||
rw [← h]
|
||||
|
||||
theorem IterM.DefaultConsumers.forIn'_eq_forIn' {m : Type w → Type w'} {α : Type w} {β : Type w}
|
||||
[Iterator α m β]
|
||||
{n : Type x → Type x'} [Monad n] [LawfulMonad n]
|
||||
{lift : ∀ γ δ, (γ → n δ) → m γ → n δ} {γ : Type x}
|
||||
{it : IterM (α := α) m β} {init : γ}
|
||||
{P : β → Prop} {hP : ∀ b, it.IsPlausibleIndirectOutput b → P b}
|
||||
{Q : β → Prop} {hQ : ∀ b, it.IsPlausibleIndirectOutput b → Q b}
|
||||
(Pl : β → γ → ForInStep γ → Prop)
|
||||
{f : (b : β) → P b → (c : γ) → n (Subtype (Pl b c))}
|
||||
{g : (b : β) → Q b → (c : γ) → n (Subtype (Pl b c))}
|
||||
(wf : IteratorLoop.WellFounded α m Pl)
|
||||
(hfg : ∀ b c, (hPb : P b) → (hQb : Q b) → f b hPb c = g b hQb c) :
|
||||
IterM.DefaultConsumers.forIn' lift γ Pl it init P hP f =
|
||||
IterM.DefaultConsumers.forIn' lift γ Pl it init Q hQ g := by
|
||||
rw [forIn'_eq_match_step Pl wf, forIn'_eq_match_step Pl wf]
|
||||
congr; ext step
|
||||
split
|
||||
· congr
|
||||
· apply hfg
|
||||
· ext forInStep
|
||||
match forInStep with
|
||||
| ⟨.yield _, h⟩ => apply IterM.DefaultConsumers.forIn'_eq_forIn' <;> assumption
|
||||
| ⟨.done _, h⟩ => rfl
|
||||
· apply IterM.DefaultConsumers.forIn'_eq_forIn' <;> assumption
|
||||
· rfl
|
||||
termination_by IteratorLoop.WithWF.mk it init (hwf := wf)
|
||||
decreasing_by
|
||||
· exact Or.inl ⟨_, ‹_›, ‹_›⟩
|
||||
· exact Or.inr ⟨‹_›, rfl⟩
|
||||
|
||||
theorem IterM.forIn'_eq_match_step {α β : Type w} {m : Type w → Type w'} [Iterator α m β]
|
||||
[Finite α m] {n : Type w → Type w''} [Monad m] [Monad n] [LawfulMonad n]
|
||||
[IteratorLoop α m n] [LawfulIteratorLoop α m n]
|
||||
@@ -108,21 +186,21 @@ theorem IterM.forIn'_eq_match_step {α β : Type w} {m : Type w → Type w'} [It
|
||||
fun out h' acc => f out (.indirect ⟨_, rfl, h⟩ h') acc
|
||||
| .done _ => return init) := by
|
||||
rw [IterM.forIn'_eq, DefaultConsumers.forIn'_eq_match_step]
|
||||
apply bind_congr
|
||||
intro step
|
||||
cases step.inflate using PlausibleIterStep.casesOn
|
||||
· simp only [map_eq_pure_bind, bind_assoc]
|
||||
apply bind_congr
|
||||
intro forInStep
|
||||
cases forInStep
|
||||
· apply bind_congr; intro step
|
||||
cases step.inflate using PlausibleIterStep.casesOn
|
||||
· simp only [bind_assoc]
|
||||
apply bind_congr
|
||||
intro forInStep
|
||||
cases forInStep
|
||||
· simp
|
||||
· simp only [forIn'_eq, pure_bind]
|
||||
exact DefaultConsumers.forIn'_eq_forIn' (α := α) (m := m) (n := n) _
|
||||
IteratorLoop.wellFounded_of_finite (by simp)
|
||||
· simp only [forIn'_eq]
|
||||
exact DefaultConsumers.forIn'_eq_forIn' (α := α) (m := m) (n := n) _
|
||||
IteratorLoop.wellFounded_of_finite (by simp)
|
||||
· simp
|
||||
· simp only [bind_pure_comp, pure_bind, forIn'_eq]
|
||||
apply DefaultConsumers.forIn'_eq_forIn'
|
||||
intros; congr
|
||||
· simp only [forIn'_eq]
|
||||
apply DefaultConsumers.forIn'_eq_forIn'
|
||||
intros; congr
|
||||
· simp
|
||||
· exact IteratorLoop.wellFounded_of_finite
|
||||
|
||||
theorem IterM.forIn_eq_match_step {α β : Type w} {m : Type w → Type w'} [Iterator α m β]
|
||||
[Finite α m] {n : Type w → Type w''} [Monad m] [Monad n] [LawfulMonad n]
|
||||
@@ -703,4 +781,4 @@ theorem IterM.findM?_pure {α β : Type w} {m : Type w → Type w'} [Monad m]
|
||||
· simp [ihs ‹_›]
|
||||
· simp
|
||||
|
||||
end Std.Iterators
|
||||
end Std
|
||||
|
||||
@@ -10,7 +10,8 @@ public import Init.Data.Iterators.Basic
|
||||
|
||||
public section
|
||||
|
||||
namespace Std.Iterators
|
||||
namespace Std
|
||||
open Std.Iterators
|
||||
|
||||
/--
|
||||
Induction principle for finite monadic iterators: One can define a function `f` that maps every
|
||||
@@ -46,4 +47,4 @@ def IterM.inductSkips {α m β} [Iterator α m β] [Productive α m]
|
||||
step it (fun {it'} _ => inductSkips motive step it')
|
||||
termination_by it.finitelyManySkips
|
||||
|
||||
end Std.Iterators
|
||||
end Std
|
||||
|
||||
@@ -19,34 +19,32 @@ This module provides lemmas about the interactions of `List.iter` with `Iter.ste
|
||||
collectors.
|
||||
-/
|
||||
|
||||
namespace Std.Iterators
|
||||
open Std Std.Iterators
|
||||
|
||||
variable {β : Type w}
|
||||
|
||||
@[simp]
|
||||
theorem _root_.List.step_iter_nil :
|
||||
theorem List.step_iter_nil :
|
||||
(([] : List β).iter).step = ⟨.done, rfl⟩ := by
|
||||
simp [Iter.step, IterM.step, Iterator.step, List.iter, List.iterM, toIterM]
|
||||
simp [Iter.step, IterM.step, Iterator.step, List.iter, List.iterM, IterM.mk]
|
||||
|
||||
@[simp]
|
||||
theorem _root_.List.step_iter_cons {x : β} {xs : List β} :
|
||||
theorem List.step_iter_cons {x : β} {xs : List β} :
|
||||
((x :: xs).iter).step = ⟨.yield xs.iter x, rfl⟩ := by
|
||||
simp [List.iter, List.iterM, toIterM, IterM.toIter, Iter.step, Iter.toIterM, IterM.step,
|
||||
simp [List.iter, List.iterM, IterM.mk, IterM.toIter, Iter.step, Iter.toIterM, IterM.step,
|
||||
Iterator.step]
|
||||
|
||||
@[simp]
|
||||
theorem _root_.List.toArray_iter {l : List β} :
|
||||
theorem List.toArray_iter {l : List β} :
|
||||
l.iter.toArray = l.toArray := by
|
||||
simp [List.iter, List.toArray_iterM, Iter.toArray_eq_toArray_toIterM]
|
||||
|
||||
@[simp]
|
||||
theorem _root_.List.toList_iter {l : List β} :
|
||||
theorem List.toList_iter {l : List β} :
|
||||
l.iter.toList = l := by
|
||||
simp [List.iter, List.toList_iterM]
|
||||
|
||||
@[simp]
|
||||
theorem _root_.List.toListRev_iter {l : List β} :
|
||||
theorem List.toListRev_iter {l : List β} :
|
||||
l.iter.toListRev = l.reverse := by
|
||||
simp [List.iter, Iter.toListRev_eq_toListRev_toIterM, List.toListRev_iterM]
|
||||
|
||||
end Std.Iterators
|
||||
|
||||
@@ -18,28 +18,27 @@ This module provides lemmas about the interactions of `List.iterM` with `IterM.s
|
||||
collectors.
|
||||
-/
|
||||
|
||||
namespace Std.Iterators
|
||||
open Std.Internal
|
||||
open Std Std.Internal Std.Iterators Std.Iterators.Types
|
||||
|
||||
variable {m : Type w → Type w'} {n : Type w → Type w''} [Monad m] {β : Type w}
|
||||
|
||||
@[simp]
|
||||
theorem _root_.List.step_iterM_nil :
|
||||
theorem List.step_iterM_nil :
|
||||
(([] : List β).iterM m).step = pure (.deflate ⟨.done, rfl⟩) := by
|
||||
simp only [IterM.step, Iterator.step]; rfl
|
||||
|
||||
@[simp]
|
||||
theorem _root_.List.step_iterM_cons {x : β} {xs : List β} :
|
||||
theorem List.step_iterM_cons {x : β} {xs : List β} :
|
||||
((x :: xs).iterM m).step = pure (.deflate ⟨.yield (xs.iterM m) x, rfl⟩) := by
|
||||
simp only [List.iterM, IterM.step, Iterator.step]; rfl
|
||||
|
||||
theorem _root_.List.step_iterM {l : List β} :
|
||||
theorem List.step_iterM {l : List β} :
|
||||
(l.iterM m).step = match l with
|
||||
| [] => pure (.deflate ⟨.done, rfl⟩)
|
||||
| x :: xs => pure (.deflate ⟨.yield (xs.iterM m) x, rfl⟩) := by
|
||||
cases l <;> simp [List.step_iterM_cons, List.step_iterM_nil]
|
||||
|
||||
theorem ListIterator.toArrayMapped_iterM [Monad n] [LawfulMonad n]
|
||||
theorem Std.Iterators.Types.ListIterator.toArrayMapped_iterM [Monad n] [LawfulMonad n]
|
||||
{β : Type w} {γ : Type w} {lift : ⦃δ : Type w⦄ → m δ → n δ}
|
||||
[LawfulMonadLiftFunction lift] {f : β → n γ} {l : List β} :
|
||||
IteratorCollect.toArrayMapped lift f (l.iterM m) (m := m) = List.toArray <$> l.mapM f := by
|
||||
@@ -53,19 +52,17 @@ theorem ListIterator.toArrayMapped_iterM [Monad n] [LawfulMonad n]
|
||||
simp [List.step_iterM_cons, List.mapM_cons, pure_bind, ih, LawfulMonadLiftFunction.lift_pure]
|
||||
|
||||
@[simp]
|
||||
theorem _root_.List.toArray_iterM [LawfulMonad m] {l : List β} :
|
||||
theorem List.toArray_iterM [LawfulMonad m] {l : List β} :
|
||||
(l.iterM m).toArray = pure l.toArray := by
|
||||
simp only [IterM.toArray, ListIterator.toArrayMapped_iterM]
|
||||
rw [List.mapM_pure, map_pure, List.map_id']
|
||||
|
||||
@[simp]
|
||||
theorem _root_.List.toList_iterM [LawfulMonad m] {l : List β} :
|
||||
theorem List.toList_iterM [LawfulMonad m] {l : List β} :
|
||||
(l.iterM m).toList = pure l := by
|
||||
rw [← IterM.toList_toArray, List.toArray_iterM, map_pure, List.toList_toArray]
|
||||
|
||||
@[simp]
|
||||
theorem _root_.List.toListRev_iterM [LawfulMonad m] {l : List β} :
|
||||
theorem List.toListRev_iterM [LawfulMonad m] {l : List β} :
|
||||
(l.iterM m).toListRev = pure l.reverse := by
|
||||
simp [IterM.toListRev_eq, List.toList_iterM]
|
||||
|
||||
end Std.Iterators
|
||||
|
||||
@@ -10,14 +10,14 @@ public import Init.Data.Iterators.Producers.Monadic.List
|
||||
|
||||
@[expose] public section
|
||||
|
||||
open Std Std.Iterators Std.Iterators.Types
|
||||
|
||||
/-!
|
||||
# List iterator
|
||||
|
||||
This module provides an iterator for lists that is accessible via `List.iter`.
|
||||
-/
|
||||
|
||||
namespace Std.Iterators
|
||||
|
||||
/--
|
||||
Returns a finite iterator for the given list.
|
||||
The iterator yields the elements of the list in order and then terminates.
|
||||
@@ -30,8 +30,6 @@ The monadic version of this iterator is `List.iterM`.
|
||||
* `Productive` instance: always
|
||||
-/
|
||||
@[always_inline, inline]
|
||||
def _root_.List.iter {α : Type w} (l : List α) :
|
||||
def List.iter {α : Type w} (l : List α) :
|
||||
Iter (α := ListIterator α) α :=
|
||||
((l.iterM Id).toIter : Iter α)
|
||||
|
||||
end Std.Iterators
|
||||
|
||||
@@ -17,9 +17,9 @@ public import Init.Data.Iterators.Internal.Termination
|
||||
This module provides an iterator for lists that is accessible via `List.iterM`.
|
||||
-/
|
||||
|
||||
namespace Std.Iterators
|
||||
namespace Std
|
||||
|
||||
variable {α : Type w} {m : Type w → Type w'}
|
||||
namespace Iterators.Types
|
||||
|
||||
/--
|
||||
The underlying state of a list iterator. Its contents are internal and should
|
||||
@@ -29,6 +29,12 @@ not be used by downstream users of the library.
|
||||
structure ListIterator (α : Type w) where
|
||||
list : List α
|
||||
|
||||
end Iterators.Types
|
||||
|
||||
open Std.Iterators Std.Iterators.Types
|
||||
|
||||
variable {α : Type w} {m : Type w → Type w'}
|
||||
|
||||
/--
|
||||
Returns a finite iterator for the given list.
|
||||
The iterator yields the elements of the list in order and then terminates.
|
||||
@@ -43,19 +49,21 @@ The non-monadic version of this iterator is `List.iter`.
|
||||
@[always_inline, inline]
|
||||
def _root_.List.iterM {α : Type w} (l : List α) (m : Type w → Type w') [Pure m] :
|
||||
IterM (α := ListIterator α) m α :=
|
||||
toIterM { list := l } m α
|
||||
.mk { list := l } m α
|
||||
|
||||
namespace Iterators.Types
|
||||
|
||||
@[always_inline, inline]
|
||||
instance {α : Type w} [Pure m] : Iterator (ListIterator α) m α where
|
||||
instance ListIterator.instIterator {α : Type w} [Pure m] : Iterator (ListIterator α) m α where
|
||||
IsPlausibleStep it
|
||||
| .yield it' out => it.internalState.list = out :: it'.internalState.list
|
||||
| .skip _ => False
|
||||
| .done => it.internalState.list = []
|
||||
step it := pure (match it with
|
||||
| ⟨⟨[]⟩⟩ => .deflate ⟨.done, rfl⟩
|
||||
| ⟨⟨x :: xs⟩⟩ => .deflate ⟨.yield (toIterM ⟨xs⟩ m α) x, rfl⟩)
|
||||
| ⟨⟨x :: xs⟩⟩ => .deflate ⟨.yield (.mk ⟨xs⟩ m α) x, rfl⟩)
|
||||
|
||||
private def ListIterator.finitenessRelation [Pure m] :
|
||||
private def ListIterator.instFinitenessRelation [Pure m] :
|
||||
FinitenessRelation (ListIterator α) m where
|
||||
rel := InvImage WellFoundedRelation.rel (ListIterator.list ∘ IterM.internalState)
|
||||
wf := InvImage.wf _ WellFoundedRelation.wf
|
||||
@@ -64,27 +72,17 @@ private def ListIterator.finitenessRelation [Pure m] :
|
||||
obtain ⟨step, h, h'⟩ := h
|
||||
cases step <;> simp_all [IterStep.successor, IterM.IsPlausibleStep, Iterator.IsPlausibleStep]
|
||||
|
||||
instance [Pure m] : Finite (ListIterator α) m :=
|
||||
by exact Finite.of_finitenessRelation ListIterator.finitenessRelation
|
||||
instance ListIterator.instFinite [Pure m] : Finite (ListIterator α) m :=
|
||||
by exact Finite.of_finitenessRelation ListIterator.instFinitenessRelation
|
||||
|
||||
@[always_inline, inline]
|
||||
instance {α : Type w} [Monad m] {n : Type w → Type w''} [Monad n] :
|
||||
instance ListIterator.instIteratorCollect{α : Type w} [Monad m] {n : Type w → Type w''} [Monad n] :
|
||||
IteratorCollect (ListIterator α) m n :=
|
||||
.defaultImplementation
|
||||
|
||||
@[always_inline, inline]
|
||||
instance {α : Type w} [Monad m] {n : Type w → Type w''} [Monad n] :
|
||||
IteratorCollectPartial (ListIterator α) m n :=
|
||||
.defaultImplementation
|
||||
|
||||
@[always_inline, inline]
|
||||
instance {α : Type w} [Monad m] {n : Type x → Type x'} [Monad n] :
|
||||
instance ListIterator.instIteratorLoop {α : Type w} [Monad m] {n : Type x → Type x'} [Monad n] :
|
||||
IteratorLoop (ListIterator α) m n :=
|
||||
.defaultImplementation
|
||||
|
||||
@[always_inline, inline]
|
||||
instance {α : Type w} [Monad m] {n : Type x → Type x'} [Monad n] :
|
||||
IteratorLoopPartial (ListIterator α) m n :=
|
||||
.defaultImplementation
|
||||
|
||||
end Std.Iterators
|
||||
end Std.Iterators.Types
|
||||
|
||||
@@ -15,9 +15,7 @@ This module provides the typeclass `ToIterator`, which is implemented by types t
|
||||
converted into iterators.
|
||||
-/
|
||||
|
||||
open Std.Iterators
|
||||
|
||||
namespace Std.Iterators
|
||||
namespace Std
|
||||
|
||||
/-- This typeclass provides an iterator for elements of type `γ`. -/
|
||||
class ToIterator (γ : Type u) (m : Type w → Type w') (α β : outParam (Type w)) where
|
||||
@@ -60,4 +58,4 @@ theorem ToIterator.iter_eq {γ : Type u} {x : γ} {α β : Type v} {it} :
|
||||
ToIterator.iter x = (it x).toIter :=
|
||||
rfl
|
||||
|
||||
end Std.Iterators
|
||||
end Std
|
||||
|
||||
@@ -301,7 +301,7 @@ Examples:
|
||||
def getLast : ∀ (as : List α), as ≠ [] → α
|
||||
| [], h => absurd rfl h
|
||||
| [a], _ => a
|
||||
| _::b::as, _ => getLast (b::as) (fun h => List.noConfusion h)
|
||||
| _::b::as, _ => getLast (b::as) (fun h => List.noConfusion rfl (heq_of_eq h))
|
||||
|
||||
/-! ### getLast? -/
|
||||
|
||||
@@ -318,7 +318,7 @@ Examples:
|
||||
-/
|
||||
def getLast? : List α → Option α
|
||||
| [] => none
|
||||
| a::as => some (getLast (a::as) (fun h => List.noConfusion h))
|
||||
| a::as => some (getLast (a::as) (fun h => List.noConfusion rfl (heq_of_eq h)))
|
||||
|
||||
@[simp, grind =] theorem getLast?_nil : @getLast? α [] = none := rfl
|
||||
|
||||
@@ -337,7 +337,7 @@ Examples:
|
||||
-/
|
||||
def getLastD : (as : List α) → (fallback : α) → α
|
||||
| [], a₀ => a₀
|
||||
| a::as, _ => getLast (a::as) (fun h => List.noConfusion h)
|
||||
| a::as, _ => getLast (a::as) (fun h => List.noConfusion rfl (heq_of_eq h))
|
||||
|
||||
-- These aren't `simp` lemmas since we always simplify `getLastD` in terms of `getLast?`.
|
||||
theorem getLastD_nil {a : α} : getLastD [] a = a := rfl
|
||||
@@ -1607,8 +1607,8 @@ such element is found.
|
||||
`O(|l|)`.
|
||||
|
||||
Examples:
|
||||
* `[7, 6, 5, 8, 1, 2, 6].find? (· < 5) = some 2`
|
||||
* `[7, 6, 5, 8, 1, 2, 6].find? (· < 1) = none`
|
||||
* `[7, 6, 5, 8, 1, 2, 6].findRev? (· < 5) = some 2`
|
||||
* `[7, 6, 5, 8, 1, 2, 6].findRev? (· < 1) = none`
|
||||
-/
|
||||
def findRev? (p : α → Bool) : List α → Option α
|
||||
| [] => none
|
||||
@@ -1847,6 +1847,7 @@ Examples:
|
||||
* `[2, 4, 5, 6].any (· % 2 = 0) = true`
|
||||
* `[2, 4, 5, 6].any (· % 2 = 1) = true`
|
||||
-/
|
||||
@[suggest_for List.some]
|
||||
def any : (l : List α) → (p : α → Bool) → Bool
|
||||
| [], _ => false
|
||||
| h :: t, p => p h || any t p
|
||||
@@ -1866,6 +1867,7 @@ Examples:
|
||||
* `[2, 4, 6].all (· % 2 = 0) = true`
|
||||
* `[2, 4, 5, 6].all (· % 2 = 0) = false`
|
||||
-/
|
||||
@[suggest_for List.every]
|
||||
def all : List α → (α → Bool) → Bool
|
||||
| [], _ => true
|
||||
| h :: t, p => p h && all t p
|
||||
@@ -2252,7 +2254,7 @@ def eraseReps {α} [BEq α] (as : List α) : List α := eraseRepsBy (· == ·) a
|
||||
/-! ### span -/
|
||||
|
||||
/--
|
||||
Splits a list into the the longest initial segment for which `p` returns `true`, paired with the
|
||||
Splits a list into the longest initial segment for which `p` returns `true`, paired with the
|
||||
remainder of the list.
|
||||
|
||||
`O(|l|)`.
|
||||
|
||||
@@ -57,7 +57,7 @@ Examples:
|
||||
@[expose]
|
||||
def getLast! [Inhabited α] : List α → α
|
||||
| [] => panic! "empty list"
|
||||
| a::as => getLast (a::as) (fun h => List.noConfusion h)
|
||||
| a::as => getLast (a::as) (fun h => List.noConfusion rfl (heq_of_eq h))
|
||||
|
||||
/-! ## Head and tail -/
|
||||
|
||||
|
||||
@@ -366,12 +366,6 @@ theorem idRun_findM? (p : α → Id Bool) (as : List α) :
|
||||
(findM? p as).run = as.find? (p · |>.run) :=
|
||||
findM?_pure _ _
|
||||
|
||||
@[deprecated idRun_findM? (since := "2025-05-21")]
|
||||
theorem findM?_id (p : α → Id Bool) (as : List α) :
|
||||
findM? (m := Id) p as = as.find? p :=
|
||||
findM?_pure _ _
|
||||
|
||||
|
||||
/--
|
||||
Returns the first non-`none` result of applying the monadic function `f` to each element of the
|
||||
list, in order. Returns `none` if `f` returns `none` for all elements.
|
||||
@@ -434,11 +428,6 @@ theorem idRun_findSomeM? (f : α → Id (Option β)) (as : List α) :
|
||||
(findSomeM? f as).run = as.findSome? (f · |>.run) :=
|
||||
findSomeM?_pure
|
||||
|
||||
@[deprecated idRun_findSomeM? (since := "2025-05-21")]
|
||||
theorem findSomeM?_id (f : α → Id (Option β)) (as : List α) :
|
||||
findSomeM? (m := Id) f as = as.findSome? f :=
|
||||
findSomeM?_pure
|
||||
|
||||
theorem findSome?_eq_findSomeM? {f : α → Option β} {as : List α} :
|
||||
as.findSome? f = (as.findSomeM? (pure (f := Id) <| f ·)).run := by
|
||||
simp
|
||||
|
||||
@@ -29,7 +29,7 @@ section countP
|
||||
|
||||
variable {p q : α → Bool}
|
||||
|
||||
@[simp] theorem countP_nil : countP p [] = 0 := rfl
|
||||
@[simp, grind =] theorem countP_nil : countP p [] = 0 := rfl
|
||||
|
||||
protected theorem countP_go_eq_add {l} : countP.go p l n = n + countP.go p l 0 := by
|
||||
induction l generalizing n with
|
||||
@@ -47,6 +47,7 @@ protected theorem countP_go_eq_add {l} : countP.go p l n = n + countP.go p l 0 :
|
||||
@[simp] theorem countP_cons_of_neg {l} (pa : ¬p a) : countP p (a :: l) = countP p l := by
|
||||
simp [countP, countP.go, pa]
|
||||
|
||||
@[grind =]
|
||||
theorem countP_cons {a : α} {l : List α} : countP p (a :: l) = countP p l + if p a then 1 else 0 := by
|
||||
by_cases h : p a <;> simp [h]
|
||||
|
||||
@@ -66,7 +67,6 @@ theorem length_eq_countP_add_countP (p : α → Bool) {l : List α} : length l =
|
||||
· rfl
|
||||
· simp [h]
|
||||
|
||||
@[grind =] -- This to quite aggressive, as it introduces `filter` based reasoning whenever we see `countP`.
|
||||
theorem countP_eq_length_filter {l : List α} : countP p l = (filter p l).length := by
|
||||
induction l with
|
||||
| nil => rfl
|
||||
@@ -75,7 +75,8 @@ theorem countP_eq_length_filter {l : List α} : countP p l = (filter p l).length
|
||||
then rw [countP_cons_of_pos h, ih, filter_cons_of_pos h, length]
|
||||
else rw [countP_cons_of_neg h, ih, filter_cons_of_neg h]
|
||||
|
||||
@[grind =]
|
||||
grind_pattern countP_eq_length_filter => l.countP p, l.filter p
|
||||
|
||||
theorem countP_eq_length_filter' : countP p = length ∘ filter p := by
|
||||
funext l
|
||||
apply countP_eq_length_filter
|
||||
@@ -351,10 +352,6 @@ theorem filter_eq [DecidableEq α] {l : List α} (a : α) : l.filter (· = a) =
|
||||
· simpa only [count_replicate_self] using h.count_le a
|
||||
· exact ((replicate_sublist_replicate a).2 h).trans <| filter_beq a ▸ filter_sublist
|
||||
|
||||
@[deprecated replicate_sublist_iff (since := "2025-05-26")]
|
||||
theorem le_count_iff_replicate_sublist {l : List α} : n ≤ count a l ↔ replicate n a <+ l :=
|
||||
replicate_sublist_iff.symm
|
||||
|
||||
theorem replicate_count_eq_of_count_eq_length {l : List α} (h : count a l = length l) :
|
||||
replicate (count a l) a = l :=
|
||||
(replicate_sublist_iff.mpr (Nat.le_refl _)).eq_of_length <| length_replicate.trans h
|
||||
|
||||
@@ -77,7 +77,7 @@ Further results, which first require developing further automation around `Nat`,
|
||||
* `Init.Data.List.Nat.TakeDrop`: `List.take` and `List.drop`
|
||||
|
||||
Also
|
||||
* `Init.Data.List.Monadic` for addiation lemmas about `List.mapM` and `List.forM`.
|
||||
* `Init.Data.List.Monadic` for additional lemmas about `List.mapM` and `List.forM`.
|
||||
|
||||
-/
|
||||
|
||||
@@ -2566,17 +2566,9 @@ theorem foldr_eq_foldrM {f : α → β → β} {b : β} {l : List α} :
|
||||
theorem idRun_foldlM {f : β → α → Id β} {b : β} {l : List α} :
|
||||
Id.run (l.foldlM f b) = l.foldl (f · · |>.run) b := foldl_eq_foldlM.symm
|
||||
|
||||
@[deprecated idRun_foldlM (since := "2025-05-21")]
|
||||
theorem id_run_foldlM {f : β → α → Id β} {b : β} {l : List α} :
|
||||
Id.run (l.foldlM f b) = l.foldl f b := foldl_eq_foldlM.symm
|
||||
|
||||
theorem idRun_foldrM {f : α → β → Id β} {b : β} {l : List α} :
|
||||
Id.run (l.foldrM f b) = l.foldr (f · · |>.run) b := foldr_eq_foldrM.symm
|
||||
|
||||
@[deprecated idRun_foldrM (since := "2025-05-21")]
|
||||
theorem id_run_foldrM {f : α → β → Id β} {b : β} {l : List α} :
|
||||
Id.run (l.foldrM f b) = l.foldr f b := foldr_eq_foldrM.symm
|
||||
|
||||
@[simp] theorem foldlM_reverse [Monad m] {l : List α} {f : β → α → m β} {b : β} :
|
||||
l.reverse.foldlM f b = l.foldrM (fun x y => f y x) b := rfl
|
||||
|
||||
|
||||
@@ -73,10 +73,6 @@ theorem mapM'_eq_mapM [Monad m] [LawfulMonad m] {f : α → m β} {l : List α}
|
||||
@[simp, grind =] theorem idRun_mapM {l : List α} {f : α → Id β} : (l.mapM f).run = l.map (f · |>.run) :=
|
||||
mapM_pure
|
||||
|
||||
@[deprecated idRun_mapM (since := "2025-05-21")]
|
||||
theorem mapM_id {l : List α} {f : α → Id β} : (l.mapM f).run = l.map (f · |>.run) :=
|
||||
mapM_pure
|
||||
|
||||
@[simp, grind =] theorem mapM_map [Monad m] [LawfulMonad m] {f : α → β} {g : β → m γ} {l : List α} :
|
||||
(l.map f).mapM g = l.mapM (g ∘ f) := by
|
||||
induction l <;> simp_all
|
||||
@@ -388,13 +384,6 @@ theorem forIn'_eq_foldlM [Monad m] [LawfulMonad m]
|
||||
l.attach.foldl (fun b ⟨a, h⟩ => f a h b |>.run) init :=
|
||||
forIn'_pure_yield_eq_foldl _ _
|
||||
|
||||
@[deprecated idRun_forIn'_yield_eq_foldl (since := "2025-05-21")]
|
||||
theorem forIn'_yield_eq_foldl
|
||||
{l : List α} (f : (a : α) → a ∈ l → β → β) (init : β) :
|
||||
forIn' (m := Id) l init (fun a m b => .yield (f a m b)) =
|
||||
l.attach.foldl (fun b ⟨a, h⟩ => f a h b) init :=
|
||||
forIn'_pure_yield_eq_foldl _ _
|
||||
|
||||
@[simp, grind =] theorem forIn'_map [Monad m] [LawfulMonad m]
|
||||
{l : List α} (g : α → β) (f : (b : β) → b ∈ l.map g → γ → m (ForInStep γ)) :
|
||||
forIn' (l.map g) init f = forIn' l init fun a h y => f (g a) (mem_map_of_mem h) y := by
|
||||
@@ -447,13 +436,6 @@ theorem forIn_eq_foldlM [Monad m] [LawfulMonad m]
|
||||
l.foldl (fun b a => f a b |>.run) init :=
|
||||
forIn_pure_yield_eq_foldl _ _
|
||||
|
||||
@[deprecated idRun_forIn_yield_eq_foldl (since := "2025-05-21")]
|
||||
theorem forIn_yield_eq_foldl
|
||||
{l : List α} (f : α → β → β) (init : β) :
|
||||
forIn (m := Id) l init (fun a b => .yield (f a b)) =
|
||||
l.foldl (fun b a => f a b) init :=
|
||||
forIn_pure_yield_eq_foldl _ _
|
||||
|
||||
@[simp, grind =] theorem forIn_map [Monad m] [LawfulMonad m]
|
||||
{l : List α} {g : α → β} {f : β → γ → m (ForInStep γ)} :
|
||||
forIn (l.map g) init f = forIn l init fun a y => f (g a) y := by
|
||||
|
||||
@@ -121,9 +121,6 @@ theorem eraseIdx_insertIdx_self {i : Nat} {l : List α} (a : α) : (l.insertIdx
|
||||
rw [eraseIdx_eq_modifyTailIdx, insertIdx, modifyTailIdx_modifyTailIdx_self]
|
||||
exact modifyTailIdx_id _ _
|
||||
|
||||
@[deprecated eraseIdx_insertIdx_self (since := "2025-06-18")]
|
||||
abbrev eraseIdx_insertIdx := @eraseIdx_insertIdx_self
|
||||
|
||||
@[simp]
|
||||
theorem insertIdx_length_self {l : List α} {x : α} : l.insertIdx l.length x = l ++ [x] := by
|
||||
induction l with
|
||||
|
||||
@@ -60,14 +60,14 @@ theorem set_set_perm {as : List α} {i j : Nat} (h₁ : i < as.length) (h₂ : j
|
||||
|
||||
namespace Perm
|
||||
|
||||
/-- Variant of `List.Perm.take` specifying the the permutation is constant after `i` elementwise. -/
|
||||
/-- Variant of `List.Perm.take` specifying that the permutation is constant after `i` elementwise. -/
|
||||
theorem take_of_getElem? {l₁ l₂ : List α} (h : l₁ ~ l₂) {i : Nat} (w : ∀ j, i ≤ j → l₁[j]? = l₂[j]?) :
|
||||
l₁.take i ~ l₂.take i := by
|
||||
refine h.take (Perm.of_eq ?_)
|
||||
ext1 j
|
||||
simpa using w (i + j) (by omega)
|
||||
|
||||
/-- Variant of `List.Perm.drop` specifying the the permutation is constant before `i` elementwise. -/
|
||||
/-- Variant of `List.Perm.drop` specifying that the permutation is constant before `i` elementwise. -/
|
||||
theorem drop_of_getElem? {l₁ l₂ : List α} (h : l₁ ~ l₂) {i : Nat} (w : ∀ j, j < i → l₁[j]? = l₂[j]?) :
|
||||
l₁.drop i ~ l₂.drop i := by
|
||||
refine h.drop (Perm.of_eq ?_)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user