mirror of
https://github.com/leanprover/lean4.git
synced 2026-03-29 00:04:11 +00:00
Compare commits
205 Commits
grind_patt
...
sym_simp_d
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b3b07f1b13 | ||
|
|
1e01ed29c9 | ||
|
|
9cf9829ae9 | ||
|
|
14cf40d6d0 | ||
|
|
58e599f2f9 | ||
|
|
c91a2c63c2 | ||
|
|
d7cbdebf0b | ||
|
|
28a5e9f93c | ||
|
|
470498cc06 | ||
|
|
d57f71c1c0 | ||
|
|
eaf8cf15ff | ||
|
|
cae739c27c | ||
|
|
9280a0ba9e | ||
|
|
e42262e397 | ||
|
|
a96ae4bb12 | ||
|
|
14039942f3 | ||
|
|
5bb7f37645 | ||
|
|
15a719cb36 | ||
|
|
0f1eb1d0e5 | ||
|
|
e766839345 | ||
|
|
22bef1c45a | ||
|
|
b771d12072 | ||
|
|
214abb7eb2 | ||
|
|
76a734c907 | ||
|
|
f65fe51630 | ||
|
|
e6d021967e | ||
|
|
4c360d50fa | ||
|
|
821218aabd | ||
|
|
7b1fb7ac9e | ||
|
|
cd632b033d | ||
|
|
d92cdae8e9 | ||
|
|
7d5a96941e | ||
|
|
b4cf6b02b9 | ||
|
|
ea7c740ad4 | ||
|
|
aa8fa47321 | ||
|
|
7e6365567f | ||
|
|
1361d733a6 | ||
|
|
0ad15fe982 | ||
|
|
531dbf0e1b | ||
|
|
2e649e16f0 | ||
|
|
0e4794a1a9 | ||
|
|
975a81cdb8 | ||
|
|
f7de0c408f | ||
|
|
60cdda3c1e | ||
|
|
8484dbad5d | ||
|
|
b0ebfaa812 | ||
|
|
c3cc61cdb4 | ||
|
|
ff87bcb8e5 | ||
|
|
a6ed0d640d | ||
|
|
8154453bb5 | ||
|
|
11e4e44be0 | ||
|
|
c871f66cfa | ||
|
|
0f866236c7 | ||
|
|
f6c8b8d974 | ||
|
|
175661b6c3 | ||
|
|
fd88637948 | ||
|
|
7376772cbd | ||
|
|
c358b0c734 | ||
|
|
8207919728 | ||
|
|
06b7b022b3 | ||
|
|
460b3c3e43 | ||
|
|
b46688d683 | ||
|
|
82f60a7ff3 | ||
|
|
6bf2486e13 | ||
|
|
f1c903ca65 | ||
|
|
35d8925c50 | ||
|
|
9f404d8fbe | ||
|
|
81c93aeae8 | ||
|
|
cf36ac986d | ||
|
|
609d99e860 | ||
|
|
78c9a01bb2 | ||
|
|
a2cf78ac4a | ||
|
|
bc72487aed | ||
|
|
b40dabdecd | ||
|
|
19df2c41b3 | ||
|
|
ce8fdb1aa7 | ||
|
|
fab1897f28 | ||
|
|
3804a1df8d | ||
|
|
514a5fddc6 | ||
|
|
d8f0507d2a | ||
|
|
4eb5b5776d | ||
|
|
6642061623 | ||
|
|
4e8b5cfc46 | ||
|
|
c07ee77d33 | ||
|
|
b82f969e5b | ||
|
|
97c23abf8e | ||
|
|
ef9777ec0d | ||
|
|
b7360969ed | ||
|
|
9b1b932242 | ||
|
|
d4563a818f | ||
|
|
e8781f12c0 | ||
|
|
1ca4faae18 | ||
|
|
3a5887276c | ||
|
|
e086b9b5c6 | ||
|
|
16ae74e98e | ||
|
|
2a28cd98fc | ||
|
|
bba35e4532 | ||
|
|
17581a2628 | ||
|
|
05664b15a3 | ||
|
|
1590a72913 | ||
|
|
f77ce8c669 | ||
|
|
4e1a2487b7 | ||
|
|
b60556af4e | ||
|
|
2bca310bea | ||
|
|
5042c8cc37 | ||
|
|
1e99ff1dba | ||
|
|
48bb954e4e | ||
|
|
96160e553a | ||
|
|
18702bdd47 | ||
|
|
4eaaadf1c1 | ||
|
|
2234c91163 | ||
|
|
4f7ba5eb09 | ||
|
|
da70626e64 | ||
|
|
214acc921c | ||
|
|
f483c6c10f | ||
|
|
c0d5e8bc2c | ||
|
|
c02f570b76 | ||
|
|
19d16ff9b7 | ||
|
|
58420f9416 | ||
|
|
b3b33e85d3 | ||
|
|
723acce2a7 | ||
|
|
e765138bb4 | ||
|
|
501375f340 | ||
|
|
ce56e2139e | ||
|
|
c34e4cf0f7 | ||
|
|
f2c9fcc0b2 | ||
|
|
950a2b7896 | ||
|
|
88f17dee71 | ||
|
|
4d2647f9c7 | ||
|
|
a471f005d6 | ||
|
|
f6a25b13b9 | ||
|
|
a847b13b1a | ||
|
|
186a81627b | ||
|
|
0df74178d8 | ||
|
|
72f9b725aa | ||
|
|
dc53fac626 | ||
|
|
13c88f960f | ||
|
|
0d2a574f96 | ||
|
|
a7562bc578 | ||
|
|
c86b10d141 | ||
|
|
54a88e941f | ||
|
|
b87d2c0fb9 | ||
|
|
eb990538ae | ||
|
|
4c0765fc07 | ||
|
|
5e24120dba | ||
|
|
f317e28d84 | ||
|
|
bb8e6801f0 | ||
|
|
5440bf724d | ||
|
|
c88ec35c0d | ||
|
|
73ff198d11 | ||
|
|
cee149cc1f | ||
|
|
2236122411 | ||
|
|
c74d24aaaa | ||
|
|
34d619bf93 | ||
|
|
eb11ccb234 | ||
|
|
2db0a98b7c | ||
|
|
6cabf59099 | ||
|
|
89bbe804a5 | ||
|
|
4e656ea8e9 | ||
|
|
aa9f7ab14b | ||
|
|
5ef0207a85 | ||
|
|
a1b8ffe31b | ||
|
|
f21f8d96f9 | ||
|
|
1918d4f0dc | ||
|
|
08c87b2ad3 | ||
|
|
489f8acd77 | ||
|
|
3e61514ce4 | ||
|
|
f63c2363ee | ||
|
|
fe96911368 | ||
|
|
08f0d12ffb | ||
|
|
06d2390fb3 | ||
|
|
3ac9bbb3d8 | ||
|
|
118160bf07 | ||
|
|
c1bc886d98 | ||
|
|
0708024c46 | ||
|
|
2d9571563a | ||
|
|
e2617903f8 | ||
|
|
7ba21c4d1b | ||
|
|
b7f1cf9ba7 | ||
|
|
12c282b1e9 | ||
|
|
5f4d724c2d | ||
|
|
98616529fd | ||
|
|
8f80d2c2e0 | ||
|
|
fd0a65f312 | ||
|
|
bd5d750780 | ||
|
|
49d4752bfd | ||
|
|
95a7c769d8 | ||
|
|
7b8e51e025 | ||
|
|
949cf69246 | ||
|
|
e02f229305 | ||
|
|
9b49b6b68d | ||
|
|
eb20c07b4a | ||
|
|
3fdde57e7b | ||
|
|
c79d74d9a1 | ||
|
|
082c65f226 | ||
|
|
6a0b0c8273 | ||
|
|
62b900e8ef | ||
|
|
429e09cd82 | ||
|
|
c4d67c22e6 | ||
|
|
923d7e1ed6 | ||
|
|
5db865ea2f | ||
|
|
0f2ac0b099 | ||
|
|
b7ff463358 | ||
|
|
799c6b5ff8 | ||
|
|
2d0c62c767 |
@@ -29,6 +29,23 @@ After rebuilding, LSP diagnostics may be stale until the user interacts with fil
|
||||
|
||||
If the user expresses frustration with you, stop and ask them to help update this `.claude/CLAUDE.md` file with missing guidance.
|
||||
|
||||
## Creating pull requests.
|
||||
## Creating pull requests
|
||||
|
||||
All PRs must have a first paragraph starting with "This PR". This paragraph is automatically incorporated into release notes. Read `lean4/doc/dev/commit_convention.md` when making PRs.
|
||||
Follow the commit convention in `doc/dev/commit_convention.md`.
|
||||
|
||||
**Title format:** `<type>: <subject>` where type is one of: `feat`, `fix`, `doc`, `style`, `refactor`, `test`, `chore`, `perf`.
|
||||
Subject should use imperative present tense ("add" not "added"), no capitalization, no trailing period.
|
||||
|
||||
**Body format:** The first paragraph must start with "This PR". This paragraph is automatically incorporated into release notes. Use imperative present tense. Include motivation and contrast with previous behavior when relevant.
|
||||
|
||||
Example:
|
||||
```
|
||||
feat: add optional binder limit to `mkPatternFromTheorem`
|
||||
|
||||
This PR adds a `num?` parameter to `mkPatternFromTheorem` to control how many
|
||||
leading quantifiers are stripped when creating a pattern.
|
||||
```
|
||||
|
||||
## CI Log Retrieval
|
||||
|
||||
When CI jobs fail, investigate immediately - don't wait for other jobs to complete. Individual job logs are often available even while other jobs are still running. Try `gh run view <run-id> --log` or `gh run view <run-id> --log-failed`, or use `gh run view <run-id> --job=<job-id>` to target the specific failed job. Sleeping is fine when asked to monitor CI and no failures exist yet, but once any job fails, investigate that failure immediately.
|
||||
|
||||
2
.github/workflows/actionlint.yml
vendored
2
.github/workflows/actionlint.yml
vendored
@@ -15,7 +15,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v6
|
||||
- name: actionlint
|
||||
uses: raven-actions/actionlint@v2
|
||||
with:
|
||||
|
||||
4
.github/workflows/build-template.yml
vendored
4
.github/workflows/build-template.yml
vendored
@@ -67,13 +67,13 @@ jobs:
|
||||
if: runner.os == 'macOS'
|
||||
- name: Checkout
|
||||
if: (!endsWith(matrix.os, '-with-cache'))
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
# the default is to use a virtual merge commit between the PR and master: just use the PR
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
- name: Namespace Checkout
|
||||
if: endsWith(matrix.os, '-with-cache')
|
||||
uses: namespacelabs/nscloud-checkout-action@v7
|
||||
uses: namespacelabs/nscloud-checkout-action@v8
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
- name: Open Nix shell once
|
||||
|
||||
2
.github/workflows/check-prelude.yml
vendored
2
.github/workflows/check-prelude.yml
vendored
@@ -7,7 +7,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
# the default is to use a virtual merge commit between the PR and master: just use the PR
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
|
||||
2
.github/workflows/check-stage0.yml
vendored
2
.github/workflows/check-stage0.yml
vendored
@@ -8,7 +8,7 @@ jobs:
|
||||
check-stage0-on-queue:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
fetch-depth: 0
|
||||
|
||||
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');
|
||||
}
|
||||
20
.github/workflows/ci.yml
vendored
20
.github/workflows/ci.yml
vendored
@@ -50,7 +50,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v6
|
||||
# don't schedule nightlies on forks
|
||||
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
|
||||
@@ -267,12 +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.
|
||||
// 9366 is too close to timeout
|
||||
"CTEST_OPTIONS": "-E 'StackOverflow|reverse-ffi|interactive|async_select_channel|9366'"
|
||||
// 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",
|
||||
@@ -432,7 +434,7 @@ jobs:
|
||||
with:
|
||||
path: artifacts
|
||||
- name: Release
|
||||
uses: softprops/action-gh-release@6da8fa9354ddfdc4aeace5fc48d7f679b5214090
|
||||
uses: softprops/action-gh-release@a06a81a03ee405af7f2048a818ed3f03bbf83c7b
|
||||
with:
|
||||
files: artifacts/*/*
|
||||
fail_on_unmatched_files: true
|
||||
@@ -453,7 +455,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
# needed for tagging
|
||||
fetch-depth: 0
|
||||
@@ -478,7 +480,7 @@ jobs:
|
||||
echo -e "\n*Full commit log*\n" >> diff.md
|
||||
git log --oneline "$last_tag"..HEAD | sed 's/^/* /' >> diff.md
|
||||
- name: Release Nightly
|
||||
uses: softprops/action-gh-release@6da8fa9354ddfdc4aeace5fc48d7f679b5214090
|
||||
uses: softprops/action-gh-release@a06a81a03ee405af7f2048a818ed3f03bbf83c7b
|
||||
with:
|
||||
body_path: diff.md
|
||||
prerelease: true
|
||||
|
||||
2
.github/workflows/copyright-header.yml
vendored
2
.github/workflows/copyright-header.yml
vendored
@@ -6,7 +6,7 @@ jobs:
|
||||
check-lean-files:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- uses: actions/checkout@v6
|
||||
|
||||
- name: Verify .lean files start with a copyright header.
|
||||
run: |
|
||||
|
||||
26
.github/workflows/pr-release.yml
vendored
26
.github/workflows/pr-release.yml
vendored
@@ -71,7 +71,7 @@ jobs:
|
||||
GH_TOKEN: ${{ secrets.PR_RELEASES_TOKEN }}
|
||||
- name: Release (short format)
|
||||
if: ${{ steps.workflow-info.outputs.pullRequestNumber != '' }}
|
||||
uses: softprops/action-gh-release@6da8fa9354ddfdc4aeace5fc48d7f679b5214090
|
||||
uses: softprops/action-gh-release@a06a81a03ee405af7f2048a818ed3f03bbf83c7b
|
||||
with:
|
||||
name: Release for PR ${{ steps.workflow-info.outputs.pullRequestNumber }}
|
||||
# There are coredumps files here as well, but all in deeper subdirectories.
|
||||
@@ -86,7 +86,7 @@ jobs:
|
||||
|
||||
- name: Release (SHA-suffixed format)
|
||||
if: ${{ steps.workflow-info.outputs.pullRequestNumber != '' }}
|
||||
uses: softprops/action-gh-release@6da8fa9354ddfdc4aeace5fc48d7f679b5214090
|
||||
uses: softprops/action-gh-release@a06a81a03ee405af7f2048a818ed3f03bbf83c7b
|
||||
with:
|
||||
name: Release for PR ${{ steps.workflow-info.outputs.pullRequestNumber }} (${{ steps.workflow-info.outputs.sourceHeadSha }})
|
||||
# There are coredumps files here as well, but all in deeper subdirectories.
|
||||
@@ -166,22 +166,14 @@ jobs:
|
||||
if [ "$NIGHTLY_SHA" = "$MERGE_BASE_SHA" ]; then
|
||||
echo "The merge base of this PR coincides with the nightly release"
|
||||
|
||||
BATTERIES_REMOTE_TAGS="$(git ls-remote https://github.com/leanprover-community/batteries.git nightly-testing-"$MOST_RECENT_NIGHTLY")"
|
||||
MATHLIB_REMOTE_TAGS="$(git ls-remote https://github.com/leanprover-community/mathlib4-nightly-testing.git nightly-testing-"$MOST_RECENT_NIGHTLY")"
|
||||
|
||||
if [[ -n "$BATTERIES_REMOTE_TAGS" ]]; then
|
||||
echo "... and Batteries has a 'nightly-testing-$MOST_RECENT_NIGHTLY' tag."
|
||||
if [[ -n "$MATHLIB_REMOTE_TAGS" ]]; then
|
||||
echo "... and Mathlib has a 'nightly-testing-$MOST_RECENT_NIGHTLY' tag."
|
||||
MESSAGE=""
|
||||
|
||||
if [[ -n "$MATHLIB_REMOTE_TAGS" ]]; then
|
||||
echo "... and Mathlib has a 'nightly-testing-$MOST_RECENT_NIGHTLY' tag."
|
||||
else
|
||||
echo "... but Mathlib does not yet have a 'nightly-testing-$MOST_RECENT_NIGHTLY' tag."
|
||||
MESSAGE="- ❗ Mathlib CI can not be attempted yet, as the \`nightly-testing-$MOST_RECENT_NIGHTLY\` tag does not exist there yet. We will retry when you push more commits. If you rebase your branch onto \`nightly-with-mathlib\`, Mathlib CI should run now."
|
||||
fi
|
||||
else
|
||||
echo "... but Batteries does not yet have a 'nightly-testing-$MOST_RECENT_NIGHTLY' tag."
|
||||
MESSAGE="- ❗ Batteries CI can not be attempted yet, as the \`nightly-testing-$MOST_RECENT_NIGHTLY\` tag does not exist there yet. We will retry when you push more commits. If you rebase your branch onto \`nightly-with-mathlib\`, Batteries CI should run now."
|
||||
echo "... but Mathlib does not yet have a 'nightly-testing-$MOST_RECENT_NIGHTLY' tag."
|
||||
MESSAGE="- ❗ Mathlib CI can not be attempted yet, as the \`nightly-testing-$MOST_RECENT_NIGHTLY\` tag does not exist there yet. We will retry when you push more commits. If you rebase your branch onto \`nightly-with-mathlib\`, Mathlib CI should run now."
|
||||
fi
|
||||
else
|
||||
echo "The most recently nightly tag on this branch has SHA: $NIGHTLY_SHA"
|
||||
@@ -395,7 +387,7 @@ jobs:
|
||||
# Checkout the Batteries repository with all branches
|
||||
- name: Checkout Batteries repository
|
||||
if: steps.workflow-info.outputs.pullRequestNumber != '' && steps.ready.outputs.mathlib_ready == 'true'
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
repository: leanprover-community/batteries
|
||||
token: ${{ secrets.MATHLIB4_BOT }}
|
||||
@@ -455,7 +447,7 @@ jobs:
|
||||
# Checkout the mathlib4 repository with all branches
|
||||
- name: Checkout mathlib4 repository
|
||||
if: steps.workflow-info.outputs.pullRequestNumber != '' && steps.ready.outputs.mathlib_ready == 'true'
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
repository: leanprover-community/mathlib4-nightly-testing
|
||||
token: ${{ secrets.MATHLIB4_BOT }}
|
||||
@@ -538,7 +530,7 @@ jobs:
|
||||
# Checkout the reference manual repository with all branches
|
||||
- name: Checkout mathlib4 repository
|
||||
if: steps.workflow-info.outputs.pullRequestNumber != '' && steps.reference-manual-ready.outputs.manual_ready == 'true'
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
repository: leanprover/reference-manual
|
||||
token: ${{ secrets.MANUAL_PR_BOT }}
|
||||
|
||||
2
.github/workflows/update-stage0.yml
vendored
2
.github/workflows/update-stage0.yml
vendored
@@ -27,7 +27,7 @@ jobs:
|
||||
# This action should push to an otherwise protected branch, so it
|
||||
# uses a deploy key with write permissions, as suggested at
|
||||
# https://stackoverflow.com/a/76135647/946226
|
||||
- uses: actions/checkout@v5
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
ssh-key: ${{secrets.STAGE0_SSH_KEY}}
|
||||
- run: echo "should_update_stage0=yes" >> "$GITHUB_ENV"
|
||||
|
||||
190
doc/dev/ffi.md
190
doc/dev/ffi.md
@@ -1,189 +1,9 @@
|
||||
# Foreign Function Interface
|
||||
|
||||
NOTE: The current interface was designed for internal use in Lean and should be considered **unstable**.
|
||||
It will be refined and extended in the future.
|
||||
The Lean FFI documentation is now part of the [Lean language reference](https://lean-lang.org/doc/reference/latest/).
|
||||
|
||||
As Lean is written partially in Lean itself and partially in C++, it offers efficient interoperability between the two languages (or rather, between Lean and any language supporting C interfaces).
|
||||
This support is however currently limited to transferring Lean data types; in particular, it is not possible yet to pass or return compound data structures such as C `struct`s by value from or to Lean.
|
||||
* [General FFI](https://lean-lang.org/doc/reference/latest/find/?domain=Verso.Genre.Manual.section&name=ffi)
|
||||
* [Representation of inductive types](https://lean-lang.org/doc/reference/latest/find/?domain=Verso.Genre.Manual.section&name=inductive-types-ffi)
|
||||
* [String](https://lean-lang.org/doc/reference/latest/find/?domain=Verso.Genre.Manual.section&name=string-ffi)
|
||||
* [Array](https://lean-lang.org/doc/reference/latest/find/?domain=Verso.Genre.Manual.section&name=array-ffi)
|
||||
|
||||
There are two primary attributes for interoperating with other languages:
|
||||
* `@[extern "sym"] constant leanSym : ...` binds a Lean declaration to the external symbol `sym`.
|
||||
It can also be used with `def` to provide an internal definition, but ensuring consistency of both definitions is up to the user.
|
||||
* `@[export sym] def leanSym : ...` exports `leanSym` under the unmangled symbol name `sym`.
|
||||
|
||||
For simple examples of how to call foreign code from Lean and vice versa, see <https://github.com/leanprover/lean4/blob/master/src/lake/examples/ffi> and <https://github.com/leanprover/lean4/blob/master/src/lake/examples/reverse-ffi>, respectively.
|
||||
|
||||
## The Lean ABI
|
||||
|
||||
The Lean Application Binary Interface (ABI) describes how the signature of a Lean declaration is encoded as a native calling convention.
|
||||
It is based on the standard C ABI and calling convention of the target platform.
|
||||
For a Lean declaration marked with either `@[extern "sym"]` or `@[export sym]` for some symbol name `sym`, let `α₁ → ... → αₙ → β` be the normalized declaration's type.
|
||||
If `n` is 0, the corresponding C declaration is
|
||||
```c
|
||||
extern s sym;
|
||||
```
|
||||
where `s` is the C translation of `β` as specified in the next section.
|
||||
In the case of an `@[extern]` definition, the symbol's value is guaranteed to be initialized only after calling the Lean module's initializer or that of an importing module; see [Initialization](#initialization).
|
||||
|
||||
If `n` is greater than 0, the corresponding C declaration is
|
||||
```c
|
||||
s sym(t₁, ..., tₘ);
|
||||
```
|
||||
where the parameter types `tᵢ` are the C translation of the `αᵢ` as in the next section.
|
||||
In the case of `@[extern]` all *irrelevant* types are removed first; see next section.
|
||||
|
||||
### Translating Types from Lean to C
|
||||
|
||||
* The integer types `UInt8`, ..., `UInt64`, `USize` are represented by the C types `uint8_t`, ..., `uint64_t`, `size_t`, respectively
|
||||
* `Char` is represented by `uint32_t`
|
||||
* `Float` is represented by `double`
|
||||
* An *enum* inductive type of at least 2 and at most 2^32 constructors, each of which with no parameters, is represented by the first type of `uint8_t`, `uint16_t`, `uint32_t` that is sufficient to represent all constructor indices.
|
||||
|
||||
For example, the type `Bool` is represented as `uint8_t` with values `0` for `false` and `1` for `true`.
|
||||
* `Decidable α` is represented the same way as `Bool`
|
||||
* An inductive type with a *trivial structure*, that is,
|
||||
* it is none of the types described above
|
||||
* it is not marked `unsafe`
|
||||
* it has a single constructor with a single parameter of *relevant* type
|
||||
|
||||
is represented by the representation of that parameter's type.
|
||||
|
||||
For example, `{ x : α // p }`, the `Subtype` structure of a value of type `α` and an irrelevant proof, is represented by the representation of `α`.
|
||||
Similarly, the signed integer types `Int8`, ..., `Int64`, `ISize` are also represented by the unsigned C types `uint8_t`, ..., `uint64_t`, `size_t`, respectively, because they have a trivial structure.
|
||||
* `Nat` and `Int` are represented by `lean_object *`.
|
||||
Their runtime values is either a pointer to an opaque bignum object or, if the lowest bit of the "pointer" is 1 (`lean_is_scalar`), an encoded unboxed natural number or integer (`lean_box`/`lean_unbox`).
|
||||
* A universe `Sort u`, type constructor `... → Sort u`, `Void α` or proposition `p : Prop` is *irrelevant* and is either statically erased (see above) or represented as a `lean_object *` with the runtime value `lean_box(0)`
|
||||
* Any other type is represented by `lean_object *`.
|
||||
Its runtime value is a pointer to an object of a subtype of `lean_object` (see the "Inductive types" section below) or the unboxed value `lean_box(cidx)` for the `cidx`th constructor of an inductive type if this constructor does not have any relevant parameters.
|
||||
|
||||
Example: the runtime value of `u : Unit` is always `lean_box(0)`.
|
||||
|
||||
#### Inductive types
|
||||
|
||||
For inductive types which are in the fallback `lean_object *` case above and not trivial constructors, the type is stored as a `lean_ctor_object`, and `lean_is_ctor` will return true. A `lean_ctor_object` stores the constructor index in the header, and the fields are stored in the `m_objs` portion of the object.
|
||||
|
||||
The memory order of the fields is derived from the types and order of the fields in the declaration. They are ordered as follows:
|
||||
|
||||
* Non-scalar fields stored as `lean_object *`
|
||||
* Fields of type `USize`
|
||||
* Other scalar fields, in decreasing order by size
|
||||
|
||||
Within each group the fields are ordered in declaration order. Trivial wrapper types count as their underlying wrapped type for this purpose.
|
||||
|
||||
* To access fields of the first kind, use `lean_ctor_get(val, i)` to get the `i`th non-scalar field.
|
||||
* To access `USize` fields, use `lean_ctor_get_usize(val, n+i)` to get the `i`th usize field and `n` is the total number of fields of the first kind.
|
||||
* To access other scalar fields, use `lean_ctor_get_uintN(val, off)` or `lean_ctor_get_usize(val, off)` as appropriate. Here `off` is the byte offset of the field in the structure, starting at `n*sizeof(void*)` where `n` is the number of fields of the first two kinds.
|
||||
|
||||
For example, a structure such as
|
||||
```lean
|
||||
structure S where
|
||||
ptr_1 : Array Nat
|
||||
usize_1 : USize
|
||||
sc64_1 : UInt64
|
||||
sc64_2 : { x : UInt64 // x > 0 } -- wrappers of scalars count as scalars
|
||||
sc64_3 : Float -- `Float` is 64 bit
|
||||
sc8_1 : Bool
|
||||
sc16_1 : UInt16
|
||||
sc8_2 : UInt8
|
||||
sc64_4 : UInt64
|
||||
usize_2 : USize
|
||||
sc32_1 : Char -- trivial wrapper around `UInt32`
|
||||
sc32_2 : UInt32
|
||||
sc16_2 : UInt16
|
||||
```
|
||||
would get re-sorted into the following memory order:
|
||||
|
||||
* `S.ptr_1` - `lean_ctor_get(val, 0)`
|
||||
* `S.usize_1` - `lean_ctor_get_usize(val, 1)`
|
||||
* `S.usize_2` - `lean_ctor_get_usize(val, 2)`
|
||||
* `S.sc64_1` - `lean_ctor_get_uint64(val, sizeof(void*)*3)`
|
||||
* `S.sc64_2` - `lean_ctor_get_uint64(val, sizeof(void*)*3 + 8)`
|
||||
* `S.sc64_3` - `lean_ctor_get_float(val, sizeof(void*)*3 + 16)`
|
||||
* `S.sc64_4` - `lean_ctor_get_uint64(val, sizeof(void*)*3 + 24)`
|
||||
* `S.sc32_1` - `lean_ctor_get_uint32(val, sizeof(void*)*3 + 32)`
|
||||
* `S.sc32_2` - `lean_ctor_get_uint32(val, sizeof(void*)*3 + 36)`
|
||||
* `S.sc16_1` - `lean_ctor_get_uint16(val, sizeof(void*)*3 + 40)`
|
||||
* `S.sc16_2` - `lean_ctor_get_uint16(val, sizeof(void*)*3 + 42)`
|
||||
* `S.sc8_1` - `lean_ctor_get_uint8(val, sizeof(void*)*3 + 44)`
|
||||
* `S.sc8_2` - `lean_ctor_get_uint8(val, sizeof(void*)*3 + 45)`
|
||||
|
||||
### Borrowing
|
||||
|
||||
By default, all `lean_object *` parameters of an `@[extern]` function are considered *owned*, i.e. the external code is passed a "virtual RC token" and is responsible for passing this token along to another consuming function (exactly once) or freeing it via `lean_dec`.
|
||||
To reduce reference counting overhead, parameters can be marked as *borrowed* by prefixing their type with `@&`.
|
||||
Borrowed objects must only be passed to other non-consuming functions (arbitrarily often) or converted to owned values using `lean_inc`.
|
||||
In `lean.h`, the `lean_object *` aliases `lean_obj_arg` and `b_lean_obj_arg` are used to mark this difference on the C side.
|
||||
|
||||
Return values and `@[export]` parameters are always owned at the moment.
|
||||
|
||||
## Initialization
|
||||
|
||||
When including Lean code as part of a larger program, modules must be *initialized* before accessing any of their declarations.
|
||||
Module initialization entails
|
||||
* initialization of all "constants" (nullary functions), including closed terms lifted out of other functions
|
||||
* execution of all `[init]` functions
|
||||
* execution of all `[builtin_init]` functions, if the `builtin` parameter of the module initializer has been set
|
||||
|
||||
The module initializer is automatically run with the `builtin` flag for executables compiled from Lean code and for "plugins" loaded with `lean --plugin`.
|
||||
For all other modules imported by `lean`, the initializer is run without `builtin`.
|
||||
Thus `[init]` functions are run iff their module is imported, regardless of whether they have native code available or not, while `[builtin_init]` functions are only run for native executable or plugins, regardless of whether their module is imported or not.
|
||||
`lean` uses built-in initializers for e.g. registering basic parsers that should be available even without importing their module (which is necessary for bootstrapping).
|
||||
|
||||
The initializer for module `A.B` in a package `foo` is called `initialize_foo_A_B`. For modules in the Lean core (e.g., `Init.Prelude`), the initializer is called `initialize_Init_Prelude`. Module initializers will automatically initialize any imported modules. They are also idempotent (when run with the same `builtin` flag), but not thread-safe.
|
||||
|
||||
**Important for process-related functionality**: If your application needs to use process-related functions from libuv, such as `Std.Internal.IO.Process.getProcessTitle` and `Std.Internal.IO.Process.setProcessTitle`, you must call `lean_setup_args(argc, argv)` (which returns a potentially modified `argv` that must be used in place of the original) **before** calling `lean_initialize()` or `lean_initialize_runtime_module()`. This sets up process handling capabilities correctly, which is essential for certain system-level operations that Lean's runtime may depend on.
|
||||
|
||||
Together with initialization of the Lean runtime, you should execute code like the following exactly once before accessing any Lean declarations:
|
||||
|
||||
```c
|
||||
void lean_initialize_runtime_module();
|
||||
void lean_initialize();
|
||||
char ** lean_setup_args(int argc, char ** argv);
|
||||
|
||||
lean_object * initialize_A_B(uint8_t builtin);
|
||||
lean_object * initialize_C(uint8_t builtin);
|
||||
...
|
||||
|
||||
argv = lean_setup_args(argc, argv); // if using process-related functionality
|
||||
lean_initialize_runtime_module();
|
||||
//lean_initialize(); // necessary (and replaces `lean_initialize_runtime_module`) if you (indirectly) access the `Lean` package
|
||||
|
||||
lean_object * res;
|
||||
// use same default as for Lean executables
|
||||
uint8_t builtin = 1;
|
||||
res = initialize_A_B(builtin);
|
||||
if (lean_io_result_is_ok(res)) {
|
||||
lean_dec_ref(res);
|
||||
} else {
|
||||
lean_io_result_show_error(res);
|
||||
lean_dec(res);
|
||||
return ...; // do not access Lean declarations if initialization failed
|
||||
}
|
||||
res = initialize_C(builtin);
|
||||
if (lean_io_result_is_ok(res)) {
|
||||
...
|
||||
|
||||
//lean_init_task_manager(); // necessary if you (indirectly) use `Task`
|
||||
lean_io_mark_end_initialization();
|
||||
```
|
||||
|
||||
In addition, any other thread not spawned by the Lean runtime itself must be initialized for Lean use by calling
|
||||
```c
|
||||
void lean_initialize_thread();
|
||||
```
|
||||
and should be finalized in order to free all thread-local resources by calling
|
||||
```c
|
||||
void lean_finalize_thread();
|
||||
```
|
||||
|
||||
## `@[extern]` in the Interpreter
|
||||
|
||||
The interpreter can run Lean declarations for which symbols are available in loaded shared libraries, which includes `@[extern]` declarations.
|
||||
Thus to e.g. run `#eval` on such a declaration, you need to
|
||||
1. compile (at least) the module containing the declaration and its dependencies into a shared library, and then
|
||||
1. pass this library to `lean --load-dynlib=` to run code `import`ing this module.
|
||||
|
||||
Note that it is not sufficient to load the foreign library containing the external symbol because the interpreter depends on code that is emitted for each `@[extern]` declaration.
|
||||
Thus it is not possible to interpret an `@[extern]` declaration in the same file.
|
||||
|
||||
See [`tests/compiler/foreign`](https://github.com/leanprover/lean4/tree/master/tests/compiler/foreign/) for an example.
|
||||
|
||||
106
doc/style.md
106
doc/style.md
@@ -810,7 +810,7 @@ Docstrings for constants should have the following structure:
|
||||
|
||||
The **short summary** should be 1–3 sentences (ideally 1) and provide
|
||||
enough information for most readers to quickly decide whether the
|
||||
docstring is relevant to their task. The first (or only) sentence of
|
||||
constant is relevant to their task. The first (or only) sentence of
|
||||
the short summary should be a *sentence fragment* in which the subject
|
||||
is implied to be the documented item, written in present tense
|
||||
indicative, or a *noun phrase* that characterizes the documented
|
||||
@@ -1123,6 +1123,110 @@ infix:50 " ⇔ " => Bijection
|
||||
recommended_spelling "bij" for "⇔" in [Bijection, «term_⇔_»]
|
||||
```
|
||||
|
||||
#### Tactics
|
||||
|
||||
Docstrings for tactics should have the following structure:
|
||||
|
||||
* Short summary
|
||||
* Details
|
||||
* Variants
|
||||
* Examples
|
||||
|
||||
Sometimes more than one declaration is needed to implement what the user
|
||||
sees as a single tactic. In that case, only one declaration should have
|
||||
the associated docstring, and the others should have the `tactic_alt`
|
||||
attribute to mark them as an implementation detail.
|
||||
|
||||
The **short summary** should be 1–3 sentences (ideally 1) and provide
|
||||
enough information for most readers to quickly decide whether the
|
||||
tactic is relevant to their task. The first (or only) sentence of
|
||||
the short summary should be a full sentence in which the subject
|
||||
is an example invocation of the tactic, written in present tense
|
||||
indicative. If the example tactic invocation names parameters, then the
|
||||
short summary may refer to them. For the example invocation, prefer the
|
||||
simplest or most typical example. Explain more complicated forms in the
|
||||
variants section. If needed, abbreviate the invocation by naming part of
|
||||
the syntax and expanding it in the next sentence. The summary should be
|
||||
written as a single paragraph.
|
||||
|
||||
**Details**, if needed, may be 1-3 paragraphs that describe further
|
||||
relevant information. They may insert links as needed. This section
|
||||
should fully explain the scope of the tactic: its syntax format,
|
||||
on which goals it works and what the resulting goal(s) look like. It
|
||||
should be clear whether the tactic fails if it does not close the main
|
||||
goal and whether it creates any side goals. The details may include
|
||||
explanatory examples that can’t necessarily be machine checked and
|
||||
don’t fit the format.
|
||||
|
||||
If the tactic is extensible using `macro_rules`, mention this in the
|
||||
details, with a link to `lean-manual://section/tactic-macro-extension`
|
||||
and give a one-line example. If the tactic provides an attribute or a
|
||||
command that allows the user to extend its behavior, the documentation
|
||||
on how to extend the tactic belongs to that attribute or command. In the
|
||||
tactic docstring, use a single sentence to refer the reader to this
|
||||
further documentation.
|
||||
|
||||
**Variants**, if needed, should be a bulleted list describing different
|
||||
options and forms of the same tactic. The reader should be able to parse
|
||||
and understand the parts of a tactic invocation they are hovering over,
|
||||
using this list. Each list item should describe an individual variant
|
||||
and take one of two formats: the **short summary** as above, or a
|
||||
**named list item**. A named list item consists of a title in bold
|
||||
followed by an indented short paragraph.
|
||||
|
||||
Variants should be explained from the perspective of the tactic's users, not
|
||||
their implementers. A tactic that is implemented as a single Lean parser may
|
||||
have multiple variants from the perspective of users, while a tactic that is
|
||||
implemented as multiple parsers may have no variants, but merely an optional
|
||||
part of the syntax.
|
||||
|
||||
**Examples** should start with the line `Examples:` (or `Example:` if
|
||||
there’s exactly one). The section should consist of a sequence of code
|
||||
blocks, each showing a Lean declaration (usually with the `example`
|
||||
keyword) that invokes the tactic. When the effect of the tactic is not
|
||||
clear from the code, you can use code comments to describe this. Do
|
||||
not include text between examples, because it can be unclear whether
|
||||
the text refers to the code before or after the example.
|
||||
|
||||
##### Example
|
||||
|
||||
````
|
||||
`rw [e]` uses the expression `e` as a rewrite rule on the main goal,
|
||||
then tries to close the goal by "cheap" (reducible) `rfl`.
|
||||
|
||||
If `e` is a defined constant, then the equational theorems associated with `e`
|
||||
are used. This provides a convenient way to unfold `e`. If `e` has parameters,
|
||||
the tactic will try to fill these in by unification with the matching part of
|
||||
the target. Parameters are only filled in once per rule, restricting which
|
||||
later rewrites can be found. Parameters that are not filled in after
|
||||
unification will create side goals. If the `rfl` fails to close the main goal,
|
||||
no error is raised.
|
||||
|
||||
`rw` may fail to rewrite terms "under binders", such as `∀ x, ...` or `∃ x,
|
||||
...`. `rw` can also fail with a "motive is type incorrect" error in the context
|
||||
of dependent types. In these cases, consider using `simp only`.
|
||||
|
||||
* `rw [e₁, ... eₙ]` applies the given rules sequentially.
|
||||
* `rw [← e]` or `rw [<- e]` applies the rewrite in the reverse direction.
|
||||
* `rw [e] at l` rewrites with `e` at location(s) `l`.
|
||||
* `rw (occs := .pos L) [e]`, where `L` is a literal list of natural numbers,
|
||||
only rewrites the given occurrences in the target. Occurrences count from 1.
|
||||
* `rw (occs := .neg L) [e]`, where `L` is a literal list of natural numbers,
|
||||
skips rewriting the given occurrences in the target. Occurrences count from 1.
|
||||
|
||||
Examples:
|
||||
|
||||
```lean
|
||||
example {a b : Nat} (h : a + a = b) : (a + a) + (a + a) = b + b := by rw [h]
|
||||
```
|
||||
|
||||
```lean
|
||||
example {f : Nat -> Nat} (h : ∀ x, f x = 1) (a b : Nat) : f a = f b := by
|
||||
rw [h] -- `rw` instantiates `h` only once, so this is equivalent to: `rw [h a]`
|
||||
-- goal: ⊢ 1 = f b
|
||||
rw [h] -- equivalent to: `rw [h b]`
|
||||
```
|
||||
````
|
||||
|
||||
|
||||
## Dictionary
|
||||
|
||||
@@ -285,7 +285,9 @@ def isDeclMeta' (env : Environment) (declName : Name) : Bool :=
|
||||
-- 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
|
||||
-- `isMarkedMeta` knows about non-defs such as `meta structure`, isDeclMeta knows about decls
|
||||
-- implicitly marked meta
|
||||
isMarkedMeta env inferFor || isDeclMeta env inferFor
|
||||
|
||||
/--
|
||||
Given an `Expr` reference, returns the declaration name that should be considered the reference, if
|
||||
@@ -336,12 +338,14 @@ where
|
||||
deps := deps.union k {indMod}
|
||||
return deps
|
||||
|
||||
abbrev Explanations := Std.HashMap (ModuleIdx × NeedsKind) (Option (Name × Name))
|
||||
|
||||
/--
|
||||
Calculates the same as `calcNeeds` but tracing each module to a use-def declaration pair or
|
||||
`none` if merely a recorded extra use.
|
||||
-/
|
||||
def getExplanations (env : Environment) (i : ModuleIdx) :
|
||||
Std.HashMap (ModuleIdx × NeedsKind) (Option (Name × Name)) := Id.run do
|
||||
def getExplanations (s : State) (i : ModuleIdx) : Explanations := Id.run do
|
||||
let env := s.env
|
||||
let mut deps := default
|
||||
for ci in env.header.moduleData[i]!.constants do
|
||||
-- Added guard for cases like `structure` that are still exported even if private
|
||||
@@ -362,18 +366,25 @@ def getExplanations (env : Environment) (i : ModuleIdx) :
|
||||
where
|
||||
/-- Accumulate the results from expression `e` into `deps`. -/
|
||||
visitExpr (k : NeedsKind) name e deps :=
|
||||
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
|
||||
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)
|
||||
deps := addExplanation j k name c deps
|
||||
for indMod in (indirectModUseExt.getState env)[c]?.getD #[] do
|
||||
if s.transDeps[i]!.has k indMod then
|
||||
deps := addExplanation indMod k name (`_indirect ++ c) deps
|
||||
return deps
|
||||
addExplanation (j : ModuleIdx) (k : NeedsKind) (use def_ : Name) (deps : Explanations) : Explanations :=
|
||||
if
|
||||
if let some (some (name', _)) := deps[(j, k)]? then
|
||||
decide (use.toString.length < name'.toString.length)
|
||||
else true
|
||||
then
|
||||
deps.insert (j, k) (use, def_)
|
||||
else deps
|
||||
|
||||
partial def initStateFromEnv (env : Environment) : State := Id.run do
|
||||
let mut s := { env }
|
||||
@@ -540,7 +551,7 @@ def visitModule (pkg : Name) (srcSearchPath : SearchPath)
|
||||
let mut imp : Import := { k with module := s.modNames[j]! }
|
||||
let mut j := j
|
||||
if args.trace then
|
||||
IO.eprintln s!"`{imp}` is needed"
|
||||
IO.eprintln s!"`{imp}` is needed{if needs.has k j then " (calculated)" else ""}"
|
||||
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
|
||||
@@ -658,7 +669,7 @@ def visitModule (pkg : Name) (srcSearchPath : SearchPath)
|
||||
modify fun s => { s with transDeps := s.transDeps.set! i newTransDepsI }
|
||||
|
||||
if args.explain then
|
||||
let explanation := getExplanations s.env i
|
||||
let explanation := getExplanations s 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!
|
||||
|
||||
441
script/build_artifact.py
Executable file
441
script/build_artifact.py
Executable file
@@ -0,0 +1,441 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
build_artifact.py: Download pre-built CI artifacts for a Lean commit.
|
||||
|
||||
Usage:
|
||||
build_artifact.py # Download artifact for current HEAD
|
||||
build_artifact.py --sha abc1234 # Download artifact for specific commit
|
||||
build_artifact.py --clear-cache # Clear artifact cache
|
||||
|
||||
This script downloads pre-built binaries from GitHub Actions CI runs,
|
||||
which is much faster than building from source (~30s vs 2-5min).
|
||||
|
||||
Artifacts are cached in ~/.cache/lean_build_artifact/ for reuse.
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import os
|
||||
import platform
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
import urllib.request
|
||||
import urllib.error
|
||||
from pathlib import Path
|
||||
from typing import Optional
|
||||
|
||||
# Constants
|
||||
GITHUB_API_BASE = "https://api.github.com"
|
||||
LEAN4_REPO = "leanprover/lean4"
|
||||
|
||||
# CI artifact cache
|
||||
CACHE_DIR = Path.home() / '.cache' / 'lean_build_artifact'
|
||||
ARTIFACT_CACHE = CACHE_DIR
|
||||
|
||||
# Sentinel value indicating CI failed (don't bother building locally)
|
||||
CI_FAILED = object()
|
||||
|
||||
# ANSI colors for terminal output
|
||||
class Colors:
|
||||
RED = '\033[91m'
|
||||
GREEN = '\033[92m'
|
||||
YELLOW = '\033[93m'
|
||||
BLUE = '\033[94m'
|
||||
BOLD = '\033[1m'
|
||||
RESET = '\033[0m'
|
||||
|
||||
def color(text: str, c: str) -> str:
|
||||
"""Apply color to text if stdout is a tty."""
|
||||
if sys.stdout.isatty():
|
||||
return f"{c}{text}{Colors.RESET}"
|
||||
return text
|
||||
|
||||
def error(msg: str) -> None:
|
||||
"""Print error message and exit."""
|
||||
print(color(f"Error: {msg}", Colors.RED), file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
def warn(msg: str) -> None:
|
||||
"""Print warning message."""
|
||||
print(color(f"Warning: {msg}", Colors.YELLOW), file=sys.stderr)
|
||||
|
||||
def info(msg: str) -> None:
|
||||
"""Print info message."""
|
||||
print(color(msg, Colors.BLUE), file=sys.stderr)
|
||||
|
||||
def success(msg: str) -> None:
|
||||
"""Print success message."""
|
||||
print(color(msg, Colors.GREEN), file=sys.stderr)
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Platform detection
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
def get_artifact_name() -> Optional[str]:
|
||||
"""Get CI artifact name for current platform."""
|
||||
system = platform.system()
|
||||
machine = platform.machine()
|
||||
|
||||
if system == 'Darwin':
|
||||
if machine == 'arm64':
|
||||
return 'build-macOS aarch64'
|
||||
return 'build-macOS' # Intel
|
||||
elif system == 'Linux':
|
||||
if machine == 'aarch64':
|
||||
return 'build-Linux aarch64'
|
||||
return 'build-Linux release'
|
||||
# Windows not supported for CI artifact download
|
||||
return None
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# GitHub API helpers
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
_github_token_warning_shown = False
|
||||
|
||||
def get_github_token() -> Optional[str]:
|
||||
"""Get GitHub token from environment or gh CLI."""
|
||||
global _github_token_warning_shown
|
||||
|
||||
# Check environment variable first
|
||||
token = os.environ.get('GITHUB_TOKEN')
|
||||
if token:
|
||||
return token
|
||||
|
||||
# Try to get token from gh CLI
|
||||
try:
|
||||
result = subprocess.run(
|
||||
['gh', 'auth', 'token'],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
timeout=5
|
||||
)
|
||||
if result.returncode == 0 and result.stdout.strip():
|
||||
return result.stdout.strip()
|
||||
except (FileNotFoundError, subprocess.TimeoutExpired):
|
||||
pass
|
||||
|
||||
# Warn once if no token available
|
||||
if not _github_token_warning_shown:
|
||||
_github_token_warning_shown = True
|
||||
warn("No GitHub authentication found. API rate limits may apply.")
|
||||
warn("Run 'gh auth login' or set GITHUB_TOKEN to avoid rate limiting.")
|
||||
|
||||
return None
|
||||
|
||||
def github_api_request(url: str) -> dict:
|
||||
"""Make a GitHub API request and return JSON response."""
|
||||
headers = {
|
||||
'Accept': 'application/vnd.github.v3+json',
|
||||
'User-Agent': 'build-artifact'
|
||||
}
|
||||
|
||||
token = get_github_token()
|
||||
if token:
|
||||
headers['Authorization'] = f'token {token}'
|
||||
|
||||
req = urllib.request.Request(url, headers=headers)
|
||||
try:
|
||||
with urllib.request.urlopen(req, timeout=30) as response:
|
||||
return json.loads(response.read().decode())
|
||||
except urllib.error.HTTPError as e:
|
||||
if e.code == 403:
|
||||
error(f"GitHub API rate limit exceeded. Set GITHUB_TOKEN environment variable to increase limit.")
|
||||
elif e.code == 404:
|
||||
error(f"GitHub resource not found: {url}")
|
||||
else:
|
||||
error(f"GitHub API error: {e.code} {e.reason}")
|
||||
except urllib.error.URLError as e:
|
||||
error(f"Network error accessing GitHub API: {e.reason}")
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# CI artifact cache functions
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
def get_cache_path(sha: str) -> Path:
|
||||
"""Get cache directory for a commit's artifact."""
|
||||
return ARTIFACT_CACHE / sha[:12]
|
||||
|
||||
def is_cached(sha: str) -> bool:
|
||||
"""Check if artifact for this commit is already cached and valid."""
|
||||
cache_path = get_cache_path(sha)
|
||||
return cache_path.exists() and (cache_path / 'bin' / 'lean').exists()
|
||||
|
||||
def check_zstd_support() -> bool:
|
||||
"""Check if tar supports zstd compression."""
|
||||
try:
|
||||
result = subprocess.run(
|
||||
['tar', '--zstd', '--version'],
|
||||
capture_output=True,
|
||||
timeout=5
|
||||
)
|
||||
return result.returncode == 0
|
||||
except (subprocess.TimeoutExpired, FileNotFoundError):
|
||||
return False
|
||||
|
||||
def check_gh_available() -> bool:
|
||||
"""Check if gh CLI is available and authenticated."""
|
||||
try:
|
||||
result = subprocess.run(
|
||||
['gh', 'auth', 'status'],
|
||||
capture_output=True,
|
||||
timeout=10
|
||||
)
|
||||
return result.returncode == 0
|
||||
except (subprocess.TimeoutExpired, FileNotFoundError):
|
||||
return False
|
||||
|
||||
def download_ci_artifact(sha: str, quiet: bool = False):
|
||||
"""
|
||||
Try to download CI artifact for a commit.
|
||||
Returns:
|
||||
- Path to extracted toolchain directory if available
|
||||
- CI_FAILED sentinel if CI run failed (don't bother building locally)
|
||||
- None if no artifact available but local build might work
|
||||
"""
|
||||
# Check cache first
|
||||
if is_cached(sha):
|
||||
return get_cache_path(sha)
|
||||
|
||||
artifact_name = get_artifact_name()
|
||||
if artifact_name is None:
|
||||
return None # Unsupported platform
|
||||
|
||||
cache_path = get_cache_path(sha)
|
||||
|
||||
try:
|
||||
# Query for CI workflow run for this commit, including status
|
||||
# Note: Query parameters must be in the URL for GET requests
|
||||
result = subprocess.run(
|
||||
['gh', 'api', f'repos/{LEAN4_REPO}/actions/runs?head_sha={sha}&per_page=100',
|
||||
'--jq', r'.workflow_runs[] | select(.name == "CI") | "\(.id) \(.conclusion // "null")"'],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
timeout=30
|
||||
)
|
||||
if result.returncode != 0 or not result.stdout.strip():
|
||||
return None # No CI run found (old commit?)
|
||||
|
||||
# Parse "run_id conclusion" format
|
||||
line = result.stdout.strip().split('\n')[0]
|
||||
parts = line.split(' ', 1)
|
||||
run_id = parts[0]
|
||||
conclusion = parts[1] if len(parts) > 1 else "null"
|
||||
|
||||
# Check if the desired artifact exists for this run
|
||||
result = subprocess.run(
|
||||
['gh', 'api', f'repos/{LEAN4_REPO}/actions/runs/{run_id}/artifacts',
|
||||
'--jq', f'.artifacts[] | select(.name == "{artifact_name}") | .id'],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
timeout=30
|
||||
)
|
||||
if result.returncode != 0 or not result.stdout.strip():
|
||||
# No artifact available
|
||||
# If CI failed and no artifact, the build itself likely failed - skip
|
||||
if conclusion == "failure":
|
||||
return CI_FAILED
|
||||
# Otherwise (in progress, expired, etc.) - fall back to local build
|
||||
return None
|
||||
|
||||
# Download artifact
|
||||
cache_path.mkdir(parents=True, exist_ok=True)
|
||||
if not quiet:
|
||||
print("downloading CI artifact... ", end='', flush=True)
|
||||
|
||||
result = subprocess.run(
|
||||
['gh', 'run', 'download', run_id,
|
||||
'-n', artifact_name,
|
||||
'-R', LEAN4_REPO,
|
||||
'-D', str(cache_path)],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
timeout=600 # 10 minutes for large downloads
|
||||
)
|
||||
|
||||
if result.returncode != 0:
|
||||
shutil.rmtree(cache_path, ignore_errors=True)
|
||||
return None
|
||||
|
||||
# Extract tar.zst - find the file (name varies by platform/version)
|
||||
tar_files = list(cache_path.glob('*.tar.zst'))
|
||||
if not tar_files:
|
||||
shutil.rmtree(cache_path, ignore_errors=True)
|
||||
return None
|
||||
|
||||
tar_file = tar_files[0]
|
||||
if not quiet:
|
||||
print("extracting... ", end='', flush=True)
|
||||
|
||||
result = subprocess.run(
|
||||
['tar', '--zstd', '-xf', tar_file.name],
|
||||
cwd=cache_path,
|
||||
capture_output=True,
|
||||
timeout=300
|
||||
)
|
||||
|
||||
if result.returncode != 0:
|
||||
shutil.rmtree(cache_path, ignore_errors=True)
|
||||
return None
|
||||
|
||||
# Move contents up from lean-VERSION-PLATFORM/ to cache_path/
|
||||
# The extracted directory name varies (e.g., lean-4.15.0-linux, lean-4.15.0-darwin_aarch64)
|
||||
extracted_dirs = [d for d in cache_path.iterdir() if d.is_dir() and d.name.startswith('lean-')]
|
||||
if extracted_dirs:
|
||||
extracted = extracted_dirs[0]
|
||||
for item in extracted.iterdir():
|
||||
dest = cache_path / item.name
|
||||
if dest.exists():
|
||||
if dest.is_dir():
|
||||
shutil.rmtree(dest)
|
||||
else:
|
||||
dest.unlink()
|
||||
shutil.move(str(item), str(cache_path / item.name))
|
||||
extracted.rmdir()
|
||||
|
||||
# Clean up tar file
|
||||
tar_file.unlink()
|
||||
|
||||
# Verify the extraction worked
|
||||
if not (cache_path / 'bin' / 'lean').exists():
|
||||
shutil.rmtree(cache_path, ignore_errors=True)
|
||||
return None
|
||||
|
||||
return cache_path
|
||||
|
||||
except (subprocess.TimeoutExpired, FileNotFoundError):
|
||||
shutil.rmtree(cache_path, ignore_errors=True)
|
||||
return None
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Git helpers
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
def get_current_commit() -> str:
|
||||
"""Get the current git HEAD commit SHA."""
|
||||
try:
|
||||
result = subprocess.run(
|
||||
['git', 'rev-parse', 'HEAD'],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
timeout=5
|
||||
)
|
||||
if result.returncode == 0:
|
||||
return result.stdout.strip()
|
||||
error(f"Failed to get current commit: {result.stderr.strip()}")
|
||||
except subprocess.TimeoutExpired:
|
||||
error("Timeout getting current commit")
|
||||
except FileNotFoundError:
|
||||
error("git not found")
|
||||
|
||||
def resolve_sha(short_sha: str) -> str:
|
||||
"""Resolve a (possibly short) SHA to full 40-character SHA using git rev-parse."""
|
||||
if len(short_sha) == 40:
|
||||
return short_sha
|
||||
try:
|
||||
result = subprocess.run(
|
||||
['git', 'rev-parse', short_sha],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
timeout=5
|
||||
)
|
||||
if result.returncode == 0:
|
||||
full_sha = result.stdout.strip()
|
||||
if len(full_sha) == 40:
|
||||
return full_sha
|
||||
error(f"Cannot resolve SHA '{short_sha}': {result.stderr.strip() or 'not found in repository'}")
|
||||
except subprocess.TimeoutExpired:
|
||||
error(f"Timeout resolving SHA '{short_sha}'")
|
||||
except FileNotFoundError:
|
||||
error("git not found - required for SHA resolution")
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Main
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(
|
||||
description='Download pre-built CI artifacts for a Lean commit.',
|
||||
formatter_class=argparse.RawDescriptionHelpFormatter,
|
||||
epilog="""
|
||||
This script downloads pre-built binaries from GitHub Actions CI runs,
|
||||
which is much faster than building from source (~30s vs 2-5min).
|
||||
|
||||
Artifacts are cached in ~/.cache/lean_build_artifact/ for reuse.
|
||||
|
||||
Examples:
|
||||
build_artifact.py # Download for current HEAD
|
||||
build_artifact.py --sha abc1234 # Download for specific commit
|
||||
build_artifact.py --clear-cache # Clear cache to free disk space
|
||||
"""
|
||||
)
|
||||
|
||||
parser.add_argument('--sha', metavar='SHA',
|
||||
help='Commit SHA to download artifact for (default: current HEAD)')
|
||||
parser.add_argument('--clear-cache', action='store_true',
|
||||
help='Clear artifact cache and exit')
|
||||
parser.add_argument('--quiet', '-q', action='store_true',
|
||||
help='Suppress progress messages (still prints result path)')
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
# Handle cache clearing
|
||||
if args.clear_cache:
|
||||
if ARTIFACT_CACHE.exists():
|
||||
size = sum(f.stat().st_size for f in ARTIFACT_CACHE.rglob('*') if f.is_file())
|
||||
shutil.rmtree(ARTIFACT_CACHE)
|
||||
info(f"Cleared cache at {ARTIFACT_CACHE} ({size / 1024 / 1024:.1f} MB)")
|
||||
else:
|
||||
info(f"Cache directory does not exist: {ARTIFACT_CACHE}")
|
||||
return
|
||||
|
||||
# Get commit SHA
|
||||
if args.sha:
|
||||
sha = resolve_sha(args.sha)
|
||||
else:
|
||||
sha = get_current_commit()
|
||||
|
||||
if not args.quiet:
|
||||
info(f"Commit: {sha[:12]}")
|
||||
|
||||
# Check prerequisites
|
||||
if not check_gh_available():
|
||||
error("gh CLI not available or not authenticated. Run 'gh auth login' first.")
|
||||
|
||||
if not check_zstd_support():
|
||||
error("tar does not support zstd compression. Install zstd or a newer tar.")
|
||||
|
||||
artifact_name = get_artifact_name()
|
||||
if artifact_name is None:
|
||||
error(f"No CI artifacts available for this platform ({platform.system()} {platform.machine()})")
|
||||
|
||||
if not args.quiet:
|
||||
info(f"Platform: {artifact_name}")
|
||||
|
||||
# Check cache
|
||||
if is_cached(sha):
|
||||
path = get_cache_path(sha)
|
||||
if not args.quiet:
|
||||
success("Using cached artifact")
|
||||
print(path)
|
||||
return
|
||||
|
||||
# Download artifact
|
||||
result = download_ci_artifact(sha, quiet=args.quiet)
|
||||
|
||||
if result is CI_FAILED:
|
||||
if not args.quiet:
|
||||
print() # End the "downloading..." line
|
||||
error(f"CI build failed for commit {sha[:12]}")
|
||||
elif result is None:
|
||||
if not args.quiet:
|
||||
print() # End the "downloading..." line
|
||||
error(f"No CI artifact available for commit {sha[:12]}")
|
||||
else:
|
||||
if not args.quiet:
|
||||
print(color("done", Colors.GREEN))
|
||||
print(result)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
1290
script/lean-bisect
Executable file
1290
script/lean-bisect
Executable file
File diff suppressed because it is too large
Load Diff
307
script/lean-bisect-test.lean
Normal file
307
script/lean-bisect-test.lean
Normal file
@@ -0,0 +1,307 @@
|
||||
/-
|
||||
Copyright Strata Contributors
|
||||
|
||||
SPDX-License-Identifier: Apache-2.0 OR MIT
|
||||
-/
|
||||
|
||||
namespace Strata
|
||||
namespace Python
|
||||
|
||||
/-
|
||||
Parser and translator for some basic regular expression patterns supported by
|
||||
Python's `re` library
|
||||
Ref.: https://docs.python.org/3/library/re.html
|
||||
|
||||
Also see
|
||||
https://github.com/python/cpython/blob/759a048d4bea522fda2fe929be0fba1650c62b0e/Lib/re/_parser.py
|
||||
for a reference implementation.
|
||||
-/
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
inductive ParseError where
|
||||
/--
|
||||
`patternError` is raised when Python's `re.patternError` exception is
|
||||
raised.
|
||||
[Reference: Python's re exceptions](https://docs.python.org/3/library/re.html#exceptions):
|
||||
|
||||
"Exception raised when a string passed to one of the functions here is not a
|
||||
valid regular expression (for example, it might contain unmatched
|
||||
parentheses) or when some other error occurs during compilation or matching.
|
||||
It is never an error if a string contains no match for a pattern."
|
||||
-/
|
||||
| patternError (message : String) (pattern : String) (pos : String.Pos.Raw)
|
||||
/--
|
||||
`unimplemented` is raised whenever we don't support some regex operations
|
||||
(e.g., lookahead assertions).
|
||||
-/
|
||||
| unimplemented (message : String) (pattern : String) (pos : String.Pos.Raw)
|
||||
deriving Repr
|
||||
|
||||
def ParseError.toString : ParseError → String
|
||||
| .patternError msg pat pos => s!"Pattern error at position {pos.byteIdx}: {msg} in pattern '{pat}'"
|
||||
| .unimplemented msg pat pos => s!"Unimplemented at position {pos.byteIdx}: {msg} in pattern '{pat}'"
|
||||
|
||||
instance : ToString ParseError where
|
||||
toString := ParseError.toString
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
/--
|
||||
Regular Expression Nodes
|
||||
-/
|
||||
inductive RegexAST where
|
||||
/-- Single literal character: `a` -/
|
||||
| char : Char → RegexAST
|
||||
/-- Character range: `[a-z]` -/
|
||||
| range : Char → Char → RegexAST
|
||||
/-- Alternation: `a|b` -/
|
||||
| union : RegexAST → RegexAST → RegexAST
|
||||
/-- Concatenation: `ab` -/
|
||||
| concat : RegexAST → RegexAST → RegexAST
|
||||
/-- Any character: `.` -/
|
||||
| anychar : RegexAST
|
||||
/-- Zero or more: `a*` -/
|
||||
| star : RegexAST → RegexAST
|
||||
/-- One or more: `a+` -/
|
||||
| plus : RegexAST → RegexAST
|
||||
/-- Zero or one: `a?` -/
|
||||
| optional : RegexAST → RegexAST
|
||||
/-- Bounded repetition: `a{n,m}` -/
|
||||
| loop : RegexAST → Nat → Nat → RegexAST
|
||||
/-- Start of string: `^` -/
|
||||
| anchor_start : RegexAST
|
||||
/-- End of string: `$` -/
|
||||
| anchor_end : RegexAST
|
||||
/-- Grouping: `(abc)` -/
|
||||
| group : RegexAST → RegexAST
|
||||
/-- Empty string: `()` or `""` -/
|
||||
| empty : RegexAST
|
||||
/-- Complement: `[^a-z]` -/
|
||||
| complement : RegexAST → RegexAST
|
||||
deriving Inhabited, Repr
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
/-- Parse character class like [a-z], [0-9], etc. into union of ranges and
|
||||
chars. Note that this parses `|` as a character. -/
|
||||
def parseCharClass (s : String) (pos : String.Pos.Raw) : Except ParseError (RegexAST × String.Pos.Raw) := do
|
||||
if pos.get? s != some '[' then throw (.patternError "Expected '[' at start of character class" s pos)
|
||||
let mut i := pos.next s
|
||||
|
||||
-- Check for complement (negation) with leading ^
|
||||
let isComplement := !i.atEnd s && i.get? s == some '^'
|
||||
if isComplement then
|
||||
i := i.next s
|
||||
|
||||
let mut result : Option RegexAST := none
|
||||
|
||||
-- Process each element in the character class.
|
||||
while !i.atEnd s && i.get? s != some ']' do
|
||||
-- Uncommenting this makes the code stop
|
||||
--dbg_trace "Working" (pure ())
|
||||
let some c1 := i.get? s | throw (.patternError "Invalid character in class" s i)
|
||||
let i1 := i.next s
|
||||
-- Check for range pattern: c1-c2.
|
||||
if !i1.atEnd s && i1.get? s == some '-' then
|
||||
let i2 := i1.next s
|
||||
if !i2.atEnd s && i2.get? s != some ']' then
|
||||
let some c2 := i2.get? s | throw (.patternError "Invalid character in range" s i2)
|
||||
if c1 > c2 then
|
||||
throw (.patternError s!"Invalid character range [{c1}-{c2}]: \
|
||||
start character '{c1}' is greater than end character '{c2}'" s i)
|
||||
let r := RegexAST.range c1 c2
|
||||
-- Union with previous elements.
|
||||
result := some (match result with | none => r | some prev => RegexAST.union prev r)
|
||||
i := i2.next s
|
||||
continue
|
||||
-- Single character.
|
||||
let r := RegexAST.char c1
|
||||
result := some (match result with | none => r | some prev => RegexAST.union prev r)
|
||||
i := i.next s
|
||||
|
||||
let some ast := result | throw (.patternError "Unterminated character set" s pos)
|
||||
let finalAst := if isComplement then RegexAST.complement ast else ast
|
||||
pure (finalAst, i.next s)
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
/-- Parse numeric repeats like `{10}` or `{1,10}` into min and max bounds. -/
|
||||
def parseBounds (s : String) (pos : String.Pos.Raw) : Except ParseError (Nat × Nat × String.Pos.Raw) := do
|
||||
if pos.get? s != some '{' then throw (.patternError "Expected '{' at start of bounds" s pos)
|
||||
let mut i := pos.next s
|
||||
let mut numStr := ""
|
||||
|
||||
-- Parse first number.
|
||||
while !i.atEnd s && (i.get? s).any Char.isDigit do
|
||||
numStr := numStr.push ((i.get? s).get!)
|
||||
i := i.next s
|
||||
|
||||
let some n := numStr.toNat? | throw (.patternError "Invalid minimum bound" s pos)
|
||||
|
||||
-- Check for comma (range) or closing brace (exact count).
|
||||
match i.get? s with
|
||||
| some '}' => pure (n, n, i.next s) -- {n} means exactly n times.
|
||||
| some ',' =>
|
||||
i := i.next s
|
||||
-- Parse maximum bound
|
||||
numStr := ""
|
||||
while !i.atEnd s && (i.get? s).any Char.isDigit do
|
||||
numStr := numStr.push ((i.get? s).get!)
|
||||
i := i.next s
|
||||
let some max := numStr.toNat? | throw (.patternError "Invalid maximum bound" s i)
|
||||
if i.get? s != some '}' then throw (.patternError "Expected '}' at end of bounds" s i)
|
||||
-- Validate bounds order
|
||||
if max < n then
|
||||
throw (.patternError s!"Invalid repeat bounds \{{n},{max}}: \
|
||||
maximum {max} is less than minimum {n}" s pos)
|
||||
pure (n, max, i.next s)
|
||||
| _ => throw (.patternError "Invalid bounds syntax" s i)
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
mutual
|
||||
/--
|
||||
Parse atom: single element (char, class, anchor, group) with optional
|
||||
quantifier. Stops at the first `|`.
|
||||
-/
|
||||
partial def parseAtom (s : String) (pos : String.Pos.Raw) : Except ParseError (RegexAST × String.Pos.Raw) := do
|
||||
if pos.atEnd s then throw (.patternError "Unexpected end of regex" s pos)
|
||||
|
||||
let some c := pos.get? s | throw (.patternError "Invalid position" s pos)
|
||||
|
||||
-- Detect invalid quantifier at start
|
||||
if c == '*' || c == '+' || c == '{' || c == '?' then
|
||||
throw (.patternError s!"Quantifier '{c}' at position {pos} has nothing to quantify" s pos)
|
||||
|
||||
-- Detect unbalanced closing parenthesis
|
||||
if c == ')' then
|
||||
throw (.patternError "Unbalanced parenthesis" s pos)
|
||||
|
||||
-- Parse base element (anchor, char class, group, anychar, escape, or single char).
|
||||
let (base, nextPos) ← match c with
|
||||
| '^' => pure (RegexAST.anchor_start, pos.next s)
|
||||
| '$' => pure (RegexAST.anchor_end, pos.next s)
|
||||
| '[' => parseCharClass s pos
|
||||
| '(' => parseExplicitGroup s pos
|
||||
| '.' => pure (RegexAST.anychar, pos.next s)
|
||||
| '\\' =>
|
||||
-- Handle escape sequence.
|
||||
-- Note: Python uses a single backslash as an escape character, but Lean
|
||||
-- strings need to escape that. After DDMification, we will see two
|
||||
-- backslashes in Strata for every Python backslash.
|
||||
let nextPos := pos.next s
|
||||
if nextPos.atEnd s then throw (.patternError "Incomplete escape sequence at end of regex" s pos)
|
||||
let some escapedChar := nextPos.get? s | throw (.patternError "Invalid escape position" s nextPos)
|
||||
-- Check for special sequences (unsupported right now).
|
||||
match escapedChar with
|
||||
| 'A' | 'b' | 'B' | 'd' | 'D' | 's' | 'S' | 'w' | 'W' | 'z' | 'Z' =>
|
||||
throw (.unimplemented s!"Special sequence \\{escapedChar} is not supported" s pos)
|
||||
| 'a' | 'f' | 'n' | 'N' | 'r' | 't' | 'u' | 'U' | 'v' | 'x' =>
|
||||
throw (.unimplemented s!"Escape sequence \\{escapedChar} is not supported" s pos)
|
||||
| c =>
|
||||
if c.isDigit then
|
||||
throw (.unimplemented s!"Backreference \\{c} is not supported" s pos)
|
||||
else
|
||||
pure (RegexAST.char escapedChar, nextPos.next s)
|
||||
| _ => pure (RegexAST.char c, pos.next s)
|
||||
|
||||
-- Check for numeric repeat suffix on base element (but not on anchors)
|
||||
match base with
|
||||
| .anchor_start | .anchor_end => pure (base, nextPos)
|
||||
| _ =>
|
||||
if !nextPos.atEnd s then
|
||||
match nextPos.get? s with
|
||||
| some '{' =>
|
||||
let (min, max, finalPos) ← parseBounds s nextPos
|
||||
pure (RegexAST.loop base min max, finalPos)
|
||||
| some '*' =>
|
||||
let afterStar := nextPos.next s
|
||||
if !afterStar.atEnd s then
|
||||
match afterStar.get? s with
|
||||
| some '?' => throw (.unimplemented "Non-greedy quantifier *? is not supported" s nextPos)
|
||||
| some '+' => throw (.unimplemented "Possessive quantifier *+ is not supported" s nextPos)
|
||||
| _ => pure (RegexAST.star base, afterStar)
|
||||
else pure (RegexAST.star base, afterStar)
|
||||
| some '+' =>
|
||||
let afterPlus := nextPos.next s
|
||||
if !afterPlus.atEnd s then
|
||||
match afterPlus.get? s with
|
||||
| some '?' => throw (.unimplemented "Non-greedy quantifier +? is not supported" s nextPos)
|
||||
| some '+' => throw (.unimplemented "Possessive quantifier ++ is not supported" s nextPos)
|
||||
| _ => pure (RegexAST.plus base, afterPlus)
|
||||
else pure (RegexAST.plus base, afterPlus)
|
||||
| some '?' =>
|
||||
let afterQuestion := nextPos.next s
|
||||
if !afterQuestion.atEnd s then
|
||||
match afterQuestion.get? s with
|
||||
| some '?' => throw (.unimplemented "Non-greedy quantifier ?? is not supported" s nextPos)
|
||||
| some '+' => throw (.unimplemented "Possessive quantifier ?+ is not supported" s nextPos)
|
||||
| _ => pure (RegexAST.optional base, afterQuestion)
|
||||
else pure (RegexAST.optional base, afterQuestion)
|
||||
| _ => pure (base, nextPos)
|
||||
else
|
||||
pure (base, nextPos)
|
||||
|
||||
/-- Parse explicit group with parentheses. -/
|
||||
partial def parseExplicitGroup (s : String) (pos : String.Pos.Raw) : Except ParseError (RegexAST × String.Pos.Raw) := do
|
||||
if pos.get? s != some '(' then throw (.patternError "Expected '(' at start of group" s pos)
|
||||
let mut i := pos.next s
|
||||
|
||||
-- Check for extension notation (?...
|
||||
if !i.atEnd s && i.get? s == some '?' then
|
||||
let i1 := i.next s
|
||||
if !i1.atEnd s then
|
||||
match i1.get? s with
|
||||
| some '=' => throw (.unimplemented "Positive lookahead (?=...) is not supported" s pos)
|
||||
| some '!' => throw (.unimplemented "Negative lookahead (?!...) is not supported" s pos)
|
||||
| _ => throw (.unimplemented "Extension notation (?...) is not supported" s pos)
|
||||
|
||||
let (inner, finalPos) ← parseGroup s i (some ')')
|
||||
pure (.group inner, finalPos)
|
||||
|
||||
/-- Parse group: handles alternation and concatenation at current scope. -/
|
||||
partial def parseGroup (s : String) (pos : String.Pos.Raw) (endChar : Option Char) :
|
||||
Except ParseError (RegexAST × String.Pos.Raw) := do
|
||||
let mut alternatives : List (List RegexAST) := [[]]
|
||||
let mut i := pos
|
||||
|
||||
-- Parse until end of string or `endChar`.
|
||||
while !i.atEnd s && (endChar.isNone || i.get? s != endChar) do
|
||||
if i.get? s == some '|' then
|
||||
-- Push a new scope to `alternatives`.
|
||||
alternatives := [] :: alternatives
|
||||
i := i.next s
|
||||
else
|
||||
let (ast, nextPos) ← parseAtom s i
|
||||
alternatives := match alternatives with
|
||||
| [] => [[ast]]
|
||||
| head :: tail => (ast :: head) :: tail
|
||||
i := nextPos
|
||||
|
||||
-- Check for expected end character.
|
||||
if let some ec := endChar then
|
||||
if i.get? s != some ec then
|
||||
throw (.patternError s!"Expected '{ec}'" s i)
|
||||
i := i.next s
|
||||
|
||||
-- Build result: concatenate each alternative, then union them.
|
||||
let concatAlts := alternatives.reverse.filterMap fun alt =>
|
||||
match alt.reverse with
|
||||
| [] => -- Empty regex.
|
||||
some (.empty)
|
||||
| [single] => some single
|
||||
| head :: tail => some (tail.foldl RegexAST.concat head)
|
||||
|
||||
match concatAlts with
|
||||
| [] => pure (.empty, i)
|
||||
| [single] => pure (single, i)
|
||||
| head :: tail => pure (tail.foldl RegexAST.union head, i)
|
||||
end
|
||||
|
||||
/-- info: Except.ok (Strata.Python.RegexAST.range 'A' 'z', { byteIdx := 5 }) -/
|
||||
#guard_msgs in
|
||||
#eval parseCharClass "[A-z]" ⟨0⟩
|
||||
|
||||
-- Test code: Print done
|
||||
#print "Done!"
|
||||
@@ -50,12 +50,26 @@ repositories:
|
||||
dependencies:
|
||||
- lean4-cli
|
||||
|
||||
- name: lean4-unicode-basic
|
||||
url: https://github.com/fgdorais/lean4-unicode-basic
|
||||
toolchain-tag: true
|
||||
stable-branch: false
|
||||
branch: main
|
||||
dependencies: []
|
||||
|
||||
- name: BibtexQuery
|
||||
url: https://github.com/dupuisf/BibtexQuery
|
||||
toolchain-tag: true
|
||||
stable-branch: false
|
||||
branch: master
|
||||
dependencies: [lean4-unicode-basic]
|
||||
|
||||
- name: doc-gen4
|
||||
url: https://github.com/leanprover/doc-gen4
|
||||
toolchain-tag: true
|
||||
stable-branch: false
|
||||
branch: main
|
||||
dependencies: [lean4-cli]
|
||||
dependencies: [lean4-cli, BibtexQuery]
|
||||
|
||||
- name: reference-manual
|
||||
url: https://github.com/leanprover/reference-manual
|
||||
@@ -113,10 +127,30 @@ repositories:
|
||||
dependencies:
|
||||
- mathlib4
|
||||
|
||||
- name: verso-web-components
|
||||
url: https://github.com/leanprover/verso-web-components
|
||||
toolchain-tag: true
|
||||
stable-branch: false
|
||||
branch: main
|
||||
dependencies:
|
||||
- verso
|
||||
|
||||
- name: lean-fro.org
|
||||
url: https://github.com/leanprover/lean-fro.org
|
||||
toolchain-tag: false
|
||||
stable-branch: false
|
||||
branch: master
|
||||
dependencies:
|
||||
- verso
|
||||
- verso-web-components
|
||||
|
||||
- name: comparator
|
||||
url: https://github.com/leanprover/comparator
|
||||
toolchain-tag: true
|
||||
stable-branch: false
|
||||
branch: master
|
||||
|
||||
- name: lean4export
|
||||
url: https://github.com/leanprover/lean4export
|
||||
toolchain-tag: true
|
||||
stable-branch: false
|
||||
branch: master
|
||||
|
||||
@@ -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'")
|
||||
@@ -695,7 +695,7 @@ endif()
|
||||
|
||||
set(STDLIBS Init Std Lean Leanc)
|
||||
if(NOT ${CMAKE_SYSTEM_NAME} MATCHES "Emscripten")
|
||||
list(APPEND STDLIBS Lake)
|
||||
list(APPEND STDLIBS Lake LeanChecker)
|
||||
endif()
|
||||
|
||||
add_custom_target(make_stdlib ALL
|
||||
@@ -758,6 +758,12 @@ if(NOT ${CMAKE_SYSTEM_NAME} MATCHES "Emscripten")
|
||||
DEPENDS lake_shared
|
||||
COMMAND $(MAKE) -f ${CMAKE_BINARY_DIR}/stdlib.make lake
|
||||
VERBATIM)
|
||||
|
||||
add_custom_target(leanchecker ALL
|
||||
WORKING_DIRECTORY ${LEAN_SOURCE_DIR}
|
||||
DEPENDS lake_shared
|
||||
COMMAND $(MAKE) -f ${CMAKE_BINARY_DIR}/stdlib.make leanchecker
|
||||
VERBATIM)
|
||||
endif()
|
||||
|
||||
if(PREV_STAGE)
|
||||
|
||||
@@ -102,7 +102,7 @@ noncomputable def strongIndefiniteDescription {α : Sort u} (p : α → Prop) (h
|
||||
⟨xp.val, fun _ => xp.property⟩)
|
||||
(fun hp => ⟨choice h, fun h => absurd h hp⟩)
|
||||
|
||||
/-- the Hilbert epsilon Function -/
|
||||
/-- The Hilbert epsilon function. -/
|
||||
noncomputable def epsilon {α : Sort u} [h : Nonempty α] (p : α → Prop) : α :=
|
||||
(strongIndefiniteDescription p h).val
|
||||
|
||||
|
||||
@@ -16,3 +16,4 @@ public import Init.Control.Option
|
||||
public import Init.Control.Lawful
|
||||
public import Init.Control.StateCps
|
||||
public import Init.Control.ExceptCps
|
||||
public import Init.Control.MonadAttach
|
||||
|
||||
@@ -144,7 +144,7 @@ instance : ToBool Bool where
|
||||
Converts the result of the monadic action `x` to a `Bool`. If it is `true`, returns it and ignores
|
||||
`y`; otherwise, runs `y` and returns its result.
|
||||
|
||||
This a monadic counterpart to the short-circuiting `||` operator, usually accessed via the `<||>`
|
||||
This is a monadic counterpart to the short-circuiting `||` operator, usually accessed via the `<||>`
|
||||
operator.
|
||||
-/
|
||||
@[macro_inline] def orM {m : Type u → Type v} {β : Type u} [Monad m] [ToBool β] (x y : m β) : m β := do
|
||||
@@ -161,7 +161,7 @@ recommended_spelling "orM" for "<||>" in [orM, «term_<||>_»]
|
||||
Converts the result of the monadic action `x` to a `Bool`. If it is `true`, returns `y`; otherwise,
|
||||
returns the original result of `x`.
|
||||
|
||||
This a monadic counterpart to the short-circuiting `&&` operator, usually accessed via the `<&&>`
|
||||
This is a monadic counterpart to the short-circuiting `&&` operator, usually accessed via the `<&&>`
|
||||
operator.
|
||||
-/
|
||||
@[macro_inline] def andM {m : Type u → Type v} {β : Type u} [Monad m] [ToBool β] (x y : m β) : m β := do
|
||||
|
||||
@@ -25,6 +25,12 @@ instance [Repr ε] [Repr α] : Repr (Result ε σ α) where
|
||||
| Result.error e _, prec => Repr.addAppParen ("EStateM.Result.error " ++ reprArg e) prec
|
||||
| Result.ok a _, prec => Repr.addAppParen ("EStateM.Result.ok " ++ reprArg a) prec
|
||||
|
||||
instance : MonadAttach (EStateM ε σ) where
|
||||
CanReturn x a := Exists fun s => Exists fun s' => x.run s = .ok a s'
|
||||
attach x s := match h : x s with
|
||||
| .ok a s' => .ok ⟨a, s, s', h⟩ s'
|
||||
| .error e s' => .error e s'
|
||||
|
||||
end EStateM
|
||||
|
||||
namespace EStateM
|
||||
|
||||
@@ -329,3 +329,8 @@ instance ExceptT.finally {m : Type u → Type v} {ε : Type u} [MonadFinally m]
|
||||
| (.ok a, .ok b) => pure (.ok (a, b))
|
||||
| (_, .error e) => pure (.error e) -- second error has precedence
|
||||
| (.error e, _) => pure (.error e)
|
||||
|
||||
instance [Monad m] [MonadAttach m] : MonadAttach (ExceptT ε m) where
|
||||
CanReturn x a := MonadAttach.CanReturn (m := m) x (.ok a)
|
||||
attach x := show m (Except ε _) from
|
||||
(fun ⟨a, h⟩ => match a with | .ok a => .ok ⟨a, h⟩ | .error e => .error e) <$> MonadAttach.attach (m := m) x
|
||||
|
||||
@@ -75,6 +75,13 @@ instance [Monad m] : MonadLift m (ExceptCpsT σ m) where
|
||||
instance [Inhabited ε] : Inhabited (ExceptCpsT ε m α) where
|
||||
default := fun _ _ k₂ => k₂ default
|
||||
|
||||
/--
|
||||
For continuation monads, it is not possible to provide a computable `MonadAttach` instance that
|
||||
actually adds information about the return value. Therefore, this instance always attaches a proof
|
||||
of `True`.
|
||||
-/
|
||||
instance : MonadAttach (ExceptCpsT ε m) := .trivial
|
||||
|
||||
@[simp] theorem run_pure [Monad m] : run (pure x : ExceptCpsT ε m α) = pure (Except.ok x) := rfl
|
||||
|
||||
@[simp] theorem run_lift {α ε : Type u} [Monad m] (x : m α) : run (ExceptCpsT.lift x : ExceptCpsT ε m α) = (x >>= fun a => pure (Except.ok a) : m (Except ε α)) := rfl
|
||||
|
||||
@@ -9,6 +9,7 @@ module
|
||||
|
||||
prelude
|
||||
public import Init.Core
|
||||
public import Init.Control.MonadAttach
|
||||
|
||||
public section
|
||||
|
||||
@@ -67,4 +68,15 @@ instance [OfNat α n] : OfNat (Id α) n :=
|
||||
instance {m : Type u → Type v} [Pure m] : MonadLiftT Id m where
|
||||
monadLift x := pure x.run
|
||||
|
||||
instance : MonadAttach Id where
|
||||
CanReturn x a := x.run = a
|
||||
attach x := pure ⟨x.run, rfl⟩
|
||||
|
||||
instance : LawfulMonadAttach Id where
|
||||
map_attach := rfl
|
||||
canReturn_map_imp := by
|
||||
intro _ _ x _ h
|
||||
cases h
|
||||
exact x.run.2
|
||||
|
||||
end Id
|
||||
|
||||
@@ -10,3 +10,4 @@ public import Init.Control.Lawful.Basic
|
||||
public import Init.Control.Lawful.Instances
|
||||
public import Init.Control.Lawful.Lemmas
|
||||
public import Init.Control.Lawful.MonadLift
|
||||
public import Init.Control.Lawful.MonadAttach
|
||||
|
||||
@@ -248,10 +248,10 @@ namespace Id
|
||||
instance : LawfulMonad Id := by
|
||||
refine LawfulMonad.mk' _ ?_ ?_ ?_ <;> intros <;> rfl
|
||||
|
||||
@[simp] theorem run_map (x : Id α) (f : α → β) : (f <$> x).run = f x.run := rfl
|
||||
@[simp] theorem run_bind (x : Id α) (f : α → Id β) : (x >>= f).run = (f x.run).run := rfl
|
||||
@[simp] theorem run_pure (a : α) : (pure a : Id α).run = a := rfl
|
||||
@[simp] theorem pure_run (a : Id α) : pure a.run = a := rfl
|
||||
@[simp, grind =] theorem run_map (x : Id α) (f : α → β) : (f <$> x).run = f x.run := rfl
|
||||
@[simp, grind =] theorem run_bind (x : Id α) (f : α → Id β) : (x >>= f).run = (f x.run).run := rfl
|
||||
@[simp, grind =] theorem run_pure (a : α) : (pure a : Id α).run = a := rfl
|
||||
@[simp, grind =] theorem pure_run (a : Id α) : pure a.run = a := rfl
|
||||
@[simp] theorem run_seqRight (x y : Id α) : (x *> y).run = y.run := rfl
|
||||
@[simp] theorem run_seqLeft (x y : Id α) : (x <* y).run = x.run := rfl
|
||||
@[simp] theorem run_seq (f : Id (α → β)) (x : Id α) : (f <*> x).run = f.run x.run := rfl
|
||||
|
||||
10
src/Init/Control/Lawful/MonadAttach.lean
Normal file
10
src/Init/Control/Lawful/MonadAttach.lean
Normal file
@@ -0,0 +1,10 @@
|
||||
/-
|
||||
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.Control.Lawful.MonadAttach.Lemmas
|
||||
public import Init.Control.Lawful.MonadAttach.Instances
|
||||
86
src/Init/Control/Lawful/MonadAttach/Instances.lean
Normal file
86
src/Init/Control/Lawful/MonadAttach/Instances.lean
Normal file
@@ -0,0 +1,86 @@
|
||||
/-
|
||||
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.Control.Reader
|
||||
public import Init.Control.Lawful.Instances
|
||||
import Init.Control.Lawful.MonadAttach.Lemmas
|
||||
|
||||
public instance [Monad m] [LawfulMonad m] [MonadAttach m] [WeaklyLawfulMonadAttach m] :
|
||||
WeaklyLawfulMonadAttach (ReaderT ρ m) where
|
||||
map_attach := by
|
||||
simp only [Functor.map, MonadAttach.attach, Functor.map_map, WeaklyLawfulMonadAttach.map_attach]
|
||||
intros; rfl
|
||||
|
||||
public instance [Monad m] [LawfulMonad m] [MonadAttach m] [LawfulMonadAttach m] :
|
||||
LawfulMonadAttach (ReaderT ρ m) where
|
||||
canReturn_map_imp := by
|
||||
simp only [Functor.map, MonadAttach.CanReturn, ReaderT.run]
|
||||
rintro _ _ x a ⟨r, h⟩
|
||||
apply LawfulMonadAttach.canReturn_map_imp h
|
||||
|
||||
public instance [Monad m] [LawfulMonad m] [MonadAttach m] [WeaklyLawfulMonadAttach m] :
|
||||
WeaklyLawfulMonadAttach (StateT σ m) where
|
||||
map_attach := by
|
||||
intro α x
|
||||
simp only [Functor.map, StateT, funext_iff, StateT.map, bind_pure_comp, MonadAttach.attach,
|
||||
Functor.map_map]
|
||||
exact fun s => WeaklyLawfulMonadAttach.map_attach
|
||||
|
||||
public instance [Monad m] [LawfulMonad m] [MonadAttach m] [LawfulMonadAttach m] :
|
||||
LawfulMonadAttach (StateT σ m) where
|
||||
canReturn_map_imp := by
|
||||
simp only [Functor.map, MonadAttach.CanReturn, StateT.run, StateT.map, bind_pure_comp]
|
||||
rintro _ _ x a ⟨s, s', h⟩
|
||||
obtain ⟨a, h, h'⟩ := LawfulMonadAttach.canReturn_map_imp' h
|
||||
cases h'
|
||||
exact a.1.2
|
||||
|
||||
public instance [Monad m] [LawfulMonad m] [MonadAttach m] [WeaklyLawfulMonadAttach m] :
|
||||
WeaklyLawfulMonadAttach (ExceptT ε m) where
|
||||
map_attach {α} x := by
|
||||
simp only [Functor.map, MonadAttach.attach, ExceptT.map]
|
||||
simp
|
||||
conv => rhs; rw [← WeaklyLawfulMonadAttach.map_attach (m := m) (x := x)]
|
||||
simp only [map_eq_pure_bind]
|
||||
apply bind_congr; intro a
|
||||
match a with
|
||||
| ⟨.ok _, _⟩ => simp
|
||||
| ⟨.error _, _⟩ => simp
|
||||
|
||||
public instance [Monad m] [LawfulMonad m] [MonadAttach m] [LawfulMonadAttach m] :
|
||||
LawfulMonadAttach (ExceptT ε m) where
|
||||
canReturn_map_imp {α P x a} := by
|
||||
simp only [Functor.map, MonadAttach.CanReturn, ExceptT.map, ExceptT.mk]
|
||||
let x' := (fun a => show Subtype (fun a : Except _ _ => match a with | .ok a => P a | .error e => True) from ⟨match a with | .ok a => .ok a.1 | .error e => .error e, by cases a <;> simp [Subtype.property]⟩) <$> show m _ from x
|
||||
have := LawfulMonadAttach.canReturn_map_imp (m := m) (x := x') (a := .ok a)
|
||||
simp only at this
|
||||
intro h
|
||||
apply this
|
||||
simp only [x', map_eq_pure_bind, bind_assoc]
|
||||
refine cast ?_ h
|
||||
congr 1
|
||||
apply bind_congr; intro a
|
||||
split <;> simp
|
||||
|
||||
public instance [Monad m] [MonadAttach m] [LawfulMonad m] [WeaklyLawfulMonadAttach m] :
|
||||
WeaklyLawfulMonadAttach (StateRefT' ω σ m) :=
|
||||
inferInstanceAs (WeaklyLawfulMonadAttach (ReaderT _ _))
|
||||
|
||||
public instance [Monad m] [MonadAttach m] [LawfulMonad m] [LawfulMonadAttach m] :
|
||||
LawfulMonadAttach (StateRefT' ω σ m) :=
|
||||
inferInstanceAs (LawfulMonadAttach (ReaderT _ _))
|
||||
|
||||
section
|
||||
|
||||
attribute [local instance] MonadAttach.trivial
|
||||
|
||||
public instance [Monad m] [LawfulMonad m] :
|
||||
WeaklyLawfulMonadAttach m where
|
||||
map_attach := by simp [MonadAttach.attach]
|
||||
|
||||
end
|
||||
90
src/Init/Control/Lawful/MonadAttach/Lemmas.lean
Normal file
90
src/Init/Control/Lawful/MonadAttach/Lemmas.lean
Normal file
@@ -0,0 +1,90 @@
|
||||
/-
|
||||
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.Control.MonadAttach
|
||||
import all Init.Control.MonadAttach
|
||||
public import Init.Control.Lawful.Lemmas
|
||||
public import Init.Control.Lawful.MonadLift.Lemmas
|
||||
|
||||
public theorem LawfulMonadAttach.canReturn_bind_imp' [Monad m] [LawfulMonad m]
|
||||
[MonadAttach m] [LawfulMonadAttach m]
|
||||
{x : m α} {f : α → m β} :
|
||||
MonadAttach.CanReturn (x >>= f) b → Exists fun a => MonadAttach.CanReturn x a ∧ MonadAttach.CanReturn (f a) b := by
|
||||
intro h
|
||||
let P (b : β) := Exists fun a => MonadAttach.CanReturn x a ∧ MonadAttach.CanReturn (f a) b
|
||||
have h' : (x >>= f) = Subtype.val <$> (MonadAttach.attach x >>= (fun a => (do
|
||||
let b ← MonadAttach.attach (f a)
|
||||
return ⟨b.1, a.1, a.2, b.2⟩ : m (Subtype P)))) := by
|
||||
simp only [map_bind, map_pure]
|
||||
simp only [bind_pure_comp, WeaklyLawfulMonadAttach.map_attach]
|
||||
rw (occs := [1]) [← WeaklyLawfulMonadAttach.map_attach (x := x)]
|
||||
simp
|
||||
rw [h'] at h
|
||||
have := LawfulMonadAttach.canReturn_map_imp h
|
||||
exact this
|
||||
|
||||
public theorem LawfulMonadAttach.eq_of_canReturn_pure [Monad m] [MonadAttach m]
|
||||
[LawfulMonad m] [LawfulMonadAttach m] {a b : α}
|
||||
(h : MonadAttach.CanReturn (m := m) (pure a) b) :
|
||||
a = b := by
|
||||
let x : m (Subtype (a = ·)) := pure ⟨a, rfl⟩
|
||||
have : pure a = Subtype.val <$> x := by simp [x]
|
||||
rw [this] at h
|
||||
exact LawfulMonadAttach.canReturn_map_imp h
|
||||
|
||||
public theorem LawfulMonadAttach.canReturn_map_imp' [Monad m] [LawfulMonad m]
|
||||
[MonadAttach m] [LawfulMonadAttach m]
|
||||
{x : m α} {f : α → β} :
|
||||
MonadAttach.CanReturn (f <$> x) b → Exists fun a => MonadAttach.CanReturn x a ∧ f a = b := by
|
||||
rw [map_eq_pure_bind]
|
||||
intro h
|
||||
obtain ⟨a, h, h'⟩ := canReturn_bind_imp' h
|
||||
exact ⟨a, h, eq_of_canReturn_pure h'⟩
|
||||
|
||||
public theorem LawfulMonadAttach.canReturn_liftM_imp'
|
||||
[Monad m] [MonadAttach m] [LawfulMonad m] [LawfulMonadAttach m]
|
||||
[Monad n] [MonadAttach n] [LawfulMonad n] [LawfulMonadAttach n]
|
||||
[MonadLiftT m n] [LawfulMonadLiftT m n] {x : m α} {a : α} :
|
||||
MonadAttach.CanReturn (liftM (n := n) x) a → MonadAttach.CanReturn x a := by
|
||||
intro h
|
||||
simp only [← WeaklyLawfulMonadAttach.map_attach (x := x), liftM_map] at h
|
||||
exact canReturn_map_imp h
|
||||
|
||||
public theorem WeaklyLawfulMonadAttach.attach_bind_val
|
||||
[Monad m] [MonadAttach m] [LawfulMonad m] [WeaklyLawfulMonadAttach m]
|
||||
{x : m α} {f : α → m β} :
|
||||
MonadAttach.attach x >>= (fun a => f a.val) = x >>= f := by
|
||||
conv => rhs; simp only [← map_attach (x := x), bind_map_left]
|
||||
|
||||
public theorem WeaklyLawfulMonadAttach.bind_attach_of_nonempty
|
||||
[Monad m] [MonadAttach m] [LawfulMonad m] [WeaklyLawfulMonadAttach m] [Nonempty (m β)]
|
||||
{x : m α} {f : Subtype (MonadAttach.CanReturn x) → m β} :
|
||||
open scoped Classical in
|
||||
MonadAttach.attach x >>= f = x >>= (fun a => if ha : MonadAttach.CanReturn x a then f ⟨a, ha⟩ else Classical.ofNonempty) := by
|
||||
conv => rhs; simp +singlePass only [← map_attach (x := x)]
|
||||
simp [Subtype.property]
|
||||
|
||||
public theorem MonadAttach.attach_bind_eq_pbind
|
||||
[Monad m] [MonadAttach m]
|
||||
{x : m α} {f : Subtype (MonadAttach.CanReturn x) → m β} :
|
||||
MonadAttach.attach x >>= f = MonadAttach.pbind x (fun a ha => f ⟨a, ha⟩) := by
|
||||
simp [MonadAttach.pbind]
|
||||
|
||||
public theorem WeaklyLawfulMonadAttach.pbind_eq_bind
|
||||
[Monad m] [MonadAttach m] [LawfulMonad m] [WeaklyLawfulMonadAttach m]
|
||||
{x : m α} {f : α → m β} :
|
||||
MonadAttach.pbind x (fun a _ => f a) = x >>= f := by
|
||||
conv => rhs; rw [← map_attach (x := x)]
|
||||
simp [MonadAttach.pbind]
|
||||
|
||||
public theorem WeaklyLawfulMonadAttach.pbind_eq_bind'
|
||||
[Monad m] [MonadAttach m] [LawfulMonad m] [WeaklyLawfulMonadAttach m]
|
||||
{x : m α} {f : α → m β} :
|
||||
MonadAttach.pbind x (fun a _ => f a) = x >>= f := by
|
||||
conv => rhs; rw [← map_attach (x := x)]
|
||||
simp [MonadAttach.pbind]
|
||||
@@ -6,6 +6,7 @@ Authors: Quang Dao
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Control.Id
|
||||
public import Init.Control.Lawful.Basic
|
||||
public import Init.Control.Lawful.MonadLift.Basic
|
||||
|
||||
@@ -13,6 +14,14 @@ public section
|
||||
|
||||
universe u v w
|
||||
|
||||
theorem instMonadLiftTOfMonadLift_instMonadLiftTOfPure [Monad m] [Monad n] {_ : MonadLift m n}
|
||||
[LawfulMonadLift m n] : instMonadLiftTOfMonadLift Id m n = Id.instMonadLiftTOfPure := by
|
||||
have hext {a b : MonadLiftT Id n} (h : @a.monadLift = @b.monadLift) : a = b := by
|
||||
cases a <;> cases b <;> simp_all
|
||||
apply hext
|
||||
ext α x
|
||||
simp [monadLift, LawfulMonadLift.monadLift_pure]
|
||||
|
||||
variable {m : Type u → Type v} {n : Type u → Type w} [Monad m] [Monad n] [MonadLiftT m n]
|
||||
[LawfulMonadLiftT m n] {α β : Type u}
|
||||
|
||||
|
||||
126
src/Init/Control/MonadAttach.lean
Normal file
126
src/Init/Control/MonadAttach.lean
Normal file
@@ -0,0 +1,126 @@
|
||||
/-
|
||||
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.Control.Basic
|
||||
|
||||
set_option linter.all true
|
||||
|
||||
set_option doc.verso true
|
||||
|
||||
/-!
|
||||
# {name (scope := "Init.Control.MonadAttach")}`MonadAttach`
|
||||
|
||||
This module provides a mechanism for attaching proofs to the return values of monadic computations,
|
||||
producing a new monadic computation returning a {name}`Subtype`.
|
||||
|
||||
This function is primarily used to allow definitions by [well-founded
|
||||
recursion](lean-manual://section/well-founded-recursion) that sequence computations using
|
||||
{name}`Bind.bind` (`>>=`) to prove properties about the return values of prior computations when
|
||||
a recursive call happens.
|
||||
This allows the well-founded recursion mechanism to prove that the function terminates.
|
||||
-/
|
||||
|
||||
-- verso docstring is added below
|
||||
set_option linter.missingDocs false in
|
||||
public class MonadAttach (m : Type u → Type v) where
|
||||
/--
|
||||
A predicate that can be assumed to be true for all return values {name}`a` of actions {name}`x`
|
||||
in {name}`m`, in all situations.
|
||||
-/
|
||||
CanReturn {α : Type u} : (x : m α) → (a : α) → Prop
|
||||
/--
|
||||
Attaches a proof of {name}`MonadAttach.CanReturn` to the return value of {name}`x`. This proof
|
||||
can be used to prove the termination of well-founded recursive functions.
|
||||
-/
|
||||
attach {α : Type u} (x : m α) : m (Subtype (CanReturn x))
|
||||
|
||||
-- verso docstring is added below
|
||||
set_option linter.missingDocs false in
|
||||
public class WeaklyLawfulMonadAttach (m : Type u → Type v) [Monad m] [MonadAttach m] where
|
||||
map_attach {α : Type u} {x : m α} : Subtype.val <$> MonadAttach.attach x = x
|
||||
|
||||
/--
|
||||
This type class ensures that {name}`MonadAttach.CanReturn` is the unique strongest possible
|
||||
postcondition.
|
||||
-/
|
||||
public class LawfulMonadAttach (m : Type u → Type v) [Monad m] [MonadAttach m] extends
|
||||
WeaklyLawfulMonadAttach m where
|
||||
canReturn_map_imp {α : Type u} {P : α → Prop} {x : m (Subtype P)} {a : α} :
|
||||
MonadAttach.CanReturn (Subtype.val <$> x) a → P a
|
||||
|
||||
/--
|
||||
Like {name}`Bind.bind`, {name}`pbind` sequences two computations {lean}`x : m α` and {lean}`f`,
|
||||
allowing the second to depend on the value computed by the first.
|
||||
But other than with {name}`Bind.bind`, the second computation can also depend on a proof that
|
||||
the return value {given}`a` of {name}`x` satisfies {lean}`MonadAttach.CanReturn x a`.
|
||||
-/
|
||||
public def MonadAttach.pbind [Monad m] [MonadAttach m]
|
||||
(x : m α) (f : (a : α) → MonadAttach.CanReturn x a → m β) : m β :=
|
||||
MonadAttach.attach x >>= (fun ⟨a, ha⟩ => f a ha)
|
||||
|
||||
/--
|
||||
A {lean}`MonadAttach` instance where all return values are possible and {name}`attach` adds no
|
||||
information to the return value, except a trivial proof of {name}`True`.
|
||||
|
||||
This instance is used whenever no more useful {name}`MonadAttach` instance can be implemented.
|
||||
It always has a {name}`WeaklyLawfulMonadAttach`, but usually no {name}`LawfulMonadAttach` instance.
|
||||
-/
|
||||
@[expose]
|
||||
public protected def MonadAttach.trivial {m : Type u → Type v} [Monad m] : MonadAttach m where
|
||||
CanReturn _ _ := True
|
||||
attach x := (⟨·, .intro⟩) <$> x
|
||||
|
||||
section
|
||||
|
||||
variable (α : Type u) [∀ m, Monad m] [∀ m, MonadAttach m]
|
||||
|
||||
set_option doc.verso true
|
||||
|
||||
/--
|
||||
For every {given}`x : m α`, this type class provides a predicate {lean}`MonadAttach.CanReturn x`
|
||||
and a way to attach a proof of this predicate to the return values of {name}`x` by providing
|
||||
an element {lean}`MonadAttach.attach x` of {lean}`m { a : α // MonadAttach.CanReturn x a }`.
|
||||
|
||||
Instances should abide the law {lean}`Subtype.val <$> MonadAttach.attach x = x`, which is encoded by
|
||||
the {name}`WeaklyLawfulMonadAttach` type class. The stronger type class {name}`LawfulMonadAttach`
|
||||
ensures that {lean}`MonadAttach.CanReturn x` is the _unique_ strongest possible predicate.
|
||||
|
||||
Similarly to {name (scope := "Init.Data.List.Attach")}`List.attach`, the purpose of
|
||||
{name}`MonadAttach` is to attach proof terms necessary for well-founded termination proofs.
|
||||
The iterator library relies on {name}`MonadAttach` for combinators such as
|
||||
{name (scope := "Init.Data.Iterators")}`Std.Iter.filterM` in order to automatically attach
|
||||
information about the monadic predicate's behavior that could be relevant for the termination
|
||||
behavior of the iterator.
|
||||
|
||||
*Limitations*:
|
||||
|
||||
For many monads, there is a strongly lawful {lean}`MonadAttach` instance, but there are exceptions.
|
||||
For example, there is no way to provide a computable {lean}`MonadAttach` instance for the CPS monad
|
||||
transformers
|
||||
{name (scope := "Init.Control.StateCps")}`StateCpsT` and
|
||||
{name (scope := "Init.Control.StateCps")}`ExceptCpsT` with a predicate that is not always
|
||||
{name}`True`. Therefore, such CPS monads only provide the trivial {lean}`MonadAttach` instance
|
||||
{lean}`MonadAttach.trivial` together with {name}`WeaklyLawfulMonadAttach`, but without
|
||||
{name}`LawfulMonadAttach`.
|
||||
|
||||
For most monads with side effects, {lean}`MonadAttach` is too weak to fully capture the behavior of
|
||||
computations because the postcondition represented by {name}`MonadAttach.CanReturn` neither depends
|
||||
on the prior internal state of the monad, nor does it contain information about how the state of the
|
||||
monad changes with the computation.
|
||||
-/
|
||||
add_decl_doc MonadAttach
|
||||
|
||||
/--
|
||||
This type class ensures that every monadic action {given}`x : m α` can be recovered by stripping the
|
||||
proof component from the subtypes returned by
|
||||
{lean}`(MonadAttach.attach x) : m { a : α // MonadAttach.CanReturn x a }` . In other words,
|
||||
the type class ensures that {lean}`Subtype.val <$> MonadAttach.attach x = x`.
|
||||
-/
|
||||
add_decl_doc WeaklyLawfulMonadAttach
|
||||
|
||||
end
|
||||
@@ -112,6 +112,12 @@ instance (ε : Type u) [MonadExceptOf ε m] : MonadExceptOf ε (OptionT m) where
|
||||
throw e := OptionT.mk <| throwThe ε e
|
||||
tryCatch x handle := OptionT.mk <| tryCatchThe ε x handle
|
||||
|
||||
instance [MonadAttach m] : MonadAttach (OptionT m) where
|
||||
CanReturn x a := MonadAttach.CanReturn x.run (some a)
|
||||
attach x := .mk ((fun
|
||||
| ⟨some a, h⟩ => some ⟨a, h⟩
|
||||
| ⟨none, _⟩ => none) <$> MonadAttach.attach x.run)
|
||||
|
||||
end OptionT
|
||||
|
||||
instance [Monad m] : MonadControl m (OptionT m) where
|
||||
|
||||
@@ -51,3 +51,7 @@ A monad with access to a read-only value of type `ρ`. The value can be locally
|
||||
`withReader`, but it cannot be mutated.
|
||||
-/
|
||||
abbrev ReaderM (ρ : Type u) := ReaderT ρ Id
|
||||
|
||||
instance [Monad m] [MonadAttach m] : MonadAttach (ReaderT ρ m) where
|
||||
CanReturn x a := Exists (fun r => MonadAttach.CanReturn (x.run r) a)
|
||||
attach x := fun r => (fun ⟨a, h⟩ => ⟨a, r, h⟩) <$> MonadAttach.attach (x.run r)
|
||||
|
||||
@@ -204,3 +204,7 @@ instance StateT.tryFinally {m : Type u → Type v} {σ : Type u} [MonadFinally m
|
||||
| some (a, s') => h (some a) s'
|
||||
| none => h none s
|
||||
pure ((a, b), s'')
|
||||
|
||||
instance [Monad m] [MonadAttach m] : MonadAttach (StateT σ m) where
|
||||
CanReturn x a := Exists fun s => Exists fun s' => MonadAttach.CanReturn (x.run s) (a, s')
|
||||
attach x := fun s => (fun ⟨⟨a, s'⟩, h⟩ => ⟨⟨a, s, s', h⟩, s'⟩) <$> MonadAttach.attach (x.run s)
|
||||
|
||||
@@ -68,6 +68,13 @@ instance : MonadStateOf σ (StateCpsT σ m) where
|
||||
set s := fun _ _ k => k ⟨⟩ s
|
||||
modifyGet f := fun _ s k => let (a, s) := f s; k a s
|
||||
|
||||
/--
|
||||
For continuation monads, it is not possible to provide a computable `MonadAttach` instance that
|
||||
actually adds information about the return value. Therefore, this instance always attaches a proof
|
||||
of `True`.
|
||||
-/
|
||||
instance : MonadAttach (StateCpsT ε m) := .trivial
|
||||
|
||||
/--
|
||||
Runs an action from the underlying monad in the monad with state. The state is not modified.
|
||||
|
||||
|
||||
@@ -64,6 +64,7 @@ instance [Monad m] : Monad (StateRefT' ω σ m) := inferInstanceAs (Monad (Reade
|
||||
instance : MonadLift m (StateRefT' ω σ m) := ⟨StateRefT'.lift⟩
|
||||
instance (σ m) : MonadFunctor m (StateRefT' ω σ m) := inferInstanceAs (MonadFunctor m (ReaderT _ _))
|
||||
instance [Alternative m] [Monad m] : Alternative (StateRefT' ω σ m) := inferInstanceAs (Alternative (ReaderT _ _))
|
||||
instance [Monad m] [MonadAttach m] : MonadAttach (StateRefT' ω σ m) := inferInstanceAs (MonadAttach (ReaderT _ _))
|
||||
|
||||
/--
|
||||
Retrieves the current value of the monad's mutable state.
|
||||
|
||||
@@ -13,6 +13,10 @@ public import Init.SizeOf
|
||||
public section
|
||||
set_option linter.missingDocs true -- keep it documented
|
||||
|
||||
-- BEq instance for Option defined here so it's available early in the import chain
|
||||
-- (before Init.Grind.Config and Init.MetaTypes which need BEq (Option Nat))
|
||||
deriving instance BEq for Option
|
||||
|
||||
@[expose] section
|
||||
|
||||
universe u v w
|
||||
@@ -337,7 +341,7 @@ inductive Exists {α : Sort u} (p : α → Prop) : Prop where
|
||||
An indication of whether a loop's body terminated early that's used to compile the `for x in xs`
|
||||
notation.
|
||||
|
||||
A collection's `ForIn` or `ForIn'` instance describe's how to iterate over its elements. The monadic
|
||||
A collection's `ForIn` or `ForIn'` instance describes how to iterate over its elements. The monadic
|
||||
action that represents the body of the loop returns a `ForInStep α`, where `α` is the local state
|
||||
used to implement features such as `let mut`.
|
||||
-/
|
||||
@@ -510,12 +514,12 @@ abbrev SSuperset [HasSSubset α] (a b : α) := SSubset b a
|
||||
|
||||
/-- Notation type class for the union operation `∪`. -/
|
||||
class Union (α : Type u) where
|
||||
/-- `a ∪ b` is the union of`a` and `b`. -/
|
||||
/-- `a ∪ b` is the union of `a` and `b`. -/
|
||||
union : α → α → α
|
||||
|
||||
/-- Notation type class for the intersection operation `∩`. -/
|
||||
class Inter (α : Type u) where
|
||||
/-- `a ∩ b` is the intersection of`a` and `b`. -/
|
||||
/-- `a ∩ b` is the intersection of `a` and `b`. -/
|
||||
inter : α → α → α
|
||||
|
||||
/-- Notation type class for the set difference `\`. -/
|
||||
@@ -538,10 +542,10 @@ infix:50 " ⊇ " => Superset
|
||||
/-- Strict superset relation: `a ⊃ b` -/
|
||||
infix:50 " ⊃ " => SSuperset
|
||||
|
||||
/-- `a ∪ b` is the union of`a` and `b`. -/
|
||||
/-- `a ∪ b` is the union of `a` and `b`. -/
|
||||
infixl:65 " ∪ " => Union.union
|
||||
|
||||
/-- `a ∩ b` is the intersection of`a` and `b`. -/
|
||||
/-- `a ∩ b` is the intersection of `a` and `b`. -/
|
||||
infixl:70 " ∩ " => Inter.inter
|
||||
|
||||
/--
|
||||
|
||||
@@ -589,6 +589,8 @@ unsafe def foldlMUnsafe {α : Type u} {β : Type v} {m : Type v → Type w} [Mon
|
||||
if start < stop then
|
||||
if stop ≤ as.size then
|
||||
fold (USize.ofNat start) (USize.ofNat stop) init
|
||||
else if start < as.size then
|
||||
fold (USize.ofNat start) (USize.ofNat as.size) init
|
||||
else
|
||||
pure init
|
||||
else
|
||||
|
||||
@@ -125,6 +125,22 @@ instance instDecidableEmpEq (ys : Array α) : Decidable (#[] = ys) :=
|
||||
| ⟨[]⟩ => isTrue rfl
|
||||
| ⟨_ :: _⟩ => isFalse (fun h => Array.noConfusion rfl (heq_of_eq h) (fun h => List.noConfusion rfl h))
|
||||
|
||||
@[inline]
|
||||
def instDecidableEqEmpImpl (xs : Array α) : Decidable (xs = #[]) :=
|
||||
decidable_of_iff xs.isEmpty <| by rcases xs with ⟨⟨⟩⟩ <;> simp [Array.isEmpty]
|
||||
|
||||
@[inline]
|
||||
def instDecidableEmpEqImpl (xs : Array α) : Decidable (#[] = xs) :=
|
||||
decidable_of_iff xs.isEmpty <| by rcases xs with ⟨⟨⟩⟩ <;> simp [Array.isEmpty]
|
||||
|
||||
@[csimp]
|
||||
theorem instDecidableEqEmp_csimp : @instDecidableEqEmp = @instDecidableEqEmpImpl :=
|
||||
Subsingleton.allEq _ _
|
||||
|
||||
@[csimp]
|
||||
theorem instDecidableEmpEq_csimp : @instDecidableEmpEq = @instDecidableEmpEqImpl :=
|
||||
Subsingleton.allEq _ _
|
||||
|
||||
theorem beq_eq_decide [BEq α] (xs ys : Array α) :
|
||||
(xs == ys) = if h : xs.size = ys.size then
|
||||
decide (∀ (i : Nat) (h' : i < xs.size), xs[i] == ys[i]'(h ▸ h')) else false := by
|
||||
|
||||
@@ -62,6 +62,9 @@ theorem eq_empty_of_size_eq_zero (h : xs.size = 0) : xs = #[] := by
|
||||
cases xs
|
||||
simp_all
|
||||
|
||||
grind_pattern eq_empty_of_size_eq_zero => xs.size where
|
||||
guard xs.size = 0
|
||||
|
||||
theorem ne_empty_of_size_eq_add_one (h : xs.size = n + 1) : xs ≠ #[] := by
|
||||
cases xs
|
||||
simpa using List.ne_nil_of_length_eq_add_one h
|
||||
@@ -112,7 +115,8 @@ theorem none_eq_getElem?_iff {xs : Array α} {i : Nat} : none = xs[i]? ↔ xs.si
|
||||
theorem getElem?_eq_none {xs : Array α} (h : xs.size ≤ i) : xs[i]? = none := by
|
||||
simp [h]
|
||||
|
||||
grind_pattern Array.getElem?_eq_none => xs.size, xs[i]?
|
||||
grind_pattern Array.getElem?_eq_none => xs.size, xs[i]? where
|
||||
guard xs.size ≤ i
|
||||
|
||||
@[simp] theorem getElem?_eq_getElem {xs : Array α} {i : Nat} (h : i < xs.size) : xs[i]? = some xs[i] :=
|
||||
getElem?_pos ..
|
||||
|
||||
@@ -290,7 +290,7 @@ Lean convention that division by zero returns zero.
|
||||
|
||||
Examples:
|
||||
* `(7#4).sdiv 2 = 3#4`
|
||||
* `(-9#4).sdiv 2 = -4#4`
|
||||
* `(-8#4).sdiv 2 = -4#4`
|
||||
* `(5#4).sdiv -2 = -2#4`
|
||||
* `(-7#4).sdiv (-2) = 3#4`
|
||||
-/
|
||||
@@ -864,4 +864,17 @@ def clz (x : BitVec w) : BitVec w := clzAuxRec x (w - 1)
|
||||
/-- Count the number of trailing zeros. -/
|
||||
def ctz (x : BitVec w) : BitVec w := (x.reverse).clz
|
||||
|
||||
/-- Count the number of bits with value `1` downward from the `pos`-th bit to the
|
||||
`0`-th bit of `x`, storing the result in `acc`. -/
|
||||
def cpopNatRec (x : BitVec w) (pos acc : Nat) : Nat :=
|
||||
match pos with
|
||||
| 0 => acc
|
||||
| n + 1 => x.cpopNatRec n (acc + (x.getLsbD n).toNat)
|
||||
|
||||
/-- Population count operation, to count the number of bits with value `1` in `x`.
|
||||
Also known as `popcount`, `popcnt`.
|
||||
-/
|
||||
@[suggest_for BitVec.popcount BitVec.popcnt]
|
||||
def cpop (x : BitVec w) : BitVec w := BitVec.ofNat w (cpopNatRec x w 0)
|
||||
|
||||
end BitVec
|
||||
|
||||
@@ -67,6 +67,9 @@ theorem none_eq_getElem?_iff {l : BitVec w} : none = l[n]? ↔ w ≤ n := by
|
||||
@[simp]
|
||||
theorem getElem?_eq_none {l : BitVec w} (h : w ≤ n) : l[n]? = none := getElem?_eq_none_iff.mpr h
|
||||
|
||||
grind_pattern BitVec.getElem?_eq_none => l[n]? where
|
||||
guard w ≤ n
|
||||
|
||||
theorem getElem?_eq (l : BitVec w) (i : Nat) :
|
||||
l[i]? = if h : i < w then some l[i] else none := by
|
||||
split <;> simp_all
|
||||
@@ -1019,6 +1022,14 @@ theorem setWidth_ofNat_one_eq_ofNat_one_of_lt {v w : Nat} (hv : 0 < v) :
|
||||
rw [Nat.mod_mod_of_dvd]
|
||||
exact Nat.pow_dvd_pow_iff_le_right'.mpr h
|
||||
|
||||
@[simp]
|
||||
theorem setWidth_ofNat_of_le_of_lt {x : Nat} (h : w ≤ v) (h' : x < 2 ^ w) :
|
||||
setWidth v (BitVec.ofNat w x) = BitVec.ofNat v x := by
|
||||
apply BitVec.eq_of_toNat_eq
|
||||
have := Nat.pow_le_pow_of_le (a := 2) (m := v) (n := w) (by omega) h
|
||||
simp only [toNat_setWidth, toNat_ofNat]
|
||||
rw [Nat.mod_eq_of_lt (by omega), Nat.mod_eq_of_lt (by omega), Nat.mod_eq_of_lt (by omega)]
|
||||
|
||||
/--
|
||||
Iterated `setWidth` agrees with the second `setWidth`
|
||||
except in the case the first `setWidth` is a non-trivial truncation,
|
||||
@@ -1252,11 +1263,31 @@ theorem extractLsb'_setWidth_of_le {b : BitVec w} {start len w' : Nat} (h : star
|
||||
simp
|
||||
omega
|
||||
|
||||
@[simp]
|
||||
theorem extractLsb_setWidth_of_lt {x : BitVec w} {hi lo v : Nat} (h : lo + hi < v) :
|
||||
(x.setWidth v).extractLsb hi lo = x.extractLsb hi lo := by
|
||||
simp only [BitVec.extractLsb]
|
||||
ext k hk
|
||||
simp
|
||||
omega
|
||||
|
||||
theorem setWidth_extractLsb'_of_le {c : BitVec w} (h : len₁ ≤ len₂) :
|
||||
(c.extractLsb' start len₂).setWidth len₁ = c.extractLsb' start len₁ := by
|
||||
ext i hi
|
||||
simp [show i < len₂ by omega]
|
||||
|
||||
theorem extractLsb'_cast {x : BitVec w} :
|
||||
(x.cast hcast).extractLsb' start len = x.extractLsb' start len := by
|
||||
ext k hk
|
||||
simp
|
||||
|
||||
@[simp]
|
||||
theorem extractLsb'_extractLsb'_of_le {x : BitVec w} (hlt : start + len ≤ len') :
|
||||
(x.extractLsb' 0 len').extractLsb' start len = x.extractLsb' start len := by
|
||||
ext k hk
|
||||
simp
|
||||
omega
|
||||
|
||||
/-! ### allOnes -/
|
||||
|
||||
@[simp, grind =] theorem toNat_allOnes : (allOnes v).toNat = 2^v - 1 := by
|
||||
@@ -2913,6 +2944,15 @@ theorem setWidth_eq_append {v : Nat} {x : BitVec v} {w : Nat} (h : v ≤ w) :
|
||||
omega
|
||||
· simp [hiv, getLsbD_of_ge x i (by omega)]
|
||||
|
||||
@[simp]
|
||||
theorem extractLsb'_append_extractLsb' {x : BitVec (w + len)} :
|
||||
(x.extractLsb' len w ++ x.extractLsb' 0 len) = x := by
|
||||
ext i hi
|
||||
simp only [getElem_append, getElem_extractLsb', Nat.zero_add, dite_eq_ite]
|
||||
split
|
||||
· rw [← getLsbD_eq_getElem]
|
||||
· simp [show len + (i - len) = i by omega, ← getLsbD_eq_getElem]
|
||||
|
||||
theorem setWidth_eq_extractLsb' {v : Nat} {x : BitVec v} {w : Nat} (h : w ≤ v) :
|
||||
x.setWidth w = x.extractLsb' 0 w := by
|
||||
rw [setWidth_eq_append_extractLsb']
|
||||
@@ -3210,6 +3250,11 @@ theorem cons_append_append (x : BitVec w₁) (y : BitVec w₂) (z : BitVec w₃)
|
||||
· simp [h₂]; omega
|
||||
· simp [h₂]; omega
|
||||
|
||||
@[simp]
|
||||
theorem extractLsb'_cons {x : BitVec w} :
|
||||
(x.cons y).extractLsb' 0 w = x := by
|
||||
simp [BitVec.toNat_eq, Nat.or_mod_two_pow, Nat.shiftLeft_eq]
|
||||
|
||||
/-! ### concat -/
|
||||
|
||||
@[simp, grind =] theorem toNat_concat (x : BitVec w) (b : Bool) :
|
||||
@@ -3308,6 +3353,15 @@ theorem msb_concat {w : Nat} {b : Bool} {x : BitVec w} :
|
||||
ext
|
||||
simp [getElem_concat]
|
||||
|
||||
theorem extractLsb'_concat {x : BitVec (w + 1)} {y : Bool} :
|
||||
(x.concat y).extractLsb' 0 (t + 1) = (x.extractLsb' 0 t).concat y := by
|
||||
ext i hi
|
||||
simp only [← getLsbD_eq_getElem, getLsbD_extractLsb', hi, decide_true, Nat.zero_add,
|
||||
getLsbD_concat, Bool.true_and]
|
||||
split
|
||||
· simp
|
||||
· simp [show i - 1 < t by omega]
|
||||
|
||||
/-! ### shiftConcat -/
|
||||
|
||||
@[grind =]
|
||||
@@ -5812,6 +5866,16 @@ theorem reverse_reverse_eq {x : BitVec w} :
|
||||
ext k hk
|
||||
rw [getElem_reverse, getMsbD_reverse, getLsbD_eq_getElem]
|
||||
|
||||
@[simp]
|
||||
theorem concat_reverse_setWidth_msb_eq_reverse {x : BitVec (w + 1)} :
|
||||
concat ((x.setWidth w).reverse) x.msb = x.reverse := by
|
||||
ext i hi
|
||||
simp only [getElem_reverse, BitVec.msb, getElem_concat, getMsbD_setWidth, Nat.le_add_right,
|
||||
Nat.sub_eq_zero_of_le, Nat.zero_le, decide_true, Bool.true_and, dite_eq_ite]
|
||||
by_cases hzero : i = 0
|
||||
· simp [hzero]
|
||||
· simp [hzero, show i - 1 + (w + 1) - w = i by omega]
|
||||
|
||||
/-! ### Inequalities (le / lt) -/
|
||||
|
||||
theorem ule_eq_not_ult (x y : BitVec w) : x.ule y = !y.ult x := by
|
||||
@@ -6287,4 +6351,241 @@ theorem two_pow_ctz_le_toNat_of_ne_zero {x : BitVec w} (hx : x ≠ 0#w) :
|
||||
have hclz := getLsbD_true_ctz_of_ne_zero (x := x) hx
|
||||
exact Nat.ge_two_pow_of_testBit hclz
|
||||
|
||||
/-! ### Population Count -/
|
||||
|
||||
@[simp]
|
||||
theorem cpopNatRec_zero_self {x : BitVec w} :
|
||||
x.cpopNatRec 0 acc = acc := rfl
|
||||
|
||||
@[simp]
|
||||
theorem cpopNatRec_succ {n : Nat} {x : BitVec w} :
|
||||
x.cpopNatRec (n + 1) acc = x.cpopNatRec n (acc + (x.getLsbD n).toNat) := rfl
|
||||
|
||||
@[simp]
|
||||
theorem cpopNatRec_zero :
|
||||
(0#w).cpopNatRec n acc = acc := by
|
||||
induction n
|
||||
· case zero =>
|
||||
simp
|
||||
· case succ n ihn =>
|
||||
simp [ihn]
|
||||
|
||||
theorem cpopNatRec_eq {x : BitVec w} {n : Nat} (acc : Nat):
|
||||
x.cpopNatRec n acc = x.cpopNatRec n 0 + acc := by
|
||||
induction n generalizing acc
|
||||
· case zero =>
|
||||
simp
|
||||
· case succ n ihn =>
|
||||
simp [ihn (acc := acc + (x.getLsbD n).toNat), ihn (acc := (x.getLsbD n).toNat)]
|
||||
omega
|
||||
|
||||
theorem cpopNatRec_add {x : BitVec w} {acc n : Nat} :
|
||||
x.cpopNatRec n (acc + acc') = x.cpopNatRec n acc + acc' := by
|
||||
rw [cpopNatRec_eq (acc := acc + acc'), cpopNatRec_eq (acc := acc), Nat.add_assoc]
|
||||
|
||||
theorem cpopNatRec_le {x : BitVec w} (n : Nat) :
|
||||
x.cpopNatRec n acc ≤ acc + n := by
|
||||
induction n generalizing acc
|
||||
· case zero =>
|
||||
simp
|
||||
· case succ n ihn =>
|
||||
have : (x.getLsbD n).toNat ≤ 1 := by cases x.getLsbD n <;> simp
|
||||
specialize ihn (acc := acc + (x.getLsbD n).toNat)
|
||||
simp
|
||||
omega
|
||||
|
||||
@[simp]
|
||||
theorem cpopNatRec_of_le {x : BitVec w} (k n : Nat) (hn : w ≤ n) :
|
||||
x.cpopNatRec (n + k) acc = x.cpopNatRec n acc := by
|
||||
induction k
|
||||
· case zero =>
|
||||
simp
|
||||
· case succ k ihk =>
|
||||
simp [show n + (k + 1) = (n + k) + 1 by omega, ihk, show w ≤ n + k by omega]
|
||||
|
||||
theorem cpopNatRec_zero_le (x : BitVec w) (n : Nat) :
|
||||
x.cpopNatRec n 0 ≤ w := by
|
||||
induction n
|
||||
· case zero =>
|
||||
simp
|
||||
· case succ n ihn =>
|
||||
by_cases hle : n ≤ w
|
||||
· by_cases hx : x.getLsbD n
|
||||
· have := cpopNatRec_le (x := x) (acc := 1) (by omega)
|
||||
have := lt_of_getLsbD hx
|
||||
simp [hx]
|
||||
omega
|
||||
· have := cpopNatRec_le (x := x) (acc := 0) (by omega)
|
||||
simp [hx]
|
||||
omega
|
||||
· simp [show w ≤ n by omega]
|
||||
omega
|
||||
|
||||
@[simp]
|
||||
theorem cpopNatRec_allOnes (h : n ≤ w) :
|
||||
(allOnes w).cpopNatRec n acc = acc + n := by
|
||||
induction n
|
||||
· case zero =>
|
||||
simp
|
||||
· case succ n ihn =>
|
||||
specialize ihn (by omega)
|
||||
simp [show n < w by omega, ihn,
|
||||
cpopNatRec_add (acc := acc) (acc' := 1)]
|
||||
omega
|
||||
|
||||
@[simp]
|
||||
theorem cpop_allOnes :
|
||||
(allOnes w).cpop = BitVec.ofNat w w := by
|
||||
simp [cpop, cpopNatRec_allOnes]
|
||||
|
||||
@[simp]
|
||||
theorem cpop_zero :
|
||||
(0#w).cpop = 0#w := by
|
||||
simp [cpop]
|
||||
|
||||
theorem toNat_cpop_le (x : BitVec w) :
|
||||
x.cpop.toNat ≤ w := by
|
||||
have hlt := Nat.lt_two_pow_self (n := w)
|
||||
have hle := cpopNatRec_zero_le (x := x) (n := w)
|
||||
simp only [cpop, toNat_ofNat, ge_iff_le]
|
||||
rw [Nat.mod_eq_of_lt (by omega)]
|
||||
exact hle
|
||||
|
||||
@[simp]
|
||||
theorem cpopNatRec_cons_of_le {x : BitVec w} {b : Bool} (hn : n ≤ w) :
|
||||
(cons b x).cpopNatRec n acc = x.cpopNatRec n acc := by
|
||||
induction n generalizing acc
|
||||
· case zero =>
|
||||
simp
|
||||
· case succ n ihn =>
|
||||
specialize ihn (acc := acc + ((cons b x).getLsbD n).toNat) (by omega)
|
||||
rw [cpopNatRec_succ, ihn, getLsbD_cons]
|
||||
simp [show ¬ n = w by omega]
|
||||
|
||||
@[simp]
|
||||
theorem cpopNatRec_cons_of_lt {x : BitVec w} {b : Bool} (hn : w < n) :
|
||||
(cons b x).cpopNatRec n acc = b.toNat + x.cpopNatRec n acc := by
|
||||
induction n generalizing acc
|
||||
· case zero =>
|
||||
omega
|
||||
· case succ n ihn =>
|
||||
by_cases hlt : w < n
|
||||
· rw [cpopNatRec_succ, ihn (acc := acc + ((cons b x).getLsbD n).toNat) (by omega)]
|
||||
simp [getLsbD_cons, show ¬ n = w by omega]
|
||||
· simp [show w = n by omega, getElem_cons,
|
||||
cpopNatRec_add (acc := acc) (acc' := b.toNat), Nat.add_comm]
|
||||
|
||||
theorem cpopNatRec_concat_of_lt {x : BitVec w} {b : Bool} (hn : 0 < n) :
|
||||
(concat x b).cpopNatRec n acc = b.toNat + x.cpopNatRec (n - 1) acc := by
|
||||
induction n generalizing acc
|
||||
· case zero =>
|
||||
omega
|
||||
· case succ n ihn =>
|
||||
by_cases hn0 : 0 < n
|
||||
· specialize ihn (acc := (acc + ((x.concat b).getLsbD n).toNat)) (by omega)
|
||||
rw [cpopNatRec_succ, ihn, cpopNatRec_add (acc := acc)]
|
||||
simp [getLsbD_concat, show ¬ n = 0 by omega, show n + 1 - 1 = n - 1 + 1 by omega, cpopNatRec_add]
|
||||
· simp [show n = 0 by omega]
|
||||
omega
|
||||
|
||||
theorem toNat_cpop (x : BitVec w) :
|
||||
x.cpop.toNat = x.cpopNatRec w 0 := by
|
||||
have := cpopNatRec_zero_le x w
|
||||
have := toNat_cpop_le x
|
||||
have := Nat.lt_two_pow_self (n := w)
|
||||
rw [cpop, toNat_ofNat, Nat.mod_eq_of_lt]
|
||||
omega
|
||||
|
||||
@[simp]
|
||||
theorem toNat_cpop_cons {x : BitVec w} {b : Bool} :
|
||||
(x.cons b).cpop.toNat = b.toNat + x.cpop.toNat := by
|
||||
simp [toNat_cpop, getElem_cons, cpopNatRec_eq (acc := b.toNat), Nat.add_comm]
|
||||
|
||||
@[simp]
|
||||
theorem cpopNatRec_setWidth_of_le (x : BitVec w) (h : pos ≤ v) :
|
||||
(setWidth v x).cpopNatRec pos acc = x.cpopNatRec pos acc := by
|
||||
induction pos generalizing acc
|
||||
· case zero =>
|
||||
simp
|
||||
· case succ pos ih =>
|
||||
simp only [cpopNatRec_succ, getLsbD_setWidth]
|
||||
rw [ih]
|
||||
· congr
|
||||
by_cases h : pos < v
|
||||
<;> simp [h]
|
||||
omega
|
||||
· omega
|
||||
|
||||
theorem cpop_cons {x : BitVec w} {b : Bool} :
|
||||
(x.cons b).cpop = b.toNat + x.cpop.setWidth (w + 1) := by
|
||||
have := toNat_cpop_le x
|
||||
have := Bool.toNat_lt b
|
||||
simp only [natCast_eq_ofNat, toNat_eq, toNat_add, toNat_ofNat, toNat_setWidth, Nat.lt_add_one,
|
||||
toNat_mod_cancel_of_lt, Nat.mod_add_mod]
|
||||
rw [toNat_cpop_cons, Nat.mod_eq_of_lt]
|
||||
omega
|
||||
|
||||
theorem cpop_concat {x : BitVec w} {b : Bool} :
|
||||
(x.concat b).cpop = b.toNat + x.cpop.setWidth (w + 1) := by
|
||||
have := cpopNatRec_zero_le (x := x) (n := w)
|
||||
have := Nat.lt_two_pow_self (n := w)
|
||||
rw [cpop, cpop, cpopNatRec_concat_of_lt,
|
||||
Nat.add_one_sub_one, natCast_eq_ofNat, ofNat_add]
|
||||
congr
|
||||
rw [setWidth_ofNat_of_le_of_lt (x := x.cpopNatRec w 0) (by omega) (by omega)]
|
||||
omega
|
||||
|
||||
@[simp]
|
||||
theorem toNat_cpop_concat {x : BitVec w} {b : Bool} :
|
||||
(x.concat b).cpop.toNat = b.toNat + x.cpop.toNat := by
|
||||
have := toNat_cpop_le (x := x)
|
||||
have := Nat.lt_two_pow_self (n := w + 1)
|
||||
simp only [cpop_concat, natCast_eq_ofNat, toNat_add, toNat_ofNat, toNat_setWidth, Nat.lt_add_one,
|
||||
toNat_mod_cancel_of_lt, Nat.mod_add_mod]
|
||||
rw [Nat.mod_eq_of_lt]
|
||||
cases b <;> (simp; omega)
|
||||
|
||||
theorem cpop_cons_eq_cpop_concat (x : BitVec w) :
|
||||
(x.cons y).cpop = (x.concat y).cpop := by
|
||||
rw [cpop_cons, cpop_concat]
|
||||
|
||||
@[simp]
|
||||
theorem cpop_reverse (x : BitVec w) :
|
||||
x.reverse.cpop = x.cpop := by
|
||||
induction w
|
||||
· case zero =>
|
||||
simp [cpop, reverse]
|
||||
· case succ w ihw =>
|
||||
rw [← concat_reverse_setWidth_msb_eq_reverse, cpop_concat, ihw, ← cpop_cons]
|
||||
simp
|
||||
|
||||
@[simp]
|
||||
theorem cpopNatRec_cast_eq_of_eq {x : BitVec w} (p : w = v) :
|
||||
(x.cast p).cpopNatRec n = x.cpopNatRec n := by
|
||||
subst p; simp
|
||||
|
||||
@[simp]
|
||||
theorem cpop_cast (x : BitVec w) (h : w = v) :
|
||||
(x.cast h).cpop = x.cpop.cast h := by
|
||||
simp [cpop, cpopNatRec_cast_eq_of_eq, h]
|
||||
|
||||
@[simp]
|
||||
theorem toNat_cpop_append {x : BitVec w} {y : BitVec u} :
|
||||
(x ++ y).cpop.toNat = x.cpop.toNat + y.cpop.toNat := by
|
||||
induction w generalizing u
|
||||
· case zero =>
|
||||
simp [cpop]
|
||||
· case succ w ihw =>
|
||||
rw [← cons_msb_setWidth x, toNat_cpop_cons, cons_append, cpop_cast, toNat_cast,
|
||||
toNat_cpop_cons, ihw, ← Nat.add_assoc]
|
||||
|
||||
theorem cpop_append {x : BitVec w} {y : BitVec u} :
|
||||
(x ++ y).cpop = x.cpop.setWidth (w + u) + y.cpop.setWidth (w + u) := by
|
||||
apply eq_of_toNat_eq
|
||||
have := toNat_cpop_le x
|
||||
have := toNat_cpop_le y
|
||||
have := Nat.lt_two_pow_self (n := w + u)
|
||||
simp only [toNat_cpop_append, toNat_add, toNat_setWidth, Nat.add_mod_mod, Nat.mod_add_mod]
|
||||
rw [Nat.mod_eq_of_lt (by omega)]
|
||||
|
||||
end BitVec
|
||||
|
||||
@@ -269,6 +269,8 @@ unsafe def foldlMUnsafe {β : Type v} {m : Type v → Type w} [Monad m] (f : β
|
||||
if start < stop then
|
||||
if stop ≤ as.size then
|
||||
fold (USize.ofNat start) (USize.ofNat stop) init
|
||||
else if start < as.size then
|
||||
fold (USize.ofNat start) (USize.ofNat as.size) init
|
||||
else
|
||||
pure init
|
||||
else
|
||||
|
||||
@@ -102,7 +102,7 @@ Returns `true` if the character is a uppercase ASCII letter.
|
||||
The uppercase ASCII letters are the following: `ABCDEFGHIJKLMNOPQRSTUVWXYZ`.
|
||||
-/
|
||||
@[inline] def isUpper (c : Char) : Bool :=
|
||||
c.val ≥ 65 && c.val ≤ 90
|
||||
c.val ≥ 'A'.val ∧ c.val ≤ 'Z'.val
|
||||
|
||||
/--
|
||||
Returns `true` if the character is a lowercase ASCII letter.
|
||||
@@ -110,7 +110,7 @@ Returns `true` if the character is a lowercase ASCII letter.
|
||||
The lowercase ASCII letters are the following: `abcdefghijklmnopqrstuvwxyz`.
|
||||
-/
|
||||
@[inline] def isLower (c : Char) : Bool :=
|
||||
c.val ≥ 97 && c.val ≤ 122
|
||||
c.val ≥ 'a'.val && c.val ≤ 'z'.val
|
||||
|
||||
/--
|
||||
Returns `true` if the character is an ASCII letter.
|
||||
@@ -126,7 +126,7 @@ Returns `true` if the character is an ASCII digit.
|
||||
The ASCII digits are the following: `0123456789`.
|
||||
-/
|
||||
@[inline] def isDigit (c : Char) : Bool :=
|
||||
c.val ≥ 48 && c.val ≤ 57
|
||||
c.val ≥ '0'.val && c.val ≤ '9'.val
|
||||
|
||||
/--
|
||||
Returns `true` if the character is an ASCII letter or digit.
|
||||
@@ -143,9 +143,16 @@ alphabet are returned unchanged.
|
||||
|
||||
The uppercase ASCII letters are the following: `ABCDEFGHIJKLMNOPQRSTUVWXYZ`.
|
||||
-/
|
||||
@[inline]
|
||||
def toLower (c : Char) : Char :=
|
||||
let n := toNat c;
|
||||
if n >= 65 ∧ n <= 90 then ofNat (n + 32) else c
|
||||
if h : c.val ≥ 'A'.val ∧ c.val ≤ 'Z'.val then
|
||||
⟨c.val + ('a'.val - 'A'.val), ?_⟩
|
||||
else
|
||||
c
|
||||
where finally
|
||||
have h : c.val.toBitVec.toNat + ('a'.val - 'A'.val).toBitVec.toNat < 0xd800 :=
|
||||
Nat.add_lt_add_right (Nat.lt_of_le_of_lt h.2 (by decide)) _
|
||||
exact .inl (lt_of_eq_of_lt (Nat.mod_eq_of_lt (Nat.lt_trans h (by decide))) h)
|
||||
|
||||
/--
|
||||
Converts a lowercase ASCII letter to the corresponding uppercase letter. Letters outside the ASCII
|
||||
@@ -153,8 +160,20 @@ alphabet are returned unchanged.
|
||||
|
||||
The lowercase ASCII letters are the following: `abcdefghijklmnopqrstuvwxyz`.
|
||||
-/
|
||||
@[inline]
|
||||
def toUpper (c : Char) : Char :=
|
||||
let n := toNat c;
|
||||
if n >= 97 ∧ n <= 122 then ofNat (n - 32) else c
|
||||
if h : c.val ≥ 'a'.val ∧ c.val ≤ 'z'.val then
|
||||
⟨c.val + ('A'.val - 'a'.val), ?_⟩
|
||||
else
|
||||
c
|
||||
where finally
|
||||
have h₁ : 2^32 ≤ c.val.toNat + ('A'.val - 'a'.val).toNat :=
|
||||
@Nat.add_le_add 'a'.val.toNat _ (2^32 - 'a'.val.toNat) _ h.1 (by decide)
|
||||
have h₂ : c.val.toBitVec.toNat + ('A'.val - 'a'.val).toNat < 2^32 + 0xd800 :=
|
||||
Nat.add_lt_add_right (Nat.lt_of_le_of_lt h.2 (by decide)) _
|
||||
have add_eq {x y : UInt32} : (x + y).toNat = (x.toNat + y.toNat) % 2^32 := rfl
|
||||
replace h₂ := Nat.sub_lt_left_of_lt_add h₁ h₂
|
||||
exact .inl <| lt_of_eq_of_lt (add_eq.trans (Nat.mod_eq_sub_mod h₁) |>.trans
|
||||
(Nat.mod_eq_of_lt (Nat.lt_trans h₂ (by decide)))) h₂
|
||||
|
||||
end Char
|
||||
|
||||
@@ -144,6 +144,8 @@ unsafe def foldlMUnsafe {β : Type v} {m : Type v → Type w} [Monad m] (f : β
|
||||
if start < stop then
|
||||
if stop ≤ as.size then
|
||||
fold (USize.ofNat start) (USize.ofNat stop) init
|
||||
else if start < as.size then
|
||||
fold (USize.ofNat start) (USize.ofNat as.size) init
|
||||
else
|
||||
pure init
|
||||
else
|
||||
|
||||
@@ -113,6 +113,8 @@ theorem gcd_eq_right_iff_dvd (hb : 0 ≤ b) : gcd a b = b ↔ b ∣ a := by
|
||||
|
||||
theorem gcd_assoc (a b c : Int) : gcd (gcd a b) c = gcd a (gcd b c) := Nat.gcd_assoc ..
|
||||
|
||||
theorem gcd_left_comm (a b c : Int) : gcd a (gcd b c) = gcd b (gcd a c) := Nat.gcd_left_comm ..
|
||||
|
||||
theorem gcd_mul_left (m n k : Int) : gcd (m * n) (m * k) = m.natAbs * gcd n k := by
|
||||
simp [gcd_eq_natAbs_gcd_natAbs, Nat.gcd_mul_left, natAbs_mul]
|
||||
|
||||
|
||||
@@ -333,6 +333,12 @@ protected theorem sub_sub_self (a b : Int) : a - (a - b) = b := by
|
||||
@[simp] protected theorem add_sub_cancel (a b : Int) : a + b - b = a :=
|
||||
Int.add_neg_cancel_right a b
|
||||
|
||||
protected theorem add_sub_add_right (n k m : Int) : (n + k) - (m + k) = n - m := by
|
||||
rw [Int.add_comm m, ← Int.sub_sub, Int.add_sub_cancel]
|
||||
|
||||
protected theorem add_sub_add_left (k n m : Int) : (k + n) - (k + m) = n - m := by
|
||||
rw [Int.add_comm k, Int.add_comm k, Int.add_sub_add_right]
|
||||
|
||||
protected theorem add_sub_assoc (a b c : Int) : a + b - c = a + (b - c) := by
|
||||
rw [Int.sub_eq_add_neg, Int.add_assoc, Int.add_neg_eq_sub]
|
||||
|
||||
@@ -546,6 +552,7 @@ protected theorem mul_eq_zero {a b : Int} : a * b = 0 ↔ a = 0 ∨ b = 0 := by
|
||||
| .ofNat 0, _, _ => by simp
|
||||
| _, .ofNat 0, _ => by simp
|
||||
| .ofNat (_+1), .negSucc _, h => by cases h
|
||||
| .negSucc _, .negSucc _, h => by cases h
|
||||
|
||||
protected theorem mul_ne_zero {a b : Int} (a0 : a ≠ 0) (b0 : b ≠ 0) : a * b ≠ 0 :=
|
||||
Or.rec a0 b0 ∘ Int.mul_eq_zero.mp
|
||||
|
||||
@@ -474,6 +474,20 @@ protected theorem max_lt {a b c : Int} : max a b < c ↔ a < c ∧ b < c := by
|
||||
simp only [Int.lt_iff_add_one_le]
|
||||
simpa using Int.max_le (a := a + 1) (b := b + 1) (c := c)
|
||||
|
||||
protected theorem max_eq_right_iff {a b : Int} : max a b = b ↔ a ≤ b := by
|
||||
apply Iff.intro
|
||||
· intro h
|
||||
rw [← h]
|
||||
apply Int.le_max_left
|
||||
· apply Int.max_eq_right
|
||||
|
||||
protected theorem max_eq_left_iff {a b : Int} : max a b = a ↔ b ≤ a := by
|
||||
apply Iff.intro
|
||||
· intro h
|
||||
rw [← h]
|
||||
apply Int.le_max_right
|
||||
· apply Int.max_eq_left
|
||||
|
||||
@[simp] theorem ofNat_max_zero (n : Nat) : (max (n : Int) 0) = n := by
|
||||
rw [Int.max_eq_left (natCast_nonneg n)]
|
||||
|
||||
@@ -912,6 +926,16 @@ protected theorem sub_right_le_of_le_add {a b c : Int} (h : a ≤ b + c) : a - c
|
||||
have h := Int.add_le_add_right h (-c)
|
||||
rwa [Int.add_neg_cancel_right] at h
|
||||
|
||||
protected theorem sub_right_le_iff_le_add {a b c : Int} : a - c ≤ b ↔ a ≤ b + c :=
|
||||
⟨Int.le_add_of_sub_right_le, Int.sub_right_le_of_le_add⟩
|
||||
|
||||
theorem toNat_sub_eq_zero_iff (m n : Int) : toNat (m - n) = 0 ↔ m ≤ n := by
|
||||
rw [← ofNat_inj, ofNat_toNat, cast_ofNat_Int, Int.max_eq_right_iff, Int.sub_right_le_iff_le_add,
|
||||
Int.zero_add]
|
||||
|
||||
theorem zero_eq_toNat_sub_iff (m n : Int) : 0 = toNat (m - n) ↔ m ≤ n := by
|
||||
rw [eq_comm (a := 0), toNat_sub_eq_zero_iff]
|
||||
|
||||
protected theorem le_add_of_neg_add_le_left {a b c : Int} (h : -b + a ≤ c) : a ≤ b + c := by
|
||||
rw [Int.add_comm] at h
|
||||
exact Int.le_add_of_sub_left_le h
|
||||
@@ -989,6 +1013,10 @@ protected theorem lt_sub_right_of_add_lt {a b c : Int} (h : a + b < c) : a < c -
|
||||
have h := Int.add_lt_add_right h (-b)
|
||||
rwa [Int.add_neg_cancel_right] at h
|
||||
|
||||
protected theorem lt_sub_right_iff_add_lt {a b c : Int} :
|
||||
a < c - b ↔ a + b < c :=
|
||||
⟨Int.add_lt_of_lt_sub_right, Int.lt_sub_right_of_add_lt⟩
|
||||
|
||||
protected theorem lt_add_of_neg_add_lt {a b c : Int} (h : -b + a < c) : a < b + c := by
|
||||
have h := Int.add_lt_add_left h b
|
||||
rwa [Int.add_neg_cancel_left] at h
|
||||
|
||||
@@ -10,6 +10,7 @@ public import Init.Classical
|
||||
public import Init.Ext
|
||||
|
||||
set_option doc.verso true
|
||||
set_option linter.missingDocs true
|
||||
|
||||
public section
|
||||
|
||||
@@ -77,8 +78,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 +123,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 : α
|
||||
|
||||
@@ -293,6 +293,11 @@ theorem IterStep.mapIterator_id {step : IterStep α β} :
|
||||
step.mapIterator id = step := by
|
||||
cases step <;> rfl
|
||||
|
||||
@[simp]
|
||||
theorem IterStep.mapIterator_id' {step : IterStep α β} :
|
||||
step.mapIterator (fun x => x) = step := by
|
||||
cases step <;> rfl
|
||||
|
||||
/--
|
||||
A variant of `IterStep` that bundles the step together with a proof that it is "plausible".
|
||||
The plausibility predicate will later be chosen to assert that a state is a plausible successor
|
||||
@@ -306,7 +311,7 @@ def PlausibleIterStep (IsPlausibleStep : IterStep α β → Prop) := Subtype IsP
|
||||
/--
|
||||
Match pattern for the `yield` case. See also `IterStep.yield`.
|
||||
-/
|
||||
@[match_pattern, simp, expose]
|
||||
@[match_pattern, simp, spec, expose]
|
||||
def PlausibleIterStep.yield {IsPlausibleStep : IterStep α β → Prop}
|
||||
(it' : α) (out : β) (h : IsPlausibleStep (.yield it' out)) :
|
||||
PlausibleIterStep IsPlausibleStep :=
|
||||
@@ -315,7 +320,7 @@ def PlausibleIterStep.yield {IsPlausibleStep : IterStep α β → Prop}
|
||||
/--
|
||||
Match pattern for the `skip` case. See also `IterStep.skip`.
|
||||
-/
|
||||
@[match_pattern, simp, expose]
|
||||
@[match_pattern, simp, grind =, expose]
|
||||
def PlausibleIterStep.skip {IsPlausibleStep : IterStep α β → Prop}
|
||||
(it' : α) (h : IsPlausibleStep (.skip it')) : PlausibleIterStep IsPlausibleStep :=
|
||||
⟨.skip it', h⟩
|
||||
@@ -323,7 +328,7 @@ def PlausibleIterStep.skip {IsPlausibleStep : IterStep α β → Prop}
|
||||
/--
|
||||
Match pattern for the `done` case. See also `IterStep.done`.
|
||||
-/
|
||||
@[match_pattern, simp, expose]
|
||||
@[match_pattern, simp, grind =, expose]
|
||||
def PlausibleIterStep.done {IsPlausibleStep : IterStep α β → Prop}
|
||||
(h : IsPlausibleStep .done) : PlausibleIterStep IsPlausibleStep :=
|
||||
⟨.done, h⟩
|
||||
@@ -345,34 +350,51 @@ abbrev PlausibleIterStep.casesOn {IsPlausibleStep : IterStep α β → Prop}
|
||||
end IterStep
|
||||
|
||||
/--
|
||||
The typeclass providing the step function of an iterator in `Iter (α := α) β` or
|
||||
`IterM (α := α) m β`.
|
||||
The step function of an iterator in `Iter (α := α) β` or `IterM (α := α) m β`.
|
||||
|
||||
In order to allow intrinsic termination proofs when iterating with the `step` function, the
|
||||
step object is bundled with a proof that it is a "plausible" step for the given current iterator.
|
||||
-/
|
||||
class Iterator (α : Type w) (m : Type w → Type w') (β : outParam (Type w)) where
|
||||
/--
|
||||
A relation that governs the allowed steps from a given iterator.
|
||||
|
||||
The "plausible" steps are those which make sense for a given state; plausibility can ensure
|
||||
properties such as the successor iterator being drawn from the same collection, that an iterator
|
||||
resulting from a skip will return the same next value, or that the next item yielded is next one
|
||||
in the original collection.
|
||||
-/
|
||||
IsPlausibleStep : IterM (α := α) m β → IterStep (IterM (α := α) m β) β → Prop
|
||||
/--
|
||||
Carries out a step of iteration.
|
||||
-/
|
||||
step : (it : IterM (α := α) m β) → m (Shrink <| PlausibleIterStep <| IsPlausibleStep it)
|
||||
|
||||
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, inherit_doc IterM.mk]
|
||||
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
|
||||
|
||||
set_option linter.missingDocs false in
|
||||
@[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
|
||||
|
||||
/--
|
||||
@@ -449,8 +471,10 @@ number of steps.
|
||||
-/
|
||||
inductive IterM.IsPlausibleIndirectOutput {α β : Type w} {m : Type w → Type w'} [Iterator α m β]
|
||||
: IterM (α := α) m β → β → Prop where
|
||||
/-- The output value could plausibly be emitted in the next step. -/
|
||||
| direct {it : IterM (α := α) m β} {out : β} : it.IsPlausibleOutput out →
|
||||
it.IsPlausibleIndirectOutput out
|
||||
/-- The output value could plausibly be emitted in a step after the next step. -/
|
||||
| indirect {it it' : IterM (α := α) m β} {out : β} : it'.IsPlausibleSuccessorOf it →
|
||||
it'.IsPlausibleIndirectOutput out → it.IsPlausibleIndirectOutput out
|
||||
|
||||
@@ -460,7 +484,9 @@ finitely many steps. This relation is reflexive.
|
||||
-/
|
||||
inductive IterM.IsPlausibleIndirectSuccessorOf {α β : Type w} {m : Type w → Type w'}
|
||||
[Iterator α m β] : IterM (α := α) m β → IterM (α := α) m β → Prop where
|
||||
/-- Every iterator is a plausible indirect successor of itself. -/
|
||||
| refl (it : IterM (α := α) m β) : it.IsPlausibleIndirectSuccessorOf it
|
||||
/-- The iterator is a plausible successor of one of the current iterator's successors. -/
|
||||
| cons_right {it'' it' it : IterM (α := α) m β} (h' : it''.IsPlausibleIndirectSuccessorOf it')
|
||||
(h : it'.IsPlausibleSuccessorOf it) : it''.IsPlausibleIndirectSuccessorOf it
|
||||
|
||||
@@ -585,8 +611,10 @@ number of steps.
|
||||
-/
|
||||
inductive Iter.IsPlausibleIndirectOutput {α β : Type w} [Iterator α Id β] :
|
||||
Iter (α := α) β → β → Prop where
|
||||
/-- The output value could plausibly be emitted in the next step. -/
|
||||
| direct {it : Iter (α := α) β} {out : β} : it.IsPlausibleOutput out →
|
||||
it.IsPlausibleIndirectOutput out
|
||||
/-- The output value could plausibly be emitted in a step after the next step. -/
|
||||
| indirect {it it' : Iter (α := α) β} {out : β} : it'.IsPlausibleSuccessorOf it →
|
||||
it'.IsPlausibleIndirectOutput out → it.IsPlausibleIndirectOutput out
|
||||
|
||||
@@ -617,7 +645,9 @@ finitely many steps. This relation is reflexive.
|
||||
-/
|
||||
inductive Iter.IsPlausibleIndirectSuccessorOf {α : Type w} {β : Type w} [Iterator α Id β] :
|
||||
Iter (α := α) β → Iter (α := α) β → Prop where
|
||||
/-- Every iterator is a plausible indirect successor of itself. -/
|
||||
| refl (it : Iter (α := α) β) : IsPlausibleIndirectSuccessorOf it it
|
||||
/-- The iterator is a plausible indirect successor of one of the current iterator's successors. -/
|
||||
| cons_right {it'' it' it : Iter (α := α) β} (h' : it''.IsPlausibleIndirectSuccessorOf it')
|
||||
(h : it'.IsPlausibleSuccessorOf it) : it''.IsPlausibleIndirectSuccessorOf it
|
||||
|
||||
@@ -677,11 +707,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
|
||||
|
||||
@@ -691,6 +721,11 @@ recursion over finite iterators. See also `IterM.finitelyManySteps` and `Iter.fi
|
||||
-/
|
||||
structure IterM.TerminationMeasures.Finite
|
||||
(α : Type w) (m : Type w → Type w') {β : Type w} [Iterator α m β] where
|
||||
/--
|
||||
The wrapped iterator.
|
||||
|
||||
In the wrapper, its finiteness is used as a termination measure.
|
||||
-/
|
||||
it : IterM (α := α) m β
|
||||
|
||||
/--
|
||||
@@ -703,10 +738,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 +750,7 @@ 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⟩
|
||||
|
||||
/--
|
||||
@@ -756,7 +792,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
|
||||
|
||||
@@ -806,7 +842,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))
|
||||
|
||||
@@ -816,6 +852,11 @@ recursion over productive iterators. See also `IterM.finitelyManySkips` and `Ite
|
||||
-/
|
||||
structure IterM.TerminationMeasures.Productive
|
||||
(α : Type w) (m : Type w → Type w') {β : Type w} [Iterator α m β] where
|
||||
/--
|
||||
The wrapped iterator.
|
||||
|
||||
In the wrapper, its productivity is used as a termination measure.
|
||||
-/
|
||||
it : IterM (α := α) m β
|
||||
|
||||
/--
|
||||
@@ -846,10 +887,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
|
||||
@@ -857,7 +899,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⟩
|
||||
|
||||
/--
|
||||
@@ -876,7 +918,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
|
||||
|
||||
@@ -895,12 +937,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
|
||||
|
||||
@@ -917,10 +960,63 @@ library.
|
||||
-/
|
||||
class LawfulDeterministicIterator (α : Type w) (m : Type w → Type w') [Iterator α m β]
|
||||
where
|
||||
/--
|
||||
Every iterator with state `α` in monad `m` has exactly one plausible step.
|
||||
-/
|
||||
isPlausibleStep_eq_eq : ∀ it : IterM (α := α) m β, ∃ step, it.IsPlausibleStep = (· = step)
|
||||
|
||||
end Iterators
|
||||
namespace Iterators
|
||||
|
||||
export Iterators (Iter IterM)
|
||||
/--
|
||||
This structure provides a more convenient way to define `Finite α m` instances using
|
||||
`Finite.of_finitenessRelation : FinitenessRelation α m → Finite α m`.
|
||||
-/
|
||||
structure FinitenessRelation (α : Type w) (m : Type w → Type w') {β : Type w}
|
||||
[Iterator α m β] where
|
||||
/--
|
||||
A well-founded relation such that if `it'` is a successor iterator of `it`, then `Rel it' it`.
|
||||
-/
|
||||
Rel (it' it : IterM (α := α) m β) : Prop
|
||||
/-- `Rel` is well-founded. -/
|
||||
wf : WellFounded Rel
|
||||
/-- If `it'` is a successor iterator of `it`, then `Rel it' it`. -/
|
||||
subrelation : ∀ {it it'}, it'.IsPlausibleSuccessorOf it → Rel it' it
|
||||
|
||||
end Std
|
||||
theorem Finite.of_finitenessRelation
|
||||
{α : Type w} {m : Type w → Type w'} {β : Type w}
|
||||
[Iterator α m β] (r : FinitenessRelation α m) : Finite α m where
|
||||
wf := by
|
||||
refine Subrelation.wf (r := r.Rel) ?_ ?_
|
||||
· intro x y h
|
||||
apply FinitenessRelation.subrelation
|
||||
exact h
|
||||
· apply InvImage.wf
|
||||
exact r.wf
|
||||
|
||||
/--
|
||||
This structure provides a more convenient way to define `Productive α m` instances using
|
||||
`Productive.of_productivenessRelation : ProductivenessRelation α m → Productive α m`.
|
||||
-/
|
||||
structure ProductivenessRelation (α : Type w) (m : Type w → Type w') {β : Type w}
|
||||
[Iterator α m β] where
|
||||
/--
|
||||
A well-founded relation such that if `it'` is obtained from `it` by skipping, then `Rel it' it`.
|
||||
-/
|
||||
Rel : (IterM (α := α) m β) → (IterM (α := α) m β) → Prop
|
||||
/-- `Rel` is well-founded. -/
|
||||
wf : WellFounded Rel
|
||||
/-- If `it'` is obtained from `it` by skipping, then `Rel it' it`. -/
|
||||
subrelation : ∀ {it it'}, it'.IsPlausibleSkipSuccessorOf it → Rel it' it
|
||||
|
||||
theorem Productive.of_productivenessRelation
|
||||
{α : Type w} {m : Type w → Type w'} {β : Type w}
|
||||
[Iterator α m β] (r : ProductivenessRelation α m) : Productive α m where
|
||||
wf := by
|
||||
refine Subrelation.wf (r := r.Rel) ?_ ?_
|
||||
· intro x y h
|
||||
apply ProductivenessRelation.subrelation
|
||||
exact h
|
||||
· apply InvImage.wf
|
||||
exact r.wf
|
||||
|
||||
end Std.Iterators
|
||||
|
||||
@@ -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.
|
||||
@@ -197,12 +198,8 @@ it.filterMapM ---a'-----c'-------⊥
|
||||
For certain mapping functions `f`, the resulting iterator will be finite (or productive) even though
|
||||
no `Finite` (or `Productive`) instance is provided. For example, if `f` never returns `none`, then
|
||||
this combinator will preserve productiveness. If `f` is an `ExceptT` monad and will always fail,
|
||||
then `it.filterMapM` will be finite even if `it` isn't. In the first case, consider
|
||||
using the `map`/`mapM`/`mapWithPostcondition` combinators instead, which provide more instances out
|
||||
of the box.
|
||||
|
||||
If that does not help, the more general combinator `it.filterMapWithPostcondition f` makes it
|
||||
possible to manually prove `Finite` and `Productive` instances depending on the concrete choice of `f`.
|
||||
then `it.filterMapM` will be finite even if `it` isn't. In such cases, the termination proof needs
|
||||
to be done manually.
|
||||
|
||||
**Performance:**
|
||||
|
||||
@@ -211,7 +208,7 @@ returned `Option` value.
|
||||
-/
|
||||
@[always_inline, inline, expose]
|
||||
def Iter.filterMapM {α β γ : Type w} [Iterator α Id β] {m : Type w → Type w'}
|
||||
[Monad m] (f : β → m (Option γ)) (it : Iter (α := α) β) :=
|
||||
[Monad m] [MonadAttach m] (f : β → m (Option γ)) (it : Iter (α := α) β) :=
|
||||
(letI : MonadLift Id m := ⟨pure⟩; it.toIterM.filterMapM f : IterM m γ)
|
||||
|
||||
/--
|
||||
@@ -237,10 +234,7 @@ it.filterM ---a-----c-------⊥
|
||||
For certain mapping functions `f`, the resulting iterator will be finite (or productive) even though
|
||||
no `Finite` (or `Productive`) instance is provided. For example, if `f` is an `ExceptT` monad and
|
||||
will always fail, then `it.filterWithPostcondition` will be finite -- and productive -- even if `it`
|
||||
isn't.
|
||||
|
||||
In such situations, the more general combinator `it.filterWithPostcondition f` makes it possible to
|
||||
manually prove `Finite` and `Productive` instances depending on the concrete choice of `f`.
|
||||
isn't. In such cases, the termination proof needs to be done manually.
|
||||
|
||||
**Performance:**
|
||||
|
||||
@@ -248,7 +242,7 @@ For each value emitted by the base iterator `it`, this combinator calls `f`.
|
||||
-/
|
||||
@[always_inline, inline, expose]
|
||||
def Iter.filterM {α β : Type w} [Iterator α Id β] {m : Type w → Type w'}
|
||||
[Monad m] (f : β → m (ULift Bool)) (it : Iter (α := α) β) :=
|
||||
[Monad m] [MonadAttach m] (f : β → m (ULift Bool)) (it : Iter (α := α) β) :=
|
||||
(letI : MonadLift Id m := ⟨pure⟩; it.toIterM.filterM f : IterM m β)
|
||||
|
||||
/--
|
||||
@@ -276,10 +270,8 @@ it.mapM ---a'--b'--c'--d'-e'----⊥
|
||||
|
||||
For certain mapping functions `f`, the resulting iterator will be finite (or productive) even though
|
||||
no `Finite` (or `Productive`) instance is provided. For example, if `f` is an `ExceptT` monad and
|
||||
will always fail, then `it.mapM` will be finite even if `it` isn't.
|
||||
|
||||
If that does not help, the more general combinator `it.mapWithPostcondition f` makes it possible to
|
||||
manually prove `Finite` and `Productive` instances depending on the concrete choice of `f`.
|
||||
will always fail, then `it.mapM` will be finite even if `it` isn't. In such cases, the termination
|
||||
proof needs to be done manually.
|
||||
|
||||
**Performance:**
|
||||
|
||||
@@ -287,7 +279,7 @@ For each value emitted by the base iterator `it`, this combinator calls `f`.
|
||||
-/
|
||||
@[always_inline, inline, expose]
|
||||
def Iter.mapM {α β γ : Type w} [Iterator α Id β] {m : Type w → Type w'}
|
||||
[Monad m] (f : β → m γ) (it : Iter (α := α) β) :=
|
||||
[Monad m] [MonadAttach m] (f : β → m γ) (it : Iter (α := α) β) :=
|
||||
(letI : MonadLift Id m := ⟨pure⟩; it.toIterM.mapM f : IterM m γ)
|
||||
|
||||
@[always_inline, inline, inherit_doc IterM.filterMap, expose]
|
||||
@@ -305,4 +297,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,17 +24,17 @@ 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}
|
||||
{γ : Type w} {m : Type w → Type w'} [Monad m] [Iterator α Id β] [Iterator α₂ m γ]
|
||||
{γ : Type w} {m : Type w → Type w'} [Monad m] [MonadAttach m] [Iterator α Id β] [Iterator α₂ m γ]
|
||||
(f : β → m (IterM (α := α₂) m γ)) (it₁ : Iter (α := α) β) (it₂ : Option (IterM (α := α₂) m γ)) :=
|
||||
((it₁.mapM pure).flatMapAfterM f it₂ : IterM m γ)
|
||||
((it₁.mapWithPostcondition pure).flatMapAfterM f it₂ : IterM m γ)
|
||||
|
||||
@[always_inline, expose, inherit_doc IterM.flatMapM]
|
||||
public def Iter.flatMapM {α : Type w} {β : Type w} {α₂ : Type w}
|
||||
{γ : Type w} {m : Type w → Type w'} [Monad m] [Iterator α Id β] [Iterator α₂ m γ]
|
||||
{γ : Type w} {m : Type w → Type w'} [Monad m] [MonadAttach m] [Iterator α Id β] [Iterator α₂ m γ]
|
||||
(f : β → m (IterM (α := α₂) m γ)) (it : Iter (α := α) β) :=
|
||||
(it.flatMapAfterM f none : IterM m γ)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -6,7 +6,6 @@ Authors: Paul Reichert
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Data.Iterators.Internal.Termination
|
||||
public import Init.Data.Iterators.Consumers.Loop
|
||||
|
||||
public section
|
||||
@@ -47,7 +46,7 @@ instance Attach.instIterator {α β : Type w} {m : Type w → Type w'} [Monad m]
|
||||
def Attach.instFinitenessRelation {α β : Type w} {m : Type w → Type w'} [Monad m]
|
||||
[Iterator α m β] [Finite α m] {P : β → Prop} :
|
||||
FinitenessRelation (Attach α m P) m where
|
||||
rel := InvImage WellFoundedRelation.rel fun it => it.internalState.inner.finitelyManySteps
|
||||
Rel := InvImage WellFoundedRelation.rel fun it => it.internalState.inner.finitelyManySteps
|
||||
wf := InvImage.wf _ WellFoundedRelation.wf
|
||||
subrelation {it it'} h := by
|
||||
apply Relation.TransGen.single
|
||||
@@ -68,7 +67,7 @@ instance Attach.instFinite {α β : Type w} {m : Type w → Type w'} [Monad m]
|
||||
def Attach.instProductivenessRelation {α β : Type w} {m : Type w → Type w'} [Monad m]
|
||||
[Iterator α m β] [Productive α m] {P : β → Prop} :
|
||||
ProductivenessRelation (Attach α m P) m where
|
||||
rel := InvImage WellFoundedRelation.rel fun it => it.internalState.inner.finitelyManySkips
|
||||
Rel := InvImage WellFoundedRelation.rel fun it => it.internalState.inner.finitelyManySkips
|
||||
wf := InvImage.wf _ WellFoundedRelation.wf
|
||||
subrelation {it it'} h := by
|
||||
apply Relation.TransGen.single
|
||||
@@ -86,17 +85,12 @@ instance Attach.instProductive {α β : Type w} {m : Type w → Type w'} [Monad
|
||||
Productive (Attach α m P) m :=
|
||||
.of_productivenessRelation instProductivenessRelation
|
||||
|
||||
instance Attach.instIteratorCollect {α β : Type w} {m : Type w → Type w'} [Monad m] [Monad n]
|
||||
{P : β → Prop} [Iterator α m β] :
|
||||
IteratorCollect (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
|
||||
|
||||
end Types
|
||||
end Iterators.Types
|
||||
|
||||
/--
|
||||
“Attaches” individual proofs to an iterator of values that satisfy a predicate `P`, returning an
|
||||
@@ -111,7 +105,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
|
||||
|
||||
@@ -8,7 +8,6 @@ module
|
||||
prelude
|
||||
public import Init.Data.Iterators.Consumers.Loop
|
||||
public import Init.Data.Iterators.PostconditionMonad
|
||||
public import Init.Data.Iterators.Internal.Termination
|
||||
|
||||
public section
|
||||
|
||||
@@ -32,7 +31,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 +54,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,
|
||||
@@ -117,16 +122,18 @@ returned `Option` value.
|
||||
def IterM.filterMapWithPostcondition {α β γ : Type w} {m : Type w → Type w'} {n : Type w → Type w''}
|
||||
[MonadLiftT m n] [Iterator α m β] (f : β → PostconditionT n (Option γ))
|
||||
(it : IterM (α := α) m β) : IterM (α := FilterMap α m n (fun ⦃_⦄ => monadLift) f) n γ :=
|
||||
IterM.InternalCombinators.filterMap (fun ⦃_⦄ => monadLift) f it
|
||||
IterM.InternalCombinators.filterMap (n := n) (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 +146,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 +162,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 γ
|
||||
|
||||
@@ -165,7 +171,7 @@ private def FilterMap.instFinitenessRelation {α β γ : Type w} {m : Type w →
|
||||
{n : Type w → Type w''} [Monad n] [Iterator α m β] {lift : ⦃α : Type w⦄ → m α → n α}
|
||||
{f : β → PostconditionT n (Option γ)} [Finite α m] :
|
||||
FinitenessRelation (FilterMap α m n lift f) n where
|
||||
rel := InvImage IterM.IsPlausibleSuccessorOf (FilterMap.inner ∘ IterM.internalState)
|
||||
Rel := InvImage IterM.IsPlausibleSuccessorOf (FilterMap.inner ∘ IterM.internalState)
|
||||
wf := InvImage.wf _ Finite.wf
|
||||
subrelation {it it'} h := by
|
||||
obtain ⟨step, h, h'⟩ := h
|
||||
@@ -189,8 +195,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
|
||||
|
||||
@@ -198,7 +204,7 @@ private def Map.instProductivenessRelation {α β γ : Type w} {m : Type w → T
|
||||
{n : Type w → Type w''} [Monad n] [Iterator α m β] {lift : ⦃α : Type w⦄ → m α → n α}
|
||||
{f : β → PostconditionT n γ} [Productive α m] :
|
||||
ProductivenessRelation (Map α m n lift f) n where
|
||||
rel := InvImage IterM.IsPlausibleSkipSuccessorOf (FilterMap.inner ∘ IterM.internalState)
|
||||
Rel := InvImage IterM.IsPlausibleSkipSuccessorOf (FilterMap.inner ∘ IterM.internalState)
|
||||
wf := InvImage.wf _ Productive.wf
|
||||
subrelation {it it'} h := by
|
||||
cases h
|
||||
@@ -214,13 +220,6 @@ 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'}
|
||||
{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 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 α}
|
||||
@@ -228,23 +227,6 @@ instance FilterMap.instIteratorLoop {α β γ : Type w} {m : Type w → Type w'}
|
||||
IteratorLoop (FilterMap α m n lift f) n o :=
|
||||
.defaultImplementation
|
||||
|
||||
/--
|
||||
`map` operations allow for a more efficient implementation of `toArray`. For example,
|
||||
`array.iter.map f |>.toArray happens in-place if possible.
|
||||
-/
|
||||
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] :
|
||||
IteratorCollect (Map α m n lift₁ f) n o where
|
||||
toArrayMapped lift₂ _ g it :=
|
||||
letI : MonadLift m n := ⟨lift₁ (α := _)⟩
|
||||
letI : MonadLift n o := ⟨lift₂ (δ := _)⟩
|
||||
IteratorCollect.toArrayMapped
|
||||
(lift := fun ⦃_⦄ => monadLift)
|
||||
(fun x => do g (← (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 α}
|
||||
@@ -252,6 +234,8 @@ instance Map.instIteratorLoop {α β γ : Type w} {m : Type w → Type w'}
|
||||
IteratorLoop (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
|
||||
types and termination proofs. The variants `map` and `mapM` are easier to use and sufficient
|
||||
@@ -373,12 +357,8 @@ it.filterMapM ---a'-----c'-------⊥
|
||||
For certain mapping functions `f`, the resulting iterator will be finite (or productive) even though
|
||||
no `Finite` (or `Productive`) instance is provided. For example, if `f` never returns `none`, then
|
||||
this combinator will preserve productiveness. If `f` is an `ExceptT` monad and will always fail,
|
||||
then `it.filterMapM` will be finite even if `it` isn't. In the first case, consider
|
||||
using the `map`/`mapM`/`mapWithPostcondition` combinators instead, which provide more instances out of
|
||||
the box.
|
||||
|
||||
If that does not help, the more general combinator `it.filterMapWithPostcondition f` makes it
|
||||
possible to manually prove `Finite` and `Productive` instances depending on the concrete choice of `f`.
|
||||
then `it.filterMapM` will be finite even if `it` isn't. In such cases, the termination proof needs
|
||||
to be done manually.
|
||||
|
||||
**Performance:**
|
||||
|
||||
@@ -387,9 +367,9 @@ returned `Option` value.
|
||||
-/
|
||||
@[inline, expose]
|
||||
def IterM.filterMapM {α β γ : Type w} {m : Type w → Type w'} {n : Type w → Type w''}
|
||||
[Iterator α m β] [Monad n] [MonadLiftT m n]
|
||||
[Iterator α m β] [Monad n] [MonadAttach n] [MonadLiftT m n]
|
||||
(f : β → n (Option γ)) (it : IterM (α := α) m β) :=
|
||||
(it.filterMapWithPostcondition (fun b => PostconditionT.lift (f b)) : IterM n γ)
|
||||
(it.filterMapWithPostcondition (fun b => PostconditionT.attachLift (f b)) : IterM n γ)
|
||||
|
||||
/--
|
||||
If `it` is an iterator, then `it.mapM f` is another iterator that applies a monadic
|
||||
@@ -416,10 +396,8 @@ it.mapM ---a'--b'--c'--d'-e'----⊥
|
||||
|
||||
For certain mapping functions `f`, the resulting iterator will be finite (or productive) even though
|
||||
no `Finite` (or `Productive`) instance is provided. For example, if `f` is an `ExceptT` monad and
|
||||
will always fail, then `it.mapM` will be finite even if `it` isn't.
|
||||
|
||||
If that does not help, the more general combinator `it.mapWithPostcondition f` makes it possible to
|
||||
manually prove `Finite` and `Productive` instances depending on the concrete choice of `f`.
|
||||
will always fail, then `it.mapM` will be finite even if `it` isn't. In such cases, the termination
|
||||
proof needs to be done manually.
|
||||
|
||||
**Performance:**
|
||||
|
||||
@@ -427,8 +405,8 @@ For each value emitted by the base iterator `it`, this combinator calls `f`.
|
||||
-/
|
||||
@[inline, expose]
|
||||
def IterM.mapM {α β γ : Type w} {m : Type w → Type w'} {n : Type w → Type w''} [Iterator α m β]
|
||||
[Monad n] [MonadLiftT m n] (f : β → n γ) (it : IterM (α := α) m β) :=
|
||||
(it.mapWithPostcondition (fun b => PostconditionT.lift (f b)) : IterM n γ)
|
||||
[Monad n] [MonadAttach n] [MonadLiftT m n] (f : β → n γ) (it : IterM (α := α) m β) :=
|
||||
(it.mapWithPostcondition (fun b => PostconditionT.attachLift (f b)) : IterM n γ)
|
||||
|
||||
/--
|
||||
If `it` is an iterator, then `it.filterM f` is another iterator that applies a monadic
|
||||
@@ -456,10 +434,7 @@ it.filterM ---a-----c-------⊥
|
||||
For certain mapping functions `f`, the resulting iterator will be finite (or productive) even though
|
||||
no `Finite` (or `Productive`) instance is provided. For example, if `f` is an `ExceptT` monad and
|
||||
will always fail, then `it.filterWithPostcondition` will be finite -- and productive -- even if `it`
|
||||
isn't.
|
||||
|
||||
In such situations, the more general combinator `it.filterWithPostcondition f` makes it possible to
|
||||
manually prove `Finite` and `Productive` instances depending on the concrete choice of `f`.
|
||||
isn't. In such cases, the termination proof needs to be done manually.
|
||||
|
||||
**Performance:**
|
||||
|
||||
@@ -467,9 +442,9 @@ For each value emitted by the base iterator `it`, this combinator calls `f`.
|
||||
-/
|
||||
@[inline, expose]
|
||||
def IterM.filterM {α β : Type w} {m : Type w → Type w'} {n : Type w → Type w''} [Iterator α m β]
|
||||
[Monad n] [MonadLiftT m n] (f : β → n (ULift Bool)) (it : IterM (α := α) m β) :=
|
||||
[Monad n] [MonadAttach n] [MonadLiftT m n] (f : β → n (ULift Bool)) (it : IterM (α := α) m β) :=
|
||||
(it.filterMapWithPostcondition
|
||||
(fun b => (PostconditionT.lift (f b)).map (if ·.down = true then some b else none)) : IterM n β)
|
||||
(fun b => (PostconditionT.attachLift (f b)).map (if ·.down = true then some b else none)) : IterM n β)
|
||||
|
||||
/--
|
||||
If `it` is an iterator, then `it.filterMap f` is another iterator that applies a function `f` to all
|
||||
@@ -571,4 +546,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,11 +22,12 @@ 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 β)
|
||||
|
||||
@@ -37,7 +38,7 @@ Internal iterator combinator that is used to implement all `flatMap` variants
|
||||
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
|
||||
@@ -77,7 +78,7 @@ For each value emitted by the outer iterator `it₁`, this combinator calls `f`.
|
||||
-/
|
||||
@[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 γ]
|
||||
{γ : Type w} {m : Type w → Type w'} [Monad m] [MonadAttach m] [Iterator α m β] [Iterator α₂ m γ]
|
||||
(f : β → m (IterM (α := α₂) m γ)) (it₁ : IterM (α := α) m β) (it₂ : Option (IterM (α := α₂) m γ)) :=
|
||||
((it₁.mapM f).flattenAfter it₂ : IterM m γ)
|
||||
|
||||
@@ -116,7 +117,7 @@ For each value emitted by the outer iterator `it`, this combinator calls `f`.
|
||||
-/
|
||||
@[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 γ]
|
||||
{γ : Type w} {m : Type w → Type w'} [Monad m] [MonadAttach m] [Iterator α m β] [Iterator α₂ m γ]
|
||||
(f : β → m (IterM (α := α₂) m γ)) (it : IterM (α := α) m β) :=
|
||||
(it.flatMapAfterM f none : IterM m γ)
|
||||
|
||||
@@ -201,23 +202,25 @@ public def IterM.flatMap {α : Type w} {β : Type w} {α₂ : Type w}
|
||||
(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,10 +274,10 @@ 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
|
||||
Rel := Rel α β m
|
||||
wf := by
|
||||
apply InvImage.wf
|
||||
refine ⟨fun (a, b) => Prod.lexAccessible (WellFounded.apply ?_ a) (WellFounded.apply ?_) b⟩
|
||||
@@ -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,10 +339,10 @@ 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
|
||||
Rel := ProductiveRel α β m
|
||||
wf := by
|
||||
apply InvImage.wf
|
||||
refine ⟨fun (a, b) => Prod.lexAccessible (WellFounded.apply ?_ a) (WellFounded.apply ?_) b⟩
|
||||
@@ -360,18 +363,14 @@ 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
|
||||
|
||||
public instance Flatten.instIteratorCollect [Monad m] [Monad n] [Iterator α m (IterM (α := α₂) m β)]
|
||||
[Iterator α₂ m β] : IteratorCollect (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
|
||||
|
||||
end Std.Iterators
|
||||
end Std.Iterators.Types
|
||||
|
||||
@@ -9,7 +9,6 @@ prelude
|
||||
public import Init.Data.Nat.Lemmas
|
||||
public import Init.Data.Iterators.Consumers.Monadic.Collect
|
||||
public import Init.Data.Iterators.Consumers.Monadic.Loop
|
||||
public import Init.Data.Iterators.Internal.Termination
|
||||
|
||||
@[expose] public section
|
||||
|
||||
@@ -17,7 +16,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 +24,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 +39,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 +66,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 +92,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 +101,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) →
|
||||
@@ -161,7 +164,7 @@ theorem Take.rel_of_zero_of_inner [Monad m] [Iterator α m β]
|
||||
private def Take.instFinitenessRelation [Monad m] [Iterator α m β]
|
||||
[Productive α m] :
|
||||
FinitenessRelation (Take α m) m where
|
||||
rel := Take.Rel m
|
||||
Rel := Take.Rel m
|
||||
wf := by
|
||||
rw [Rel]
|
||||
split
|
||||
@@ -204,12 +207,8 @@ instance Take.instFinite [Monad m] [Iterator α m β] [Productive α m] :
|
||||
Finite (Take α m) m :=
|
||||
by exact Finite.of_finitenessRelation instFinitenessRelation
|
||||
|
||||
instance Take.instIteratorCollect {n : Type w → Type w'} [Monad m] [Monad n] [Iterator α m β] :
|
||||
IteratorCollect (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
|
||||
|
||||
end Std.Iterators
|
||||
end Std.Iterators.Types
|
||||
|
||||
@@ -6,16 +6,16 @@ Authors: Paul Reichert
|
||||
module
|
||||
|
||||
prelude
|
||||
public import Init.Data.Iterators.Internal.Termination
|
||||
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 +60,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 +78,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,9 +96,9 @@ 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)
|
||||
Rel := InvImage WellFoundedRelation.rel (fun it => it.internalState.inner.finitelyManySteps)
|
||||
wf := InvImage.wf _ WellFoundedRelation.wf
|
||||
subrelation h := by
|
||||
rcases h with ⟨_, hs, step, hp, rfl⟩
|
||||
@@ -105,13 +108,13 @@ 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)
|
||||
Rel := InvImage WellFoundedRelation.rel (fun it => it.internalState.inner.finitelyManySkips)
|
||||
wf := InvImage.wf _ WellFoundedRelation.wf
|
||||
subrelation h := by
|
||||
rcases h with ⟨step, hp, hs⟩
|
||||
@@ -119,18 +122,18 @@ 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.instIteratorCollect [Monad n] [Monad o] [Iterator α m β] :
|
||||
IteratorCollect (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
|
||||
@@ -149,9 +152,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
|
||||
|
||||
@@ -9,9 +9,12 @@ prelude
|
||||
public import Init.Data.Iterators.Consumers.Loop
|
||||
public import Init.Data.Iterators.Consumers.Monadic.Access
|
||||
|
||||
set_option linter.missingDocs true
|
||||
|
||||
@[expose] public section
|
||||
|
||||
namespace Std.Iterators
|
||||
namespace Std
|
||||
open Std.Iterators
|
||||
|
||||
/--
|
||||
If possible, takes `n` steps with the iterator `it` and
|
||||
@@ -62,4 +65,4 @@ def Iter.atIdx? {α β} [Iterator α Id β] [Productive α Id] [IteratorAccess
|
||||
| .skip _ => none
|
||||
| .done => none
|
||||
|
||||
end Std.Iterators
|
||||
end Std
|
||||
|
||||
@@ -21,11 +21,10 @@ Concretely, the following operations are provided:
|
||||
* `Iter.toList`, collecting the values in a list
|
||||
* `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` type class.
|
||||
-/
|
||||
|
||||
namespace Std.Iterators
|
||||
namespace Std
|
||||
open Std.Iterators
|
||||
|
||||
/--
|
||||
Traverses the given iterator and stores the emitted values in an array.
|
||||
@@ -35,7 +34,7 @@ If the iterator is not finite, this function might run forever. The variant
|
||||
-/
|
||||
@[always_inline, inline]
|
||||
def Iter.toArray {α : Type w} {β : Type w}
|
||||
[Iterator α Id β] [IteratorCollect α Id Id] (it : Iter (α := α) β) : Array β :=
|
||||
[Iterator α Id β] (it : Iter (α := α) β) : Array β :=
|
||||
it.toIterM.toArray.run
|
||||
|
||||
/--
|
||||
@@ -45,7 +44,7 @@ This function is deprecated. Instead of `it.allowNontermination.toArray`, use `i
|
||||
-/
|
||||
@[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 β :=
|
||||
[Iterator α Id β] (it : Iter.Partial (α := α) β) : Array β :=
|
||||
it.it.toArray
|
||||
|
||||
/--
|
||||
@@ -56,7 +55,7 @@ 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 (α := α) β) :
|
||||
[Iterator α Id β] [Finite α Id] (it : Iter.Total (α := α) β) :
|
||||
Array β :=
|
||||
it.it.toArray
|
||||
|
||||
@@ -104,7 +103,7 @@ If the iterator is not finite, this function might run forever. The variant
|
||||
-/
|
||||
@[always_inline, inline]
|
||||
def Iter.toList {α : Type w} {β : Type w}
|
||||
[Iterator α Id β] [IteratorCollect α Id Id] (it : Iter (α := α) β) : List β :=
|
||||
[Iterator α Id β] (it : Iter (α := α) β) : List β :=
|
||||
it.toIterM.toList.run
|
||||
|
||||
/--
|
||||
@@ -115,7 +114,7 @@ This function is deprecated. Instead of `it.allowNontermination.toList`, use `it
|
||||
-/
|
||||
@[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 β :=
|
||||
[Iterator α Id β] (it : Iter.Partial (α := α) β) : List β :=
|
||||
it.it.toList
|
||||
|
||||
/--
|
||||
@@ -127,8 +126,8 @@ 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 (α := α) β) :
|
||||
[Iterator α Id β] [Finite α Id] (it : Iter.Total (α := α) β) :
|
||||
List β :=
|
||||
it.it.toList
|
||||
|
||||
end Std.Iterators
|
||||
end Std
|
||||
|
||||
@@ -26,7 +26,8 @@ function in every iteration. Concretely, the following operations are provided:
|
||||
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,
|
||||
@@ -677,4 +678,4 @@ def Iter.Partial.size {α : Type w} {β : Type w} [Iterator α Id β] [IteratorL
|
||||
(it : Iter.Partial (α := α) β) : Nat :=
|
||||
it.it.count
|
||||
|
||||
end Std.Iterators
|
||||
end Std
|
||||
|
||||
@@ -8,9 +8,12 @@ module
|
||||
prelude
|
||||
public import Init.Data.Iterators.Basic
|
||||
|
||||
set_option linter.missingDocs true
|
||||
|
||||
public section
|
||||
|
||||
namespace Std.Iterators
|
||||
namespace Std
|
||||
open Std.Iterators
|
||||
|
||||
/--
|
||||
`it.IsPlausibleNthOutputStep n step` is the proposition that according to the
|
||||
@@ -56,8 +59,8 @@ theorem IterM.not_isPlausibleNthOutputStep_yield {α β : Type w} {m : Type w
|
||||
|
||||
/--
|
||||
`IteratorAccess α m` provides efficient implementations for random access or iterators that support
|
||||
it. `it.nextAtIdx? n` either returns the step in which the `n`-th value of `it` is emitted
|
||||
(necessarily of the form `.yield _ _`) or `.done` if `it` terminates before emitting the `n`-th
|
||||
it. `it.nextAtIdx? n` either returns the step in which the `n`th value of `it` is emitted
|
||||
(necessarily of the form `.yield _ _`) or `.done` if `it` terminates before emitting the `n`th
|
||||
value.
|
||||
|
||||
For monadic iterators, the monadic effects of this operation may differ from manually iterating
|
||||
@@ -67,6 +70,11 @@ is guaranteed to plausible in the sense of `IterM.IsPlausibleNthOutputStep`.
|
||||
This class is experimental and users of the iterator API should not explicitly depend on it.
|
||||
-/
|
||||
class IteratorAccess (α : Type w) (m : Type w → Type w') {β : Type w} [Iterator α m β] where
|
||||
/--
|
||||
`nextAtIdx? it n` either returns the step in which the `n`th value of `it` is emitted
|
||||
(necessarily of the form `.yield _ _`) or `.done` if `it` terminates before emitting the `n`th
|
||||
value.
|
||||
-/
|
||||
nextAtIdx? (it : IterM (α := α) m β) (n : Nat) :
|
||||
m (PlausibleIterStep (it.IsPlausibleNthOutputStep n))
|
||||
|
||||
@@ -105,4 +113,4 @@ def IterM.atIdx? [Iterator α m β] [IteratorAccess α m] [Monad m] (it : IterM
|
||||
| .skip _ => return none
|
||||
| .done => return none
|
||||
|
||||
end Std.Iterators
|
||||
end Std
|
||||
|
||||
@@ -11,6 +11,8 @@ public import Init.Data.Iterators.Consumers.Monadic.Total
|
||||
public import Init.Data.Iterators.Internal.LawfulMonadLiftFunction
|
||||
public import Init.WFExtrinsicFix
|
||||
|
||||
set_option linter.missingDocs true
|
||||
|
||||
@[expose] public section
|
||||
|
||||
/-!
|
||||
@@ -22,113 +24,23 @@ Concretely, the following operations are provided:
|
||||
* `IterM.toList`, collecting the values in a list
|
||||
* `IterM.toListRev`, collecting the values in a list in reverse order but more efficiently
|
||||
* `IterM.toArray`, collecting the values in an array
|
||||
|
||||
Some producers and combinators provide specialized implementations. These are captured by the
|
||||
`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
|
||||
|
||||
section Typeclasses
|
||||
|
||||
/--
|
||||
`IteratorCollect α m` provides efficient implementations of collectors for `α`-based
|
||||
iterators. Right now, it is limited to a potentially optimized `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.
|
||||
|
||||
Note: For this to be compositional enough to be useful, `toArrayMapped` would need to accept a
|
||||
termination proof for the specific mapping function used instead of the blanket `Finite α m`
|
||||
instance. Otherwise, most combinators like `map` cannot implement their own instance relying on
|
||||
the instance of their base iterators. However, fixing this is currently low priority.
|
||||
-/
|
||||
class IteratorCollect (α : 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 |>.toArray` instead.
|
||||
-/
|
||||
toArrayMapped :
|
||||
(lift : ⦃δ : Type w⦄ → m δ → n δ) → {γ : Type w} → (β → n γ) → IterM (α := α) m β → n (Array γ)
|
||||
|
||||
end Typeclasses
|
||||
namespace Std
|
||||
open Std.Internal Std.Iterators
|
||||
|
||||
section ToArray
|
||||
|
||||
def IterM.DefaultConsumers.toArrayMapped.RecursionRel {α β : Type w} {m : Type w → Type w'}
|
||||
/--
|
||||
If this relation is well-founded, then `IterM.toArray`, `IterM.toList` and `IterM.toListRev` are
|
||||
guaranteed to finish after finitely many steps. If all of the iterator's steps terminate
|
||||
individually, `IterM.toArray` is guaranteed to terminate.
|
||||
-/
|
||||
def IterM.toArray.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) ∨
|
||||
(∃ out, x.1.IsPlausibleStep (.yield x'.1 out) ∧ ∃ a, x'.2 = x.2.push a) ∨
|
||||
(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, no_expose]
|
||||
def IterM.DefaultConsumers.toArrayMapped {α β : 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 γ) :=
|
||||
letI : MonadLift m n := ⟨lift (α := _)⟩
|
||||
go it #[]
|
||||
where
|
||||
@[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 `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]
|
||||
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`
|
||||
*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'')
|
||||
{β : Type w} [Monad m] [Monad n] [Iterator α m β] [i : IteratorCollect α m n] where
|
||||
lawful_toArrayMapped : ∀ lift [LawfulMonadLiftFunction lift] [Finite α m],
|
||||
i.toArrayMapped lift (α := α) (γ := γ)
|
||||
= IteratorCollect.defaultImplementation.toArrayMapped lift
|
||||
|
||||
theorem LawfulIteratorCollect.toArrayMapped_eq {α β γ : Type w} {m : Type w → Type w'}
|
||||
{n : Type w → Type w''} [Monad m] [Monad n] [Iterator α m β] [Finite α m] [IteratorCollect α m n]
|
||||
[hl : LawfulIteratorCollect α m n] {lift : ⦃δ : Type w⦄ → m δ → n δ}
|
||||
[LawfulMonadLiftFunction lift]
|
||||
{f : β → n γ} {it : IterM (α := α) m β} :
|
||||
IteratorCollect.toArrayMapped lift f it (m := m) =
|
||||
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] :
|
||||
haveI : IteratorCollect α m n := .defaultImplementation
|
||||
LawfulIteratorCollect α m n :=
|
||||
letI : IteratorCollect α m n := .defaultImplementation
|
||||
⟨fun _ => rfl⟩
|
||||
|
||||
/--
|
||||
Traverses the given iterator and stores the emitted values in an array.
|
||||
|
||||
@@ -137,8 +49,18 @@ If the iterator is not finite, this function might run forever. The variant
|
||||
-/
|
||||
@[always_inline, inline]
|
||||
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
|
||||
(it : IterM (α := α) m β) : m (Array β) :=
|
||||
go it #[]
|
||||
where
|
||||
@[always_inline]
|
||||
go it (acc : Array β) : m (Array β) :=
|
||||
WellFounded.extrinsicFix₂ (C₂ := fun _ _ => m (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 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
|
||||
|
||||
/--
|
||||
Traverses the given iterator and stores the emitted values in an array.
|
||||
@@ -147,7 +69,7 @@ This function is deprecated. Instead of `it.allowNontermination.toArray`, use `i
|
||||
-/
|
||||
@[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 β) :=
|
||||
[Iterator α m β] (it : IterM.Partial (α := α) m β) : m (Array β) :=
|
||||
it.it.toArray
|
||||
|
||||
/--
|
||||
@@ -158,7 +80,7 @@ finite. If such a proof is not available, consider using `IterM.toArray`.
|
||||
-/
|
||||
@[always_inline, inline]
|
||||
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] :
|
||||
[Iterator α m β] [Finite α m] (it : IterM.Total (α := α) m β) :
|
||||
m (Array β) :=
|
||||
it.it.toArray
|
||||
|
||||
@@ -218,7 +140,7 @@ If the iterator is not finite, this function might run forever. The variant
|
||||
-/
|
||||
@[always_inline, inline]
|
||||
def IterM.toList {α : Type w} {m : Type w → Type w'} [Monad m] {β : Type w}
|
||||
[Iterator α m β] [IteratorCollect α m m] (it : IterM (α := α) m β) : m (List β) :=
|
||||
[Iterator α m β] (it : IterM (α := α) m β) : m (List β) :=
|
||||
Array.toList <$> IterM.toArray it
|
||||
|
||||
/--
|
||||
@@ -229,7 +151,7 @@ This function is deprecated. Instead of `it.allowNontermination.toList`, use `it
|
||||
-/
|
||||
@[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] :
|
||||
[Iterator α m β] (it : IterM.Partial (α := α) m β) :
|
||||
m (List β) :=
|
||||
Array.toList <$> it.it.toArray
|
||||
|
||||
@@ -242,8 +164,8 @@ finite. If such a proof is not available, consider using `IterM.toList`.
|
||||
-/
|
||||
@[always_inline, inline]
|
||||
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] :
|
||||
[Iterator α m β] [Finite α m] (it : IterM.Total (α := α) m β) :
|
||||
m (List β) :=
|
||||
it.it.toList
|
||||
|
||||
end Std.Iterators
|
||||
end Std
|
||||
|
||||
@@ -11,6 +11,8 @@ public import Init.Data.Iterators.Internal.LawfulMonadLiftFunction
|
||||
public import Init.WFExtrinsicFix
|
||||
public import Init.Data.Iterators.Consumers.Monadic.Total
|
||||
|
||||
set_option linter.missingDocs true
|
||||
|
||||
public section
|
||||
|
||||
/-!
|
||||
@@ -31,9 +33,9 @@ types of iterators. A default implementation is provided. The typeclass `LawfulI
|
||||
asserts that an `IteratorLoop` instance equals the default implementation.
|
||||
-/
|
||||
|
||||
namespace Std.Iterators
|
||||
namespace Std
|
||||
|
||||
open Std.Internal
|
||||
open Std.Internal Std.Iterators
|
||||
|
||||
section Typeclasses
|
||||
|
||||
@@ -70,6 +72,9 @@ provided by the standard library.
|
||||
@[ext]
|
||||
class IteratorLoop (α : Type w) (m : Type w → Type w') {β : Type w} [Iterator α m β]
|
||||
(n : Type x → Type x') where
|
||||
/--
|
||||
Iteration over the iterator `it` in the manner expected by `for` loops.
|
||||
-/
|
||||
forIn : ∀ (_liftBind : (γ : Type w) → (δ : Type x) → (γ → n δ) → m γ → n δ) (γ : Type x),
|
||||
(plausible_forInStep : β → γ → ForInStep γ → Prop) →
|
||||
(it : IterM (α := α) m β) → γ →
|
||||
@@ -82,7 +87,9 @@ end Typeclasses
|
||||
structure IteratorLoop.WithWF (α : Type w) (m : Type w → Type w') {β : Type w} [Iterator α m β]
|
||||
{γ : Type x} (PlausibleForInStep : β → γ → ForInStep γ → Prop)
|
||||
(hwf : IteratorLoop.WellFounded α m PlausibleForInStep) where
|
||||
/-- Internal implementation detail of the iterator library. -/
|
||||
it : IterM (α := α) m β
|
||||
/-- Internal implementation detail of the iterator library. -/
|
||||
acc : γ
|
||||
|
||||
instance IteratorLoop.WithWF.instWellFoundedRelation
|
||||
@@ -163,14 +170,15 @@ Asserts that a given `IteratorLoop` instance is equal to `IteratorLoop.defaultIm
|
||||
-/
|
||||
class LawfulIteratorLoop (α : Type w) (m : Type w → Type w') (n : Type x → Type x')
|
||||
[Monad m] [Monad n] [Iterator α m β] [i : IteratorLoop α m n] where
|
||||
/-- The implementation of `IteratorLoop.forIn` in `i` is equal to the default implementation. -/
|
||||
lawful lift [LawfulMonadLiftBindFunction lift] γ it init
|
||||
(Pl : β → γ → ForInStep γ → Prop) (wf : IteratorLoop.WellFounded α m Pl)
|
||||
(f : (b : β) → it.IsPlausibleIndirectOutput b → (c : γ) → n (Subtype (Pl b c))) :
|
||||
i.forIn lift γ Pl it init f =
|
||||
IteratorLoop.defaultImplementation.forIn lift γ Pl it init f
|
||||
|
||||
instance (α : Type w) (m : Type w → Type w') (n : Type x → Type x')
|
||||
[Monad m] [Monad n] [Iterator α m β] [Finite α m] :
|
||||
instance instLawfulIteratorLoopDefaultImplementation (α : Type w) (m : Type w → Type w')
|
||||
(n : Type x → Type x') [Monad m] [Monad n] [Iterator α m β] [Finite α m] :
|
||||
letI : IteratorLoop α m n := .defaultImplementation
|
||||
LawfulIteratorLoop α m n := by
|
||||
letI : IteratorLoop α m n := .defaultImplementation
|
||||
@@ -212,13 +220,14 @@ def IterM.instForIn' {m : Type w → Type w'} {n : Type w → Type w''}
|
||||
ForIn' n (IterM (α := α) m β) β ⟨fun it out => it.IsPlausibleIndirectOutput out⟩ :=
|
||||
IteratorLoop.finiteForIn' (fun _ _ f x => monadLift x >>= f)
|
||||
|
||||
instance {m : Type w → Type w'} {n : Type w → Type w''}
|
||||
instance IterM.instForInOfIteratorLoop {m : Type w → Type w'} {n : Type w → Type w''}
|
||||
{α : Type w} {β : Type w} [Iterator α m β] [IteratorLoop α m n]
|
||||
[MonadLiftT m n] [Monad n] :
|
||||
ForIn n (IterM (α := α) m β) β :=
|
||||
haveI : ForIn' n (IterM (α := α) m β) β _ := IterM.instForIn'
|
||||
instForInOfForIn'
|
||||
|
||||
/-- Internal implementation detail of the iterator library. -/
|
||||
@[always_inline, inline]
|
||||
def IterM.Partial.instForIn' {m : Type w → Type w'} {n : Type w → Type w''}
|
||||
{α : Type w} {β : Type w} [Iterator α m β] [IteratorLoop α m n] [MonadLiftT m n] [Monad n] :
|
||||
@@ -226,6 +235,7 @@ def IterM.Partial.instForIn' {m : Type w → Type w'} {n : Type w → Type w''}
|
||||
forIn' it init f :=
|
||||
haveI := @IterM.instForIn'; forIn' it.it init f
|
||||
|
||||
/-- Internal implementation detail of the iterator library. -/
|
||||
@[always_inline, inline]
|
||||
def IterM.Total.instForIn' {m : Type w → Type w'} {n : Type w → Type w''}
|
||||
{α : Type w} {β : Type w} [Iterator α m β] [IteratorLoop α m n] [MonadLiftT m n] [Monad n]
|
||||
@@ -233,7 +243,7 @@ def IterM.Total.instForIn' {m : Type w → Type w'} {n : Type w → Type w''}
|
||||
ForIn' n (IterM.Total (α := α) m β) β ⟨fun it out => it.it.IsPlausibleIndirectOutput out⟩ where
|
||||
forIn' it init f := IterM.instForIn'.forIn' it.it init f
|
||||
|
||||
instance {m : Type w → Type w'} {n : Type w → Type w''}
|
||||
instance IterM.Partial.instForInOfIteratorLoop {m : Type w → Type w'} {n : Type w → Type w''}
|
||||
{α : Type w} {β : Type w} [Iterator α m β] [IteratorLoop α m n] [MonadLiftT m n] [Monad n] :
|
||||
ForIn n (IterM.Partial (α := α) m β) β :=
|
||||
haveI : ForIn' n (IterM.Partial (α := α) m β) β _ := IterM.Partial.instForIn'
|
||||
@@ -246,12 +256,13 @@ instance {m : Type w → Type w'} {n : Type w → Type w''}
|
||||
haveI : ForIn' n (IterM.Total (α := α) m β) β _ := IterM.Total.instForIn'
|
||||
instForInOfForIn'
|
||||
|
||||
instance {m : Type w → Type w'} {n : Type w → Type w''} {α : Type w} {β : Type w} [Iterator α m β]
|
||||
[IteratorLoop α m n] [Monad n] [MonadLiftT m n] : ForM n (IterM (α := α) m β) β where
|
||||
instance IterM.instForMOfIteratorLoop {m : Type w → Type w'} {n : Type w → Type w''}
|
||||
{α : Type w} {β : Type w} [Iterator α m β] [IteratorLoop α m n] [Monad n] [MonadLiftT m n] :
|
||||
ForM n (IterM (α := α) m β) β where
|
||||
forM it f := forIn it PUnit.unit (fun out _ => do f out; return .yield .unit)
|
||||
|
||||
instance {m : Type w → Type w'} {n : Type w → Type w''} {α : Type w} {β : Type w} [Monad n]
|
||||
[Iterator α m β] [IteratorLoop α m n] [MonadLiftT m n] :
|
||||
instance IterM.Partial.instForMOfItreratorLoop {m : Type w → Type w'} {n : Type w → Type w''}
|
||||
{α : Type w} {β : Type w} [Monad n] [Iterator α m β] [IteratorLoop α m n] [MonadLiftT m n] :
|
||||
ForM n (IterM.Partial (α := α) m β) β where
|
||||
forM it f := forIn it PUnit.unit (fun out _ => do f out; return .yield .unit)
|
||||
|
||||
@@ -943,4 +954,4 @@ def IterM.Partial.size {α : Type w} {m : Type w → Type w'} {β : Type w} [Ite
|
||||
|
||||
end Count
|
||||
|
||||
end Std.Iterators
|
||||
end Std
|
||||
|
||||
@@ -8,14 +8,19 @@ module
|
||||
prelude
|
||||
public import Init.Data.Iterators.Basic
|
||||
|
||||
set_option linter.missingDocs true
|
||||
|
||||
public section
|
||||
|
||||
namespace Std.Iterators
|
||||
namespace Std
|
||||
|
||||
/--
|
||||
A wrapper around an iterator that provides partial consumers. See `IterM.allowNontermination`.
|
||||
-/
|
||||
structure IterM.Partial {α : Type w} (m : Type w → Type w') (β : Type w) where
|
||||
/--
|
||||
The wrapped iterator, which was wrapped by `IterM.allowNontermination`.
|
||||
-/
|
||||
it : IterM (α := α) m β
|
||||
|
||||
/--
|
||||
@@ -29,4 +34,4 @@ def IterM.allowNontermination {α : Type w} {m : Type w → Type w'} {β : Type
|
||||
(it : IterM (α := α) m β) : IterM.Partial (α := α) m β :=
|
||||
⟨it⟩
|
||||
|
||||
end Std.Iterators
|
||||
end Std
|
||||
|
||||
@@ -9,12 +9,19 @@ prelude
|
||||
public import Init.Data.Iterators.Basic
|
||||
|
||||
set_option doc.verso true
|
||||
set_option linter.missingDocs true
|
||||
|
||||
public section
|
||||
|
||||
namespace Std.Iterators
|
||||
namespace Std
|
||||
|
||||
/--
|
||||
A wrapper around an iterator that provides total consumers. See `IterM.ensureTermination`.
|
||||
-/
|
||||
structure IterM.Total {α : Type w} (m : Type w → Type w') (β : Type w) where
|
||||
/--
|
||||
The wrapped iterator, which was wrapped by `IterM.ensureTermination`.
|
||||
-/
|
||||
it : IterM (α := α) m β
|
||||
|
||||
/--
|
||||
@@ -33,4 +40,4 @@ A wrapper around an iterator that provides strictly terminating consumers. See
|
||||
-/
|
||||
add_decl_doc IterM.Total
|
||||
|
||||
end Std.Iterators
|
||||
end Std
|
||||
|
||||
@@ -8,14 +8,19 @@ module
|
||||
prelude
|
||||
public import Init.Data.Iterators.Basic
|
||||
|
||||
set_option linter.missingDocs true
|
||||
|
||||
public section
|
||||
|
||||
namespace Std.Iterators
|
||||
namespace Std
|
||||
|
||||
/--
|
||||
A wrapper around an iterator that provides partial consumers. See `Iter.allowNontermination`.
|
||||
-/
|
||||
structure Iter.Partial {α : Type w} (β : Type w) where
|
||||
/--
|
||||
The wrapped iterator, which was wrapped by `Iter.allowNontermination`.
|
||||
-/
|
||||
it : Iter (α := α) β
|
||||
|
||||
/--
|
||||
@@ -29,4 +34,4 @@ def Iter.allowNontermination {α : Type w} {β : Type w}
|
||||
(it : Iter (α := α) β) : Iter.Partial (α := α) β :=
|
||||
⟨it⟩
|
||||
|
||||
end Std.Iterators
|
||||
end Std
|
||||
|
||||
@@ -9,9 +9,12 @@ prelude
|
||||
public import Init.Data.Stream
|
||||
public import Init.Data.Iterators.Consumers.Access
|
||||
|
||||
set_option linter.missingDocs true
|
||||
|
||||
public section
|
||||
|
||||
namespace Std.Iterators
|
||||
namespace Std
|
||||
open Std.Iterators
|
||||
|
||||
instance {α β} [Iterator α Id β] [Productive α Id] [IteratorAccess α Id] :
|
||||
Stream (Iter (α := α) β) β where
|
||||
@@ -24,4 +27,4 @@ instance {α β} [Iterator α Id β] [Productive α Id] [IteratorAccess α Id] :
|
||||
revert h
|
||||
exact IterM.not_isPlausibleNthOutputStep_yield
|
||||
|
||||
end Std.Iterators
|
||||
end Std
|
||||
|
||||
@@ -9,12 +9,19 @@ prelude
|
||||
public import Init.Data.Iterators.Basic
|
||||
|
||||
set_option doc.verso true
|
||||
set_option linter.missingDocs true
|
||||
|
||||
public section
|
||||
|
||||
namespace Std.Iterators
|
||||
namespace Std
|
||||
|
||||
/--
|
||||
A wrapper around an iterator that provides total consumers. See `Iter.ensureTermination`.
|
||||
-/
|
||||
structure Iter.Total {α : Type w} (β : Type w) where
|
||||
/--
|
||||
The wrapped iterator, which was wrapped by `Iter.ensureTermination`.
|
||||
-/
|
||||
it : Iter (α := α) β
|
||||
|
||||
/--
|
||||
@@ -33,4 +40,4 @@ A wrapper around an iterator that provides strictly terminating consumers. See
|
||||
-/
|
||||
add_decl_doc Iter.Total
|
||||
|
||||
end Std.Iterators
|
||||
end Std
|
||||
|
||||
@@ -7,4 +7,3 @@ module
|
||||
|
||||
prelude
|
||||
public import Init.Data.Iterators.Internal.LawfulMonadLiftFunction
|
||||
public import Init.Data.Iterators.Internal.Termination
|
||||
|
||||
@@ -1,63 +0,0 @@
|
||||
/-
|
||||
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
|
||||
|
||||
public section
|
||||
|
||||
/-!
|
||||
This is an internal module used by iterator implementations.
|
||||
-/
|
||||
|
||||
namespace Std.Iterators
|
||||
|
||||
/--
|
||||
Internal implementation detail of the iterator library.
|
||||
The purpose of this class is that it implies a `Finite` instance but
|
||||
it is more convenient to implement.
|
||||
-/
|
||||
structure FinitenessRelation (α : Type w) (m : Type w → Type w') {β : Type w}
|
||||
[Iterator α m β] where
|
||||
rel : (IterM (α := α) m β) → (IterM (α := α) m β) → Prop
|
||||
wf : WellFounded rel
|
||||
subrelation : ∀ {it it'}, it'.IsPlausibleSuccessorOf it → rel it' it
|
||||
|
||||
theorem Finite.of_finitenessRelation
|
||||
{α : Type w} {m : Type w → Type w'} {β : Type w}
|
||||
[Iterator α m β] (r : FinitenessRelation α m) : Finite α m where
|
||||
wf := by
|
||||
refine Subrelation.wf (r := r.rel) ?_ ?_
|
||||
· intro x y h
|
||||
apply FinitenessRelation.subrelation
|
||||
exact h
|
||||
· apply InvImage.wf
|
||||
exact r.wf
|
||||
|
||||
/--
|
||||
Internal implementation detail of the iterator library.
|
||||
The purpose of this class is that it implies a `Productive` instance but
|
||||
it is more convenient to implement.
|
||||
-/
|
||||
structure ProductivenessRelation (α : Type w) (m : Type w → Type w') {β : Type w}
|
||||
[Iterator α m β] where
|
||||
rel : (IterM (α := α) m β) → (IterM (α := α) m β) → Prop
|
||||
wf : WellFounded rel
|
||||
subrelation : ∀ {it it'}, it'.IsPlausibleSkipSuccessorOf it → rel it' it
|
||||
|
||||
theorem Productive.of_productivenessRelation
|
||||
{α : Type w} {m : Type w → Type w'} {β : Type w}
|
||||
[Iterator α m β] (r : ProductivenessRelation α m) : Productive α m where
|
||||
wf := by
|
||||
refine Subrelation.wf (r := r.rel) ?_ ?_
|
||||
· intro x y h
|
||||
apply ProductivenessRelation.subrelation
|
||||
exact h
|
||||
· apply InvImage.wf
|
||||
exact r.wf
|
||||
|
||||
end Std.Iterators
|
||||
@@ -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 =
|
||||
@@ -26,8 +27,7 @@ theorem Iter.unattach_eq_toIter_unattach_toIterM [Iterator α Id β] {it : Iter
|
||||
|
||||
theorem Iter.unattach_toList_attachWith [Iterator α Id β]
|
||||
{it : Iter (α := α) β} {hP}
|
||||
[Finite α Id] [IteratorCollect α Id Id]
|
||||
[LawfulIteratorCollect α Id Id] :
|
||||
[Finite α Id] :
|
||||
(it.attachWith P hP).toList.unattach = it.toList := by
|
||||
simp [Iter.unattach_eq_toIter_unattach_toIterM,
|
||||
← Id.run_map (f := List.unattach), IterM.map_unattach_toList_attachWith,
|
||||
@@ -36,8 +36,7 @@ theorem Iter.unattach_toList_attachWith [Iterator α Id β]
|
||||
@[simp]
|
||||
theorem Iter.toList_attachWith [Iterator α Id β]
|
||||
{it : Iter (α := α) β} {hP}
|
||||
[Finite α Id] [IteratorCollect α Id Id]
|
||||
[LawfulIteratorCollect α Id Id] :
|
||||
[Finite α Id] :
|
||||
(it.attachWith P hP).toList = it.toList.attachWith P
|
||||
(fun out h => hP out (isPlausibleIndirectOutput_of_mem_toList h)) := by
|
||||
apply List.ext_getElem
|
||||
@@ -49,16 +48,14 @@ theorem Iter.toList_attachWith [Iterator α Id β]
|
||||
|
||||
theorem Iter.unattach_toListRev_attachWith [Iterator α Id β]
|
||||
{it : Iter (α := α) β} {hP}
|
||||
[Finite α Id] [IteratorCollect α Id Id]
|
||||
[LawfulIteratorCollect α Id Id] :
|
||||
[Finite α Id] :
|
||||
(it.attachWith P hP).toListRev.unattach = it.toListRev := by
|
||||
simp [toListRev_eq]
|
||||
|
||||
@[simp]
|
||||
theorem Iter.toListRev_attachWith [Iterator α Id β]
|
||||
{it : Iter (α := α) β} {hP}
|
||||
[Finite α Id] [IteratorCollect α Id Id]
|
||||
[LawfulIteratorCollect α Id Id] :
|
||||
[Finite α Id] :
|
||||
(it.attachWith P hP).toListRev = it.toListRev.attachWith P
|
||||
(fun out h => hP out (isPlausibleIndirectOutput_of_mem_toListRev h)) := by
|
||||
simp [toListRev_eq]
|
||||
@@ -66,16 +63,14 @@ theorem Iter.toListRev_attachWith [Iterator α Id β]
|
||||
@[simp]
|
||||
theorem Iter.unattach_toArray_attachWith [Iterator α Id β]
|
||||
{it : Iter (α := α) β} {hP}
|
||||
[Finite α Id] [IteratorCollect α Id Id]
|
||||
[LawfulIteratorCollect α Id Id] :
|
||||
[Finite α Id] :
|
||||
(it.attachWith P hP).toListRev.unattach = it.toListRev := by
|
||||
simp [toListRev_eq]
|
||||
|
||||
@[simp]
|
||||
theorem Iter.toArray_attachWith [Iterator α Id β]
|
||||
{it : Iter (α := α) β} {hP}
|
||||
[Finite α Id] [IteratorCollect α Id Id]
|
||||
[LawfulIteratorCollect α Id Id] :
|
||||
[Finite α Id] :
|
||||
(it.attachWith P hP).toArray = it.toArray.attachWith P
|
||||
(fun out h => hP out (isPlausibleIndirectOutput_of_mem_toArray h)) := by
|
||||
suffices (it.attachWith P hP).toArray.toList = (it.toArray.attachWith P
|
||||
@@ -89,8 +84,7 @@ theorem Iter.count_attachWith [Iterator α Id β]
|
||||
[Finite α Id] [IteratorLoop α Id Id]
|
||||
[LawfulIteratorLoop α Id Id] :
|
||||
(it.attachWith P hP).count = it.count := by
|
||||
letI : IteratorCollect α Id Id := .defaultImplementation
|
||||
rw [← Iter.length_toList_eq_count, toList_attachWith]
|
||||
simp
|
||||
|
||||
end Std.Iterators
|
||||
end Std
|
||||
|
||||
@@ -9,10 +9,12 @@ prelude
|
||||
public import Init.Data.Iterators.Lemmas.Consumers
|
||||
public import Init.Data.Iterators.Lemmas.Combinators.Monadic.FilterMap
|
||||
public import Init.Data.Iterators.Combinators.FilterMap
|
||||
import Init.Control.Lawful.MonadAttach.Lemmas
|
||||
|
||||
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''}
|
||||
@@ -31,15 +33,15 @@ theorem Iter.mapWithPostcondition_eq_toIter_mapWithPostcondition_toIterM [Monad
|
||||
it.mapWithPostcondition f = (letI : MonadLift Id m := ⟨pure⟩; it.toIterM.mapWithPostcondition f) :=
|
||||
rfl
|
||||
|
||||
theorem Iter.filterMapM_eq_toIter_filterMapM_toIterM [Monad m] {f : β → m (Option γ)} :
|
||||
theorem Iter.filterMapM_eq_toIter_filterMapM_toIterM [Monad m] [MonadAttach m] {f : β → m (Option γ)} :
|
||||
it.filterMapM f = (letI : MonadLift Id m := ⟨pure⟩; it.toIterM.filterMapM f) :=
|
||||
rfl
|
||||
|
||||
theorem Iter.filterM_eq_toIter_filterM_toIterM [Monad m] {f : β → m (ULift Bool)} :
|
||||
theorem Iter.filterM_eq_toIter_filterM_toIterM [Monad m] [MonadAttach m] {f : β → m (ULift Bool)} :
|
||||
it.filterM f = (letI : MonadLift Id m := ⟨pure⟩; it.toIterM.filterM f) :=
|
||||
rfl
|
||||
|
||||
theorem Iter.mapM_eq_toIter_mapM_toIterM [Monad m] {f : β → m γ} :
|
||||
theorem Iter.mapM_eq_toIter_mapM_toIterM [Monad m] [MonadAttach m] {f : β → m γ} :
|
||||
it.mapM f = (letI : MonadLift Id m := ⟨pure⟩; it.toIterM.mapM f) :=
|
||||
rfl
|
||||
|
||||
@@ -107,7 +109,7 @@ theorem Iter.step_filterWithPostcondition {f : β → PostconditionT n (ULift Bo
|
||||
| .done h => rfl
|
||||
|
||||
theorem Iter.step_mapWithPostcondition {f : β → PostconditionT n γ}
|
||||
[Monad n] [LawfulMonad n] [MonadLiftT m n] :
|
||||
[Monad n] [LawfulMonad n] :
|
||||
(it.mapWithPostcondition f).step = (do
|
||||
match it.step with
|
||||
| .yield it' out h => do
|
||||
@@ -128,15 +130,15 @@ theorem Iter.step_mapWithPostcondition {f : β → PostconditionT n γ}
|
||||
| .done h => rfl
|
||||
|
||||
theorem Iter.step_filterMapM {β' : Type w} {f : β → n (Option β')}
|
||||
[Monad n] [LawfulMonad n] [MonadLiftT m n] :
|
||||
[Monad n] [MonadAttach n] [LawfulMonad n] [MonadLiftT m n] :
|
||||
(it.filterMapM f).step = (do
|
||||
match it.step with
|
||||
| .yield it' out h => do
|
||||
match ← f out with
|
||||
| none =>
|
||||
pure <| .deflate <| .skip (it'.filterMapM f) (.yieldNone (out := out) h .intro)
|
||||
| some out' =>
|
||||
pure <| .deflate <| .yield (it'.filterMapM f) out' (.yieldSome (out := out) h .intro)
|
||||
match ← MonadAttach.attach (f out) with
|
||||
| ⟨none, hf⟩ =>
|
||||
pure <| .deflate <| .skip (it'.filterMapM f) (.yieldNone (out := out) h hf)
|
||||
| ⟨some out', hf⟩ =>
|
||||
pure <| .deflate <| .yield (it'.filterMapM f) out' (.yieldSome (out := out) h hf)
|
||||
| .skip it' h =>
|
||||
pure <| .deflate <| .skip (it'.filterMapM f) (.skip h)
|
||||
| .done h =>
|
||||
@@ -153,15 +155,15 @@ theorem Iter.step_filterMapM {β' : Type w} {f : β → n (Option β')}
|
||||
| .done h => rfl
|
||||
|
||||
theorem Iter.step_filterM {f : β → n (ULift Bool)}
|
||||
[Monad n] [LawfulMonad n] [MonadLiftT m n] :
|
||||
[Monad n] [MonadAttach n] [LawfulMonad n] [MonadLiftT m n] :
|
||||
(it.filterM f).step = (do
|
||||
match it.step with
|
||||
| .yield it' out h => do
|
||||
match ← f out with
|
||||
| .up false =>
|
||||
pure <| .deflate <| .skip (it'.filterM f) (.yieldNone (out := out) h ⟨⟨.up false, .intro⟩, rfl⟩)
|
||||
| .up true =>
|
||||
pure <| .deflate <| .yield (it'.filterM f) out (.yieldSome (out := out) h ⟨⟨.up true, .intro⟩, rfl⟩)
|
||||
match ← MonadAttach.attach (f out) with
|
||||
| ⟨.up false, hf⟩ =>
|
||||
pure <| .deflate <| .skip (it'.filterM f) (.yieldNone (out := out) h ⟨⟨.up false, hf⟩, rfl⟩)
|
||||
| ⟨.up true, hf⟩ =>
|
||||
pure <| .deflate <| .yield (it'.filterM f) out (.yieldSome (out := out) h ⟨⟨.up true, hf⟩, rfl⟩)
|
||||
| .skip it' h =>
|
||||
pure <| .deflate <| .skip (it'.filterM f) (.skip h)
|
||||
| .done h =>
|
||||
@@ -171,20 +173,19 @@ theorem Iter.step_filterM {f : β → n (ULift Bool)}
|
||||
generalize it.toIterM.step = step
|
||||
match step.inflate with
|
||||
| .yield it' out h =>
|
||||
simp [PostconditionT.lift]
|
||||
apply bind_congr
|
||||
intro step
|
||||
simp only
|
||||
apply bind_congr; intro step
|
||||
rcases step with _ | _ <;> rfl
|
||||
| .skip it' h => rfl
|
||||
| .done h => rfl
|
||||
|
||||
theorem Iter.step_mapM {f : β → n γ}
|
||||
[Monad n] [LawfulMonad n] :
|
||||
[Monad n] [MonadAttach n] [LawfulMonad n] :
|
||||
(it.mapM f).step = (do
|
||||
match it.step with
|
||||
| .yield it' out h => do
|
||||
let out' ← f out
|
||||
pure <| .deflate <| .yield (it'.mapM f) out' (.yieldSome h ⟨⟨out', True.intro⟩, rfl⟩)
|
||||
let out' ← MonadAttach.attach (f out)
|
||||
pure <| .deflate <| .yield (it'.mapM f) out'.val (.yieldSome h ⟨⟨out', out'.property⟩, rfl⟩)
|
||||
| .skip it' h =>
|
||||
pure <| .deflate <| .skip (it'.mapM f) (.skip h)
|
||||
| .done h =>
|
||||
@@ -290,174 +291,417 @@ def Iter.val_step_filter {f : β → Bool} :
|
||||
· simp
|
||||
|
||||
@[simp]
|
||||
theorem Iter.toList_filterMap
|
||||
[IteratorCollect α Id Id] [LawfulIteratorCollect α Id Id] [Finite α Id]
|
||||
theorem Iter.toList_filterMap [Finite α Id]
|
||||
{f : β → Option γ} :
|
||||
(it.filterMap f).toList = it.toList.filterMap f := by
|
||||
simp [filterMap_eq_toIter_filterMap_toIterM, toList_eq_toList_toIterM, IterM.toList_filterMap]
|
||||
|
||||
@[simp]
|
||||
theorem Iter.toList_map
|
||||
[IteratorCollect α Id Id] [LawfulIteratorCollect α Id Id] [Finite α Id]
|
||||
{f : β → γ} :
|
||||
theorem Iter.toList_mapWithPostcondition [Monad m] [LawfulMonad m] [Finite α Id]
|
||||
{f : β → PostconditionT m γ} :
|
||||
(it.mapWithPostcondition f).toList = it.toList.mapM (fun x => (f x).run) := by
|
||||
simp [Iter.mapWithPostcondition, IterM.toList_mapWithPostcondition, Iter.toList_eq_toList_toIterM]
|
||||
|
||||
@[simp]
|
||||
theorem Iter.toList_mapM [Monad m] [MonadAttach m] [LawfulMonad m] [WeaklyLawfulMonadAttach m]
|
||||
[Finite α Id] {f : β → m γ} :
|
||||
(it.mapM f).toList = it.toList.mapM f := by
|
||||
simp [Iter.mapM_eq_toIter_mapM_toIterM, IterM.toList_mapM, Iter.toList_eq_toList_toIterM]
|
||||
|
||||
@[simp]
|
||||
theorem Iter.toList_map [Finite α Id] {f : β → γ} :
|
||||
(it.map f).toList = it.toList.map f := by
|
||||
simp [map_eq_toIter_map_toIterM, IterM.toList_map, Iter.toList_eq_toList_toIterM]
|
||||
|
||||
@[simp]
|
||||
theorem Iter.toList_filter
|
||||
[IteratorCollect α Id Id] [LawfulIteratorCollect α Id Id] [Finite α Id]
|
||||
{f : β → Bool} :
|
||||
theorem Iter.toList_filter [Finite α Id] {f : β → Bool} :
|
||||
(it.filter f).toList = it.toList.filter f := by
|
||||
simp [filter_eq_toIter_filter_toIterM, IterM.toList_filter, Iter.toList_eq_toList_toIterM]
|
||||
|
||||
@[simp]
|
||||
theorem Iter.toListRev_filterMap
|
||||
[IteratorCollect α Id Id] [LawfulIteratorCollect α Id Id] [Finite α Id]
|
||||
theorem Iter.toList_filterMapWithPostcondition_filterMapWithPostcondition
|
||||
[Monad m] [LawfulMonad m] [Monad n] [LawfulMonad n] [MonadLiftT m n] [LawfulMonadLiftT m n]
|
||||
[Finite α Id]
|
||||
{f : β → PostconditionT m (Option γ)} {g : γ → PostconditionT n (Option δ)} :
|
||||
((it.filterMapWithPostcondition f).filterMapWithPostcondition g).toList =
|
||||
(it.filterMapWithPostcondition (m := n) (fun b => do
|
||||
match ← (haveI : MonadLift m n := ⟨monadLift⟩; f b) with
|
||||
| none => return none
|
||||
| some fb => g fb)).toList := by
|
||||
simp only [Iter.filterMapWithPostcondition]
|
||||
rw [IterM.toList_filterMapWithPostcondition_filterMapWithPostcondition,
|
||||
instMonadLiftTOfMonadLift_instMonadLiftTOfPure]
|
||||
rfl
|
||||
|
||||
@[simp]
|
||||
theorem Iter.toList_mapWithPostcondition_mapWithPostcondition
|
||||
[Monad m] [LawfulMonad m] [Monad n] [LawfulMonad n] [MonadLiftT m n] [LawfulMonadLiftT m n]
|
||||
[Finite α Id]
|
||||
{f : β → PostconditionT m γ} {g : γ → PostconditionT n δ} :
|
||||
((it.mapWithPostcondition f).mapWithPostcondition g).toList =
|
||||
(it.mapWithPostcondition (m := n) (haveI : MonadLift m n := ⟨monadLift⟩; fun b => f b >>= g)).toList := by
|
||||
simp only [Iter.mapWithPostcondition]
|
||||
rw [IterM.toList_mapWithPostcondition_mapWithPostcondition,
|
||||
instMonadLiftTOfMonadLift_instMonadLiftTOfPure]
|
||||
|
||||
@[simp]
|
||||
theorem Iter.toListRev_filterMap [Finite α Id]
|
||||
{f : β → Option γ} :
|
||||
(it.filterMap f).toListRev = it.toListRev.filterMap f := by
|
||||
simp [filterMap_eq_toIter_filterMap_toIterM, toListRev_eq_toListRev_toIterM, IterM.toListRev_filterMap]
|
||||
|
||||
@[simp]
|
||||
theorem Iter.toListRev_map
|
||||
[IteratorCollect α Id Id] [LawfulIteratorCollect α Id Id] [Finite α Id]
|
||||
theorem Iter.toListRev_map [Finite α Id]
|
||||
{f : β → γ} :
|
||||
(it.map f).toListRev = it.toListRev.map f := by
|
||||
simp [map_eq_toIter_map_toIterM, IterM.toListRev_map, Iter.toListRev_eq_toListRev_toIterM]
|
||||
|
||||
@[simp]
|
||||
theorem Iter.toListRev_filter
|
||||
[IteratorCollect α Id Id] [LawfulIteratorCollect α Id Id] [Finite α Id]
|
||||
theorem Iter.toListRev_filter [Finite α Id]
|
||||
{f : β → Bool} :
|
||||
(it.filter f).toListRev = it.toListRev.filter f := by
|
||||
simp [filter_eq_toIter_filter_toIterM, IterM.toListRev_filter, Iter.toListRev_eq_toListRev_toIterM]
|
||||
|
||||
@[simp]
|
||||
theorem Iter.toArray_filterMap
|
||||
[IteratorCollect α Id Id] [LawfulIteratorCollect α Id Id] [Finite α Id]
|
||||
theorem Iter.toArray_filterMap [Finite α Id]
|
||||
{f : β → Option γ} :
|
||||
(it.filterMap f).toArray = it.toArray.filterMap f := by
|
||||
simp [filterMap_eq_toIter_filterMap_toIterM, toArray_eq_toArray_toIterM, IterM.toArray_filterMap]
|
||||
|
||||
@[simp]
|
||||
theorem Iter.toArray_map
|
||||
[IteratorCollect α Id Id] [LawfulIteratorCollect α Id Id] [Finite α Id]
|
||||
{f : β → γ} :
|
||||
theorem Iter.toArray_mapWithPostcondition [Monad m] [LawfulMonad m] [Finite α Id]
|
||||
{f : β → PostconditionT m γ} :
|
||||
(it.mapWithPostcondition f).toArray = it.toArray.mapM (fun x => (f x).run) := by
|
||||
simp [Iter.mapWithPostcondition, IterM.toArray_mapWithPostcondition, Iter.toArray_eq_toArray_toIterM]
|
||||
|
||||
@[simp]
|
||||
theorem Iter.toArray_mapM [Monad m] [MonadAttach m] [LawfulMonad m] [WeaklyLawfulMonadAttach m]
|
||||
[Finite α Id] {f : β → m γ} :
|
||||
(it.mapM f).toArray = it.toArray.mapM f := by
|
||||
simp [Iter.mapM_eq_toIter_mapM_toIterM, IterM.toArray_mapM, Iter.toArray_eq_toArray_toIterM]
|
||||
|
||||
@[simp]
|
||||
theorem Iter.toArray_map [Finite α Id] {f : β → γ} :
|
||||
(it.map f).toArray = it.toArray.map f := by
|
||||
simp [map_eq_toIter_map_toIterM, IterM.toArray_map, Iter.toArray_eq_toArray_toIterM]
|
||||
|
||||
@[simp]
|
||||
theorem Iter.toArray_filter
|
||||
[IteratorCollect α Id Id] [LawfulIteratorCollect α Id Id] [Finite α Id]
|
||||
{f : β → Bool} :
|
||||
theorem Iter.toArray_filter[Finite α Id] {f : β → Bool} :
|
||||
(it.filter f).toArray = it.toArray.filter f := by
|
||||
simp [filter_eq_toIter_filter_toIterM, IterM.toArray_filter, Iter.toArray_eq_toArray_toIterM]
|
||||
|
||||
@[simp]
|
||||
theorem Iter.toArray_filterMapWithPostcondition_filterMapWithPostcondition
|
||||
[Monad m] [LawfulMonad m] [Monad n] [LawfulMonad n] [MonadLiftT m n] [LawfulMonadLiftT m n]
|
||||
[Finite α Id]
|
||||
{f : β → PostconditionT m (Option γ)} {g : γ → PostconditionT n (Option δ)} :
|
||||
((it.filterMapWithPostcondition f).filterMapWithPostcondition g).toArray =
|
||||
(it.filterMapWithPostcondition (m := n) (fun b => do
|
||||
match ← (haveI : MonadLift m n := ⟨monadLift⟩; f b) with
|
||||
| none => return none
|
||||
| some fb => g fb)).toArray := by
|
||||
simp only [Iter.filterMapWithPostcondition]
|
||||
rw [IterM.toArray_filterMapWithPostcondition_filterMapWithPostcondition,
|
||||
instMonadLiftTOfMonadLift_instMonadLiftTOfPure]
|
||||
rfl
|
||||
|
||||
@[simp]
|
||||
theorem Iter.toArray_mapWithPostcondition_mapWithPostcondition
|
||||
[Monad m] [LawfulMonad m] [Monad n] [LawfulMonad n] [MonadLiftT m n] [LawfulMonadLiftT m n]
|
||||
[Finite α Id]
|
||||
{f : β → PostconditionT m γ} {g : γ → PostconditionT n δ} :
|
||||
((it.mapWithPostcondition f).mapWithPostcondition g).toArray =
|
||||
(it.mapWithPostcondition (m := n) (haveI : MonadLift m n := ⟨monadLift⟩; fun b => f b >>= g)).toArray := by
|
||||
simp only [Iter.mapWithPostcondition]
|
||||
rw [IterM.toArray_mapWithPostcondition_mapWithPostcondition,
|
||||
instMonadLiftTOfMonadLift_instMonadLiftTOfPure]
|
||||
|
||||
section ForIn
|
||||
|
||||
theorem Iter.forIn_filterMapWithPostcondition
|
||||
[Monad n] [LawfulMonad n] [Monad o] [LawfulMonad o]
|
||||
[MonadLiftT n o] [LawfulMonadLiftT n o] [Finite α Id]
|
||||
[IteratorLoop α Id o] [LawfulIteratorLoop α Id o]
|
||||
{it : Iter (α := α) β} {f : β → PostconditionT n (Option β₂)} {init : γ}
|
||||
{g : β₂ → γ → o (ForInStep γ)} :
|
||||
forIn (it.filterMapWithPostcondition f) init g = forIn it init (fun out acc => do
|
||||
match ← (f out).run with
|
||||
| some c => g c acc
|
||||
| none => return .yield acc) := by
|
||||
simp [Iter.forIn_eq_forIn_toIterM, filterMapWithPostcondition, IterM.forIn_filterMapWithPostcondition,
|
||||
instMonadLiftTOfMonadLift_instMonadLiftTOfPure]; rfl
|
||||
|
||||
theorem Iter.forIn_filterMapM
|
||||
[Monad n] [LawfulMonad n] [Monad o] [LawfulMonad o]
|
||||
[MonadAttach n] [WeaklyLawfulMonadAttach n]
|
||||
[MonadLiftT n o] [LawfulMonadLiftT n o]
|
||||
[Finite α Id] [IteratorLoop α Id o] [LawfulIteratorLoop α Id o]
|
||||
{it : Iter (α := α) β} {f : β → n (Option β₂)} {init : γ} {g : β₂ → γ → o (ForInStep γ)} :
|
||||
forIn (it.filterMapM f) init g = forIn it init (fun out acc => do
|
||||
match ← f out with
|
||||
| some c => g c acc
|
||||
| none => return .yield acc) := by
|
||||
simp [filterMapM, forIn_eq_forIn_toIterM, IterM.forIn_filterMapM,
|
||||
instMonadLiftTOfMonadLift_instMonadLiftTOfPure]; rfl
|
||||
|
||||
theorem Iter.forIn_filterMap
|
||||
[Monad n] [LawfulMonad n] [Finite α Id]
|
||||
[IteratorLoop α Id n] [LawfulIteratorLoop α Id n]
|
||||
{it : Iter (α := α) β} {f : β → Option β₂} {init : γ} {g : β₂ → γ → n (ForInStep γ)} :
|
||||
forIn (it.filterMap f) init g = forIn it init (fun out acc => do
|
||||
match f out with
|
||||
| some c => g c acc
|
||||
| none => return .yield acc) := by
|
||||
simp [filterMap, forIn_eq_forIn_toIterM, IterM.forIn_filterMap]; rfl
|
||||
|
||||
theorem Iter.forIn_mapWithPostcondition
|
||||
[Monad n] [LawfulMonad n] [Monad o] [LawfulMonad o]
|
||||
[MonadLiftT n o] [LawfulMonadLiftT n o] [Finite α Id]
|
||||
[IteratorLoop α Id o] [LawfulIteratorLoop α Id o]
|
||||
{it : Iter (α := α) β} {f : β → PostconditionT n β₂} {init : γ}
|
||||
{g : β₂ → γ → o (ForInStep γ)} :
|
||||
forIn (it.mapWithPostcondition f) init g =
|
||||
forIn it init (fun out acc => do g (← (f out).run) acc) := by
|
||||
simp [mapWithPostcondition, forIn_eq_forIn_toIterM, IterM.forIn_mapWithPostcondition,
|
||||
instMonadLiftTOfMonadLift_instMonadLiftTOfPure]
|
||||
|
||||
theorem Iter.forIn_mapM
|
||||
[Monad n] [LawfulMonad n] [Monad o] [LawfulMonad o]
|
||||
[MonadAttach n] [WeaklyLawfulMonadAttach n]
|
||||
[MonadLiftT n o] [LawfulMonadLiftT n o]
|
||||
[Finite α Id]
|
||||
[IteratorLoop α Id o] [LawfulIteratorLoop α Id o]
|
||||
{it : Iter (α := α) β} {f : β → n β₂} {init : γ} {g : β₂ → γ → o (ForInStep γ)} :
|
||||
forIn (it.mapM f) init g = forIn it init (fun out acc => do g (← f out) acc) := by
|
||||
rw [mapM, forIn_eq_forIn_toIterM, IterM.forIn_mapM, instMonadLiftTOfMonadLift_instMonadLiftTOfPure]
|
||||
|
||||
theorem Iter.forIn_map
|
||||
[Monad n] [LawfulMonad n]
|
||||
[Finite α Id] [IteratorLoop α Id n] [LawfulIteratorLoop α Id n]
|
||||
{it : Iter (α := α) β} {f : β → β₂} {init : γ} {g : β₂ → γ → n (ForInStep γ)} :
|
||||
forIn (it.map f) init g = forIn it init (fun out acc => do g (f out) acc) := by
|
||||
simp [map, forIn_eq_forIn_toIterM, IterM.forIn_map]
|
||||
|
||||
theorem Iter.forIn_filterWithPostcondition
|
||||
[Monad n] [LawfulMonad n] [Monad o] [LawfulMonad o]
|
||||
[MonadLiftT n o] [LawfulMonadLiftT n o]
|
||||
[Finite α Id] [IteratorLoop α Id o] [LawfulIteratorLoop α Id o]
|
||||
{it : Iter (α := α) β} {f : β → PostconditionT n (ULift Bool)} {init : γ}
|
||||
{g : β → γ → o (ForInStep γ)} :
|
||||
haveI : MonadLift n o := ⟨monadLift⟩
|
||||
forIn (it.filterWithPostcondition f) init g =
|
||||
forIn it init (fun out acc => do if (← (f out).run).down then g out acc else return .yield acc) := by
|
||||
simp [filterWithPostcondition, forIn_eq_forIn_toIterM, IterM.forIn_filterWithPostcondition,
|
||||
instMonadLiftTOfMonadLift_instMonadLiftTOfPure]
|
||||
|
||||
theorem Iter.forIn_filterM
|
||||
[Monad n] [LawfulMonad n] [Monad o] [LawfulMonad o]
|
||||
[MonadAttach n] [WeaklyLawfulMonadAttach n]
|
||||
[MonadLiftT n o] [LawfulMonadLiftT n o] [Finite α Id]
|
||||
[IteratorLoop α Id o] [LawfulIteratorLoop α Id o]
|
||||
{it : Iter (α := α) β} {f : β → n (ULift Bool)} {init : γ} {g : β → γ → o (ForInStep γ)} :
|
||||
forIn (it.filterM f) init g = forIn it init (fun out acc => do if (← f out).down then g out acc else return .yield acc) := by
|
||||
simp [filterM, forIn_eq_forIn_toIterM, IterM.forIn_filterM,
|
||||
instMonadLiftTOfMonadLift_instMonadLiftTOfPure]
|
||||
|
||||
theorem Iter.forIn_filter
|
||||
[Monad n] [LawfulMonad n]
|
||||
[Finite α Id] [IteratorLoop α Id n] [LawfulIteratorLoop α Id n]
|
||||
{it : Iter (α := α) β} {f : β → Bool} {init : γ} {g : β → γ → n (ForInStep γ)} :
|
||||
forIn (it.filter f) init g = forIn it init (fun out acc => do if f out then g out acc else return .yield acc) := by
|
||||
simp [filter, forIn_eq_forIn_toIterM, IterM.forIn_filter]
|
||||
|
||||
end ForIn
|
||||
|
||||
section Fold
|
||||
|
||||
theorem Iter.foldM_filterMapM {α β γ δ : Type w} {m : Type w → Type w'} {n : Type w → Type w''}
|
||||
[Iterator α Id β] [Finite α Id] [Monad m] [Monad n] [LawfulMonad m] [LawfulMonad n]
|
||||
[IteratorLoop α Id Id] [IteratorLoop α Id m] [IteratorLoop α Id n]
|
||||
[MonadLiftT m n] [LawfulMonadLiftT m n]
|
||||
[LawfulIteratorLoop α Id Id] [LawfulIteratorLoop α Id m] [LawfulIteratorLoop α Id n]
|
||||
{f : β → m (Option γ)} {g : δ → γ → n δ} {init : δ} {it : Iter (α := α) β} :
|
||||
theorem Iter.foldM_filterMapWithPostcondition {α β γ δ : Type w}
|
||||
{n : Type w → Type w''} {o : Type w → Type w'''}
|
||||
[Iterator α Id β] [Finite α Id]
|
||||
[Monad n] [Monad o] [LawfulMonad n] [LawfulMonad o]
|
||||
[IteratorLoop α Id n] [IteratorLoop α Id o]
|
||||
[LawfulIteratorLoop α Id n] [LawfulIteratorLoop α Id o]
|
||||
[MonadLiftT n o] [LawfulMonadLiftT n o]
|
||||
{f : β → PostconditionT n (Option γ)} {g : δ → γ → o δ} {init : δ} {it : Iter (α := α) β} :
|
||||
(it.filterMapWithPostcondition f).foldM (init := init) g =
|
||||
it.foldM (init := init) (fun d b => do
|
||||
let some c ← (f b).run | pure d
|
||||
g d c) := by
|
||||
rw [filterMapWithPostcondition, IterM.foldM_filterMapWithPostcondition, foldM_eq_foldM_toIterM,
|
||||
instMonadLiftTOfMonadLift_instMonadLiftTOfPure]; rfl
|
||||
|
||||
theorem Iter.foldM_filterMapM {α β γ δ : Type w}
|
||||
{n : Type w → Type w''} {o : Type w → Type w'''}
|
||||
[Iterator α Id β] [Finite α Id]
|
||||
[Monad n] [MonadAttach n] [LawfulMonad n] [WeaklyLawfulMonadAttach n]
|
||||
[Monad o] [LawfulMonad o]
|
||||
[IteratorLoop α Id n] [IteratorLoop α Id o]
|
||||
[LawfulIteratorLoop α Id n] [LawfulIteratorLoop α Id o]
|
||||
[MonadLiftT n o] [LawfulMonadLiftT n o]
|
||||
{f : β → n (Option γ)} {g : δ → γ → o δ} {init : δ} {it : Iter (α := α) β} :
|
||||
(it.filterMapM f).foldM (init := init) g =
|
||||
it.foldM (init := init) (fun d b => do
|
||||
let some c ← f b | pure d
|
||||
g d c) := by
|
||||
rw [foldM_eq_foldM_toIterM, filterMapM_eq_toIter_filterMapM_toIterM, IterM.foldM_filterMapM]
|
||||
congr
|
||||
simp [instMonadLiftTOfMonadLift, Id.instMonadLiftTOfPure]
|
||||
simp [filterMapM, IterM.foldM_filterMapM, foldM_eq_foldM_toIterM,
|
||||
instMonadLiftTOfMonadLift_instMonadLiftTOfPure]; rfl
|
||||
|
||||
theorem Iter.foldM_mapM {α β γ δ : Type w} {m : Type w → Type w'} {n : Type w → Type w''}
|
||||
[Iterator α Id β] [Finite α Id] [Monad m] [Monad n] [LawfulMonad m] [LawfulMonad n]
|
||||
[IteratorLoop α Id m] [IteratorLoop α Id n]
|
||||
[LawfulIteratorLoop α Id m] [LawfulIteratorLoop α Id n]
|
||||
[MonadLiftT m n] [LawfulMonadLiftT m n]
|
||||
{f : β → m γ} {g : δ → γ → n δ} {init : δ} {it : Iter (α := α) β} :
|
||||
theorem Iter.foldM_mapWithPostcondition {α β γ δ : Type w}
|
||||
{n : Type w → Type w''} {o : Type w → Type w'''}
|
||||
[Iterator α Id β] [Finite α Id]
|
||||
[Monad m] [Monad n] [Monad o] [LawfulMonad m][LawfulMonad n] [LawfulMonad o]
|
||||
[IteratorLoop α Id n] [IteratorLoop α Id o]
|
||||
[LawfulIteratorLoop α Id n] [LawfulIteratorLoop α Id o]
|
||||
[MonadLiftT n o] [LawfulMonadLiftT n o]
|
||||
{f : β → PostconditionT n γ} {g : δ → γ → o δ} {init : δ} {it : Iter (α := α) β} :
|
||||
(it.mapWithPostcondition f).foldM (init := init) g =
|
||||
it.foldM (init := init) (fun d b => do let c ← (f b).run; g d c) := by
|
||||
simp [mapWithPostcondition, IterM.foldM_mapWithPostcondition, foldM_eq_foldM_toIterM,
|
||||
instMonadLiftTOfMonadLift_instMonadLiftTOfPure]
|
||||
|
||||
theorem Iter.foldM_mapM {α β γ δ : Type w}
|
||||
{n : Type w → Type w''} {o : Type w → Type w'''}
|
||||
[Iterator α Id β] [Finite α Id]
|
||||
[Monad n] [MonadAttach n] [LawfulMonad n] [WeaklyLawfulMonadAttach n]
|
||||
[Monad o] [LawfulMonad o]
|
||||
[IteratorLoop α Id n] [IteratorLoop α Id o]
|
||||
[LawfulIteratorLoop α Id n] [LawfulIteratorLoop α Id o]
|
||||
[MonadLiftT n o] [LawfulMonadLiftT n o]
|
||||
{f : β → n γ} {g : δ → γ → o δ} {init : δ} {it : Iter (α := α) β} :
|
||||
haveI : MonadLift n o := ⟨MonadLiftT.monadLift⟩
|
||||
(it.mapM f).foldM (init := init) g =
|
||||
it.foldM (init := init) (fun d b => do let c ← f b; g d c) := by
|
||||
rw [foldM_eq_foldM_toIterM, mapM_eq_toIter_mapM_toIterM, IterM.foldM_mapM]
|
||||
congr
|
||||
simp [instMonadLiftTOfMonadLift, Id.instMonadLiftTOfPure]
|
||||
simp [mapM, IterM.foldM_mapM, foldM_eq_foldM_toIterM,
|
||||
instMonadLiftTOfMonadLift_instMonadLiftTOfPure]
|
||||
|
||||
theorem Iter.foldM_filterMap {α β γ : Type w} {δ : Type x} {m : Type x → Type w'}
|
||||
[Iterator α Id β] [Finite α Id] [Monad m] [LawfulMonad m]
|
||||
[IteratorLoop α Id m] [LawfulIteratorLoop α Id m]
|
||||
{f : β → Option γ} {g : δ → γ → m δ} {init : δ} {it : Iter (α := α) β} :
|
||||
theorem Iter.foldM_filterWithPostcondition {α β δ : Type w}
|
||||
{n : Type w → Type w''} {o : Type w → Type w'''}
|
||||
[Iterator α Id β] [Finite α Id]
|
||||
[Monad n] [Monad o] [LawfulMonad n] [LawfulMonad o]
|
||||
[IteratorLoop α Id n] [IteratorLoop α Id o]
|
||||
[LawfulIteratorLoop α Id n] [LawfulIteratorLoop α Id o]
|
||||
[MonadLiftT n o] [LawfulMonadLiftT n o]
|
||||
{f : β → PostconditionT n (ULift Bool)} {g : δ → β → o δ} {init : δ} {it : Iter (α := α) β} :
|
||||
(it.filterWithPostcondition f).foldM (init := init) g =
|
||||
it.foldM (init := init) (fun d b => do if (← (f b).run).down then g d b else pure d) := by
|
||||
simp [filterWithPostcondition, IterM.foldM_filterWithPostcondition, foldM_eq_foldM_toIterM,
|
||||
instMonadLiftTOfMonadLift_instMonadLiftTOfPure]
|
||||
|
||||
theorem Iter.foldM_filterM {α β δ : Type w}
|
||||
{n : Type w → Type w''} {o : Type w → Type w'''}
|
||||
[Iterator α Id β] [Finite α Id]
|
||||
[Monad n] [MonadAttach n] [LawfulMonad n] [WeaklyLawfulMonadAttach n]
|
||||
[Monad o] [LawfulMonad o]
|
||||
[IteratorLoop α Id n] [IteratorLoop α Id o]
|
||||
[LawfulIteratorLoop α Id n] [LawfulIteratorLoop α Id o]
|
||||
[MonadLiftT n o] [LawfulMonadLiftT n o]
|
||||
{f : β → n (ULift Bool)} {g : δ → β → o δ} {init : δ} {it : Iter (α := α) β} :
|
||||
(it.filterM f).foldM (init := init) g =
|
||||
it.foldM (init := init) (fun d b => do if (← f b).down then g d b else pure d) := by
|
||||
simp [filterM, IterM.foldM_filterM, foldM_eq_foldM_toIterM,
|
||||
instMonadLiftTOfMonadLift_instMonadLiftTOfPure]
|
||||
|
||||
theorem Iter.foldM_filterMap {α β γ δ : Type w} {n : Type w → Type w''}
|
||||
[Iterator α Id β] [Finite α Id] [Monad n] [LawfulMonad n]
|
||||
[IteratorLoop α Id n]
|
||||
[LawfulIteratorLoop α Id n]
|
||||
{f : β → Option γ} {g : δ → γ → n δ} {init : δ} {it : Iter (α := α) β} :
|
||||
(it.filterMap f).foldM (init := init) g =
|
||||
it.foldM (init := init) (fun d b => do
|
||||
let some c := f b | pure d
|
||||
g d c) := by
|
||||
induction it using Iter.inductSteps generalizing init with | step it ihy ihs
|
||||
rw [foldM_eq_match_step, foldM_eq_match_step, step_filterMap]
|
||||
-- There seem to be some type dependencies that, combined with nested match expressions,
|
||||
-- force us to split a lot.
|
||||
split <;> rename_i h
|
||||
· split at h
|
||||
· split at h
|
||||
· cases h
|
||||
· cases h; simp [*, ihy ‹_›]
|
||||
· cases h
|
||||
· cases h
|
||||
· split at h
|
||||
· split at h
|
||||
· cases h; simp [*, ihy ‹_›]
|
||||
· cases h
|
||||
· cases h; simp [*, ihs ‹_›]
|
||||
· cases h
|
||||
· split at h
|
||||
· split at h
|
||||
· cases h
|
||||
· cases h
|
||||
· cases h
|
||||
· simp [*]
|
||||
simp [filterMap, IterM.foldM_filterMap, foldM_eq_foldM_toIterM]; rfl
|
||||
|
||||
theorem Iter.foldM_map {α β γ : Type w} {δ : Type x} {m : Type x → Type w'}
|
||||
[Iterator α Id β] [Finite α Id] [Monad m] [LawfulMonad m]
|
||||
[IteratorLoop α Id m] [LawfulIteratorLoop α Id m]
|
||||
{f : β → γ} {g : δ → γ → m δ} {init : δ} {it : Iter (α := α) β} :
|
||||
theorem Iter.foldM_map {α β γ δ : Type w} {n : Type w → Type w''}
|
||||
[Iterator α Id β] [Finite α Id] [Monad n] [LawfulMonad n]
|
||||
[IteratorLoop α Id n] [LawfulIteratorLoop α Id n]
|
||||
{f : β → γ} {g : δ → γ → n δ} {init : δ} {it : Iter (α := α) β} :
|
||||
(it.map f).foldM (init := init) g =
|
||||
it.foldM (init := init) (fun d b => g d (f b)) := by
|
||||
induction it using Iter.inductSteps generalizing init with | step it ihy ihs
|
||||
rw [foldM_eq_match_step, foldM_eq_match_step, step_map]
|
||||
cases it.step using PlausibleIterStep.casesOn
|
||||
· simp [*, ihy ‹_›]
|
||||
· simp [*, ihs ‹_›]
|
||||
· simp
|
||||
it.foldM (init := init) (fun d b => do g d (f b)) := by
|
||||
simp [foldM_eq_forIn, forIn_map]
|
||||
|
||||
theorem Iter.fold_filterMapM {α β γ δ : Type w} {m : Type w → Type w'}
|
||||
[Iterator α Id β] [Finite α Id] [Monad m] [LawfulMonad m]
|
||||
[IteratorLoop α Id Id.{w}] [IteratorLoop α Id m]
|
||||
[LawfulIteratorLoop α Id Id] [LawfulIteratorLoop α Id m]
|
||||
{f : β → m (Option γ)} {g : δ → γ → δ} {init : δ} {it : Iter (α := α) β} :
|
||||
theorem Iter.foldM_filter {α β δ : Type w} {n : Type w → Type w''}
|
||||
[Iterator α Id β] [Finite α Id] [Monad n] [LawfulMonad n]
|
||||
[IteratorLoop α Id n] [LawfulIteratorLoop α Id n]
|
||||
{f : β → Bool} {g : δ → β → n δ} {init : δ} {it : Iter (α := α) β} :
|
||||
(it.filter f).foldM (init := init) g =
|
||||
it.foldM (init := init) (fun d b => if f b then g d b else pure d) := by
|
||||
simp only [foldM_eq_forIn, forIn_filter]
|
||||
congr 1; ext out acc
|
||||
cases f out <;> simp
|
||||
|
||||
theorem Iter.fold_filterMapWithPostcondition {α β γ δ : Type w} {n : Type w → Type w''}
|
||||
[Iterator α Id β] [Finite α Id]
|
||||
[Monad n] [LawfulMonad n]
|
||||
[IteratorLoop α Id n] [LawfulIteratorLoop α Id n]
|
||||
{f : β → PostconditionT n (Option γ)} {g : δ → γ → δ} {init : δ} {it : Iter (α := α) β} :
|
||||
(it.filterMapWithPostcondition f).fold (init := init) g =
|
||||
it.foldM (init := init) (fun d b => do
|
||||
let some c ← (f b).run | pure d
|
||||
return g d c) := by
|
||||
simp [filterMapWithPostcondition, IterM.fold_filterMapWithPostcondition, foldM_eq_foldM_toIterM]
|
||||
rfl
|
||||
|
||||
theorem Iter.fold_filterMapM {α β γ δ : Type w} {n : Type w → Type w''}
|
||||
[Iterator α Id β] [Finite α Id]
|
||||
[Monad n] [MonadAttach n] [LawfulMonad n] [WeaklyLawfulMonadAttach n]
|
||||
[IteratorLoop α Id n] [LawfulIteratorLoop α Id n]
|
||||
{f : β → n (Option γ)} {g : δ → γ → δ} {init : δ} {it : Iter (α := α) β} :
|
||||
(it.filterMapM f).fold (init := init) g =
|
||||
it.foldM (init := init) (fun d b => do
|
||||
let some c ← f b | pure d
|
||||
return g d c) := by
|
||||
rw [foldM_eq_foldM_toIterM, filterMapM_eq_toIter_filterMapM_toIterM, IterM.fold_filterMapM]
|
||||
rfl
|
||||
simp [filterMapM, IterM.fold_filterMapM, foldM_eq_foldM_toIterM]; rfl
|
||||
|
||||
theorem Iter.fold_mapM {α β γ δ : Type w} {m : Type w → Type w'}
|
||||
[Iterator α Id β] [Finite α Id] [Monad m] [LawfulMonad m]
|
||||
[IteratorLoop α Id Id.{w}] [IteratorLoop α Id m]
|
||||
[LawfulIteratorLoop α Id Id] [LawfulIteratorLoop α Id m]
|
||||
{f : β → m γ} {g : δ → γ → δ} {init : δ} {it : Iter (α := α) β} :
|
||||
theorem Iter.fold_mapWithPostcondition {α β γ δ : Type w} {n : Type w → Type w''}
|
||||
[Iterator α Id β] [Finite α Id]
|
||||
[Monad n] [LawfulMonad n]
|
||||
[IteratorLoop α Id n] [LawfulIteratorLoop α Id n]
|
||||
{f : β → PostconditionT n γ} {g : δ → γ → δ} {init : δ} {it : Iter (α := α) β} :
|
||||
(it.mapWithPostcondition f).fold (init := init) g =
|
||||
it.foldM (init := init) (fun d b => do let c ← (f b).run; return g d c) := by
|
||||
simp [mapWithPostcondition, IterM.fold_mapWithPostcondition, foldM_eq_foldM_toIterM]
|
||||
|
||||
theorem Iter.fold_mapM {α β γ δ : Type w} {n : Type w → Type w''}
|
||||
[Iterator α Id β] [Finite α Id]
|
||||
[Monad n] [MonadAttach n] [LawfulMonad n] [WeaklyLawfulMonadAttach n]
|
||||
[IteratorLoop α Id n] [LawfulIteratorLoop α Id n]
|
||||
{f : β → n γ} {g : δ → γ → δ} {init : δ} {it : Iter (α := α) β} :
|
||||
(it.mapM f).fold (init := init) g =
|
||||
it.foldM (init := init) (fun d b => do return g d (← f b)) := by
|
||||
rw [foldM_eq_foldM_toIterM, mapM_eq_toIter_mapM_toIterM, IterM.fold_mapM]
|
||||
it.foldM (init := init) (fun d b => do let c ← f b; return g d c) := by
|
||||
simp [mapM, IterM.fold_mapM, foldM_eq_foldM_toIterM]
|
||||
|
||||
theorem Iter.fold_filterMap {α β γ : Type w} {δ : Type x}
|
||||
[Iterator α Id β] [Finite α Id] [IteratorLoop α Id Id] [LawfulIteratorLoop α Id Id]
|
||||
theorem Iter.fold_filterWithPostcondition {α β δ : Type w}
|
||||
{n : Type w → Type w''}
|
||||
[Iterator α Id β] [Finite α Id]
|
||||
[Monad n] [LawfulMonad n]
|
||||
[IteratorLoop α Id n] [LawfulIteratorLoop α Id n]
|
||||
{f : β → PostconditionT n (ULift Bool)} {g : δ → β → δ} {init : δ} {it : Iter (α := α) β} :
|
||||
(it.filterWithPostcondition f).fold (init := init) g =
|
||||
it.foldM (init := init) (fun d b => return if (← (f b).run).down then g d b else d) := by
|
||||
simp [filterWithPostcondition, IterM.fold_filterWithPostcondition, foldM_eq_foldM_toIterM]
|
||||
|
||||
theorem Iter.fold_filterM {α β δ : Type w} {n : Type w → Type w''}
|
||||
[Iterator α Id β] [Finite α Id]
|
||||
[Monad n] [MonadAttach n] [LawfulMonad n] [WeaklyLawfulMonadAttach n]
|
||||
[IteratorLoop α Id n] [LawfulIteratorLoop α Id n]
|
||||
{f : β → n (ULift Bool)} {g : δ → β → δ} {init : δ} {it : Iter (α := α) β} :
|
||||
(it.filterM f).fold (init := init) g =
|
||||
it.foldM (init := init) (fun d b => return if (← f b).down then g d b else d) := by
|
||||
simp [filterM, IterM.fold_filterM, foldM_eq_foldM_toIterM]
|
||||
|
||||
theorem Iter.fold_filterMap {α β γ δ : Type w}
|
||||
[Iterator α Id β] [Finite α Id]
|
||||
[IteratorLoop α Id Id] [LawfulIteratorLoop α Id Id]
|
||||
{f : β → Option γ} {g : δ → γ → δ} {init : δ} {it : Iter (α := α) β} :
|
||||
(it.filterMap f).fold (init := init) g =
|
||||
it.fold (init := init) (fun d b =>
|
||||
match f b with
|
||||
| some c => g d c
|
||||
| _ => d) := by
|
||||
simp only [fold_eq_foldM, foldM_filterMap]
|
||||
rfl
|
||||
simp [filterMap, IterM.fold_filterMap, fold_eq_fold_toIterM]; rfl
|
||||
|
||||
theorem Iter.fold_map {α β γ : Type w} {δ : Type x}
|
||||
theorem Iter.fold_map {α β γ δ : Type w}
|
||||
[Iterator α Id β] [Finite α Id]
|
||||
[IteratorLoop α Id Id] [LawfulIteratorLoop α Id Id]
|
||||
{f : β → γ} {g : δ → γ → δ} {init : δ} {it : Iter (α := α) β} :
|
||||
@@ -465,6 +709,14 @@ theorem Iter.fold_map {α β γ : Type w} {δ : Type x}
|
||||
it.fold (init := init) (fun d b => g d (f b)) := by
|
||||
simp [fold_eq_foldM, foldM_map]
|
||||
|
||||
theorem Iter.fold_filter {α β δ : Type w}
|
||||
[Iterator α Id β] [Finite α Id]
|
||||
[IteratorLoop α Id Id] [LawfulIteratorLoop α Id Id]
|
||||
{f : β → Bool} {g : δ → β → δ} {init : δ} {it : Iter (α := α) β} :
|
||||
(it.filter f).fold (init := init) g =
|
||||
it.fold (init := init) (fun d b => if f b then g d b else d) := by
|
||||
simp [filter, IterM.fold_filter, fold_eq_fold_toIterM]
|
||||
|
||||
end Fold
|
||||
|
||||
section Count
|
||||
@@ -479,7 +731,7 @@ theorem Iter.count_map {α β β' : Type w} [Iterator α Id β]
|
||||
end Count
|
||||
|
||||
theorem Iter.anyM_filterMapM {α β β' : Type w} {m : Type w → Type w'}
|
||||
[Iterator α Id β] [Finite α Id] [Monad m] [LawfulMonad m]
|
||||
[Iterator α Id β] [Finite α Id] [Monad m] [MonadAttach m] [LawfulMonad m] [WeaklyLawfulMonadAttach m]
|
||||
{it : Iter (α := α) β} {f : β → m (Option β')} {p : β' → m (ULift Bool)} :
|
||||
(it.filterMapM f).anyM p = (it.mapM (pure (f := m))).anyM (fun x => do
|
||||
match ← f x with
|
||||
@@ -494,14 +746,24 @@ This lemma expresses `Iter.anyM` in terms of `IterM.anyM`.
|
||||
It requires all involved types to live in `Type 0`.
|
||||
-/
|
||||
theorem Iter.anyM_eq_anyM_mapM_pure {α β : Type} {m : Type → Type w'} [Iterator α Id β]
|
||||
[Finite α Id] [Monad m] [LawfulMonad m] [IteratorLoop α Id m] [LawfulIteratorLoop α Id m]
|
||||
[Finite α Id] [Monad m] [MonadAttach m] [LawfulMonad m] [WeaklyLawfulMonadAttach m]
|
||||
[IteratorLoop α Id m] [LawfulIteratorLoop α Id m]
|
||||
{it : Iter (α := α) β} {p : β → m Bool} :
|
||||
it.anyM p = ULift.down <$> (it.mapM (α := α) (pure (f := m))).anyM (fun x => ULift.up <$> p x) := by
|
||||
rw [anyM_eq_forIn, IterM.anyM_eq_forIn, map_eq_pure_bind]
|
||||
induction it using Iter.inductSteps with | step it ihy ihs =>
|
||||
rw [forIn_eq_match_step, IterM.forIn_eq_match_step, bind_assoc, step_mapM]
|
||||
cases it.step using PlausibleIterStep.casesOn
|
||||
· simp only [bind_assoc, liftM_pure, pure_bind, map_eq_pure_bind, Shrink.inflate_deflate]
|
||||
· rename_i out _
|
||||
simp only [bind_assoc, pure_bind, map_eq_pure_bind, Shrink.inflate_deflate,
|
||||
liftM, monadLift]
|
||||
have {x : m Bool} : x = MonadAttach.attach (pure out) >>= (fun _ => x) := by
|
||||
rw (occs := [1]) [show x = pure out >>= (fun _ => x) by simp]
|
||||
conv => lhs; rw [← WeaklyLawfulMonadAttach.map_attach (x := pure out)]
|
||||
simp
|
||||
refine Eq.trans this ?_
|
||||
simp only [WeaklyLawfulMonadAttach.bind_attach_of_nonempty (x := pure out), pure_bind]
|
||||
split; rotate_left; rfl
|
||||
apply bind_congr; intro px
|
||||
split
|
||||
· simp
|
||||
@@ -510,13 +772,13 @@ theorem Iter.anyM_eq_anyM_mapM_pure {α β : Type} {m : Type → Type w'} [Itera
|
||||
· simp
|
||||
|
||||
theorem Iter.anyM_mapM {α β β' : Type w} {m : Type w → Type w'}
|
||||
[Iterator α Id β] [Finite α Id] [Monad m] [LawfulMonad m]
|
||||
[Iterator α Id β] [Finite α Id] [Monad m] [MonadAttach m] [LawfulMonad m] [WeaklyLawfulMonadAttach m]
|
||||
{it : Iter (α := α) β} {f : β → m β'} {p : β' → m (ULift Bool)} :
|
||||
(it.mapM f).anyM p = (it.mapM (pure (f := m))).anyM (fun x => do p (← f x)) := by
|
||||
rw [mapM_eq_toIter_mapM_toIterM, IterM.anyM_mapM, mapM_eq_toIter_mapM_toIterM]
|
||||
|
||||
theorem Iter.anyM_filterM {α β : Type w} {m : Type w → Type w'}
|
||||
[Iterator α Id β] [Finite α Id] [Monad m] [LawfulMonad m]
|
||||
[Iterator α Id β] [Finite α Id] [Monad m] [MonadAttach m] [LawfulMonad m] [WeaklyLawfulMonadAttach m]
|
||||
{it : Iter (α := α) β} {f : β → m (ULift Bool)} {p : β → m (ULift Bool)} :
|
||||
(it.filterM f).anyM p = (it.mapM (pure (f := m))).anyM (fun x => do
|
||||
if (← f x).down then
|
||||
@@ -576,8 +838,8 @@ theorem Iter.anyM_filter {α β : Type w} {m : Type → Type w'}
|
||||
· simp
|
||||
|
||||
theorem Iter.any_filterMapM {α β β' : Type w} {m : Type w → Type w'}
|
||||
[Iterator α Id β] [Finite α Id] [Monad m] [IteratorLoop α Id m]
|
||||
[LawfulMonad m] [LawfulIteratorLoop α Id m]
|
||||
[Iterator α Id β] [Finite α Id] [IteratorLoop α Id m]
|
||||
[Monad m] [MonadAttach m] [LawfulMonad m] [WeaklyLawfulMonadAttach m] [LawfulIteratorLoop α Id m]
|
||||
{it : Iter (α := α) β} {f : β → m (Option β')} {p : β' → Bool} :
|
||||
(it.filterMapM f).any p = (it.mapM (pure (f := m))).anyM (fun x => do
|
||||
match ← f x with
|
||||
@@ -586,15 +848,15 @@ theorem Iter.any_filterMapM {α β β' : Type w} {m : Type w → Type w'}
|
||||
simp [IterM.any_eq_anyM, anyM_filterMapM]
|
||||
|
||||
theorem Iter.any_mapM {α β β' : Type w} {m : Type w → Type w'}
|
||||
[Iterator α Id β] [Finite α Id] [Monad m] [IteratorLoop α Id m]
|
||||
[LawfulMonad m] [LawfulIteratorLoop α Id m]
|
||||
[Iterator α Id β] [Finite α Id] [IteratorLoop α Id m]
|
||||
[Monad m] [MonadAttach m] [LawfulMonad m] [WeaklyLawfulMonadAttach m] [LawfulIteratorLoop α Id m]
|
||||
{it : Iter (α := α) β} {f : β → m β'} {p : β' → Bool} :
|
||||
(it.mapM f).any p = (it.mapM pure).anyM (fun x => (.up <| p ·) <$> (f x)) := by
|
||||
simp [IterM.any_eq_anyM, anyM_mapM]
|
||||
|
||||
theorem Iter.any_filterM {α β : Type w} {m : Type w → Type w'}
|
||||
[Iterator α Id β] [Finite α Id] [Monad m] [IteratorLoop α Id m]
|
||||
[LawfulMonad m] [LawfulIteratorLoop α Id m]
|
||||
[Iterator α Id β] [Finite α Id] [IteratorLoop α Id m]
|
||||
[Monad m] [MonadAttach m] [LawfulMonad m] [WeaklyLawfulMonadAttach m] [LawfulIteratorLoop α Id m]
|
||||
{it : Iter (α := α) β} {f : β → m (ULift Bool)} {p : β → Bool} :
|
||||
(it.filterM f).any p = (it.mapM (pure (f := m))).anyM (fun x => do
|
||||
if (← f x).down then
|
||||
@@ -636,7 +898,7 @@ theorem Iter.any_map {α β β' : Type w}
|
||||
· simp
|
||||
|
||||
theorem Iter.allM_filterMapM {α β β' : Type w} {m : Type w → Type w'}
|
||||
[Iterator α Id β] [Finite α Id] [Monad m] [LawfulMonad m]
|
||||
[Iterator α Id β] [Finite α Id] [Monad m] [MonadAttach m] [LawfulMonad m] [WeaklyLawfulMonadAttach m]
|
||||
{it : Iter (α := α) β} {f : β → m (Option β')} {p : β' → m (ULift Bool)} :
|
||||
(it.filterMapM f).allM p = (it.mapM (pure (f := m))).allM (fun x => do
|
||||
match ← f x with
|
||||
@@ -650,29 +912,19 @@ This lemma expresses `Iter.allM` in terms of `IterM.allM`.
|
||||
It requires all involved types to live in `Type 0`.
|
||||
-/
|
||||
theorem Iter.allM_eq_allM_mapM_pure {α β : Type} {m : Type → Type w'} [Iterator α Id β]
|
||||
[Finite α Id] [Monad m] [LawfulMonad m] [IteratorLoop α Id m] [LawfulIteratorLoop α Id m]
|
||||
{it : Iter (α := α) β} {p : β → m Bool} :
|
||||
[Finite α Id] [Monad m] [MonadAttach m] [LawfulMonad m] [WeaklyLawfulMonadAttach m]
|
||||
[IteratorLoop α Id m] [LawfulIteratorLoop α Id m] {it : Iter (α := α) β} {p : β → m Bool} :
|
||||
it.allM p = ULift.down <$> (it.mapM (α := α) (pure (f := m))).allM (fun x => ULift.up <$> p x) := by
|
||||
rw [allM_eq_forIn, IterM.allM_eq_forIn, map_eq_pure_bind]
|
||||
induction it using Iter.inductSteps with | step it ihy ihs =>
|
||||
rw [forIn_eq_match_step, IterM.forIn_eq_match_step, bind_assoc, step_mapM]
|
||||
cases it.step using PlausibleIterStep.casesOn
|
||||
· simp only [bind_assoc, liftM_pure, pure_bind, map_eq_pure_bind, Shrink.inflate_deflate]
|
||||
apply bind_congr; intro px
|
||||
split
|
||||
· simp [ihy ‹_›]
|
||||
· simp
|
||||
· simp [ihs ‹_›]
|
||||
· simp
|
||||
simp [allM_eq_not_anyM_not, anyM_eq_anyM_mapM_pure, IterM.allM_eq_not_anyM_not]
|
||||
|
||||
theorem Iter.allM_mapM {α β β' : Type w} {m : Type w → Type w'}
|
||||
[Iterator α Id β] [Finite α Id] [Monad m] [LawfulMonad m]
|
||||
[Iterator α Id β] [Finite α Id] [Monad m] [MonadAttach m] [LawfulMonad m] [WeaklyLawfulMonadAttach m]
|
||||
{it : Iter (α := α) β} {f : β → m β'} {p : β' → m (ULift Bool)} :
|
||||
(it.mapM f).allM p = (it.mapM (pure (f := m))).allM (fun x => do p (← f x)) := by
|
||||
rw [mapM_eq_toIter_mapM_toIterM, IterM.allM_mapM, mapM_eq_toIter_mapM_toIterM]
|
||||
|
||||
theorem Iter.allM_filterM {α β : Type w} {m : Type w → Type w'}
|
||||
[Iterator α Id β] [Finite α Id] [Monad m] [LawfulMonad m]
|
||||
[Iterator α Id β] [Finite α Id] [Monad m] [MonadAttach m] [LawfulMonad m] [WeaklyLawfulMonadAttach m]
|
||||
{it : Iter (α := α) β} {f : β → m (ULift Bool)} {p : β → m (ULift Bool)} :
|
||||
(it.filterM f).allM p = (it.mapM (pure (f := m))).allM (fun x => do
|
||||
if (← f x).down then
|
||||
@@ -732,8 +984,9 @@ theorem Iter.allM_filter {α β : Type w} {m : Type → Type w'}
|
||||
· simp
|
||||
|
||||
theorem Iter.all_filterMapM {α β β' : Type w} {m : Type w → Type w'}
|
||||
[Iterator α Id β] [Finite α Id] [Monad m] [IteratorLoop α Id m]
|
||||
[LawfulMonad m] [LawfulIteratorLoop α Id m]
|
||||
[Iterator α Id β] [Finite α Id] [IteratorLoop α Id m]
|
||||
[Monad m] [MonadAttach m] [LawfulMonad m] [WeaklyLawfulMonadAttach m]
|
||||
[LawfulIteratorLoop α Id m]
|
||||
{it : Iter (α := α) β} {f : β → m (Option β')} {p : β' → Bool} :
|
||||
(it.filterMapM f).all p = (it.mapM (pure (f := m))).allM (fun x => do
|
||||
match ← f x with
|
||||
@@ -742,15 +995,15 @@ theorem Iter.all_filterMapM {α β β' : Type w} {m : Type w → Type w'}
|
||||
simp [IterM.all_eq_allM, allM_filterMapM]
|
||||
|
||||
theorem Iter.all_mapM {α β β' : Type w} {m : Type w → Type w'}
|
||||
[Iterator α Id β] [Finite α Id] [Monad m] [IteratorLoop α Id m]
|
||||
[LawfulMonad m] [LawfulIteratorLoop α Id m]
|
||||
{it : Iter (α := α) β} {f : β → m β'} {p : β' → Bool} :
|
||||
[Iterator α Id β] [Finite α Id] [IteratorLoop α Id m]
|
||||
[Monad m] [MonadAttach m] [LawfulMonad m] [WeaklyLawfulMonadAttach m]
|
||||
[LawfulIteratorLoop α Id m] {it : Iter (α := α) β} {f : β → m β'} {p : β' → Bool} :
|
||||
(it.mapM f).all p = (it.mapM pure).allM (fun x => (.up <| p ·) <$> (f x)) := by
|
||||
simp [IterM.all_eq_allM, allM_mapM]
|
||||
|
||||
theorem Iter.all_filterM {α β : Type w} {m : Type w → Type w'}
|
||||
[Iterator α Id β] [Finite α Id] [Monad m] [IteratorLoop α Id m]
|
||||
[LawfulMonad m] [LawfulIteratorLoop α Id m]
|
||||
[Iterator α Id β] [Finite α Id] [IteratorLoop α Id m]
|
||||
[Monad m] [MonadAttach m] [LawfulMonad m] [WeaklyLawfulMonadAttach m] [LawfulIteratorLoop α Id m]
|
||||
{it : Iter (α := α) β} {f : β → m (ULift Bool)} {p : β → Bool} :
|
||||
(it.filterM f).all p = (it.mapM (pure (f := m))).allM (fun x => do
|
||||
if (← f x).down then
|
||||
@@ -791,4 +1044,4 @@ theorem Iter.all_map {α β β' : Type w}
|
||||
· simp [ihs ‹_›]
|
||||
· simp
|
||||
|
||||
end Std.Iterators
|
||||
end Std
|
||||
|
||||
@@ -10,48 +10,59 @@ import Init.Data.Iterators.Lemmas.Combinators.FilterMap
|
||||
public import Init.Data.Iterators.Combinators.FlatMap
|
||||
import all Init.Data.Iterators.Combinators.FlatMap
|
||||
public import Init.Data.Iterators.Lemmas.Combinators.Monadic.FlatMap
|
||||
import Init.Control.Lawful.MonadAttach.Lemmas
|
||||
|
||||
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 γ]
|
||||
{γ : Type w} {m : Type w → Type w'}
|
||||
[Monad m] [MonadAttach m] [LawfulMonad m] [WeaklyLawfulMonadAttach m] [Iterator α Id β]
|
||||
[Iterator α₂ m γ]
|
||||
{f : β → m (IterM (α := α₂) m γ)} {it₁ it₁' : Iter (α := α) β} {it₂' b}
|
||||
(h : it₁.IsPlausibleStep (.yield it₁' b)) :
|
||||
(h : it₁.IsPlausibleStep (.yield it₁' b)) (h' : MonadAttach.CanReturn (f b) it₂') :
|
||||
(it₁.flatMapAfterM f none).IsPlausibleStep (.skip (it₁'.flatMapAfterM f (some it₂'))) := by
|
||||
apply outerYield_flatMapM
|
||||
exact .yieldSome h (out' := b) (by simp [PostconditionT.lift, PostconditionT.bind])
|
||||
apply outerYield_flatMapM (b := b)
|
||||
· exact FilterMap.PlausibleStep.yieldSome h (by simp)
|
||||
· exact h'
|
||||
|
||||
public theorem Flatten.IsPlausibleStep.outerSkip_flatMapM_pure {α : Type w} {β : Type w} {α₂ : Type w}
|
||||
{γ : Type w} {m : Type w → Type w'} [Monad m] [LawfulMonad m] [Iterator α Id β] [Iterator α₂ m γ]
|
||||
{γ : Type w} {m : Type w → Type w'}
|
||||
[Monad m] [MonadAttach m] [LawfulMonad m] [Iterator α Id β] [Iterator α₂ m γ]
|
||||
{f : β → m (IterM (α := α₂) m γ)} {it₁ it₁' : Iter (α := α) β}
|
||||
(h : it₁.IsPlausibleStep (.skip it₁')) :
|
||||
(it₁.flatMapAfterM f none).IsPlausibleStep (.skip (it₁'.flatMapAfterM f none)) :=
|
||||
outerSkip_flatMapM (.skip h)
|
||||
|
||||
public theorem Flatten.IsPlausibleStep.outerDone_flatMapM_pure {α : Type w} {β : Type w} {α₂ : Type w}
|
||||
{γ : Type w} {m : Type w → Type w'} [Monad m] [LawfulMonad m] [Iterator α Id β] [Iterator α₂ m γ]
|
||||
{γ : Type w} {m : Type w → Type w'}
|
||||
[Monad m] [MonadAttach m] [LawfulMonad m] [Iterator α Id β] [Iterator α₂ m γ]
|
||||
{f : β → m (IterM (α := α₂) m γ)} {it₁ : Iter (α := α) β}
|
||||
(h : it₁.IsPlausibleStep .done) :
|
||||
(it₁.flatMapAfterM f none).IsPlausibleStep .done :=
|
||||
outerDone_flatMapM (.done h)
|
||||
|
||||
public theorem Flatten.IsPlausibleStep.innerYield_flatMapM_pure {α : Type w} {β : Type w} {α₂ : Type w}
|
||||
{γ : Type w} {m : Type w → Type w'} [Monad m] [LawfulMonad m] [Iterator α Id β] [Iterator α₂ m γ]
|
||||
{γ : Type w} {m : Type w → Type w'}
|
||||
[Monad m] [MonadAttach m] [LawfulMonad m] [Iterator α Id β] [Iterator α₂ m γ]
|
||||
{f : β → m (IterM (α := α₂) m γ)} {it₁ : Iter (α := α) β} {it₂ it₂' b}
|
||||
(h : it₂.IsPlausibleStep (.yield it₂' b)) :
|
||||
(it₁.flatMapAfterM f (some it₂)).IsPlausibleStep (.yield (it₁.flatMapAfterM f (some it₂')) b) :=
|
||||
innerYield_flatMapM h
|
||||
|
||||
public theorem Flatten.IsPlausibleStep.innerSkip_flatMapM_pure {α : Type w} {β : Type w} {α₂ : Type w}
|
||||
{γ : Type w} {m : Type w → Type w'} [Monad m] [LawfulMonad m] [Iterator α Id β] [Iterator α₂ m γ]
|
||||
{γ : Type w} {m : Type w → Type w'}
|
||||
[Monad m] [MonadAttach m] [LawfulMonad m] [Iterator α Id β] [Iterator α₂ m γ]
|
||||
{f : β → m (IterM (α := α₂) m γ)} {it₁ : Iter (α := α) β} {it₂ it₂'}
|
||||
(h : it₂.IsPlausibleStep (.skip it₂')) :
|
||||
(it₁.flatMapAfterM f (some it₂)).IsPlausibleStep (.skip (it₁.flatMapAfterM f (some it₂'))) :=
|
||||
innerSkip_flatMapM h
|
||||
|
||||
public theorem Flatten.IsPlausibleStep.innerDone_flatMapM_pure {α : Type w} {β : Type w} {α₂ : Type w}
|
||||
{γ : Type w} {m : Type w → Type w'} [Monad m] [LawfulMonad m] [Iterator α Id β] [Iterator α₂ m γ]
|
||||
{γ : Type w} {m : Type w → Type w'}
|
||||
[Monad m] [MonadAttach m] [LawfulMonad m] [Iterator α Id β] [Iterator α₂ m γ]
|
||||
{f : β → m (IterM (α := α₂) m γ)} {it₁ : Iter (α := α) β} {it₂}
|
||||
(h : it₂.IsPlausibleStep .done) :
|
||||
(it₁.flatMapAfterM f (some it₂)).IsPlausibleStep (.skip (it₁.flatMapAfterM f none)) :=
|
||||
@@ -99,15 +110,19 @@ 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 γ]
|
||||
{γ : Type w} {m : Type w → Type w'}
|
||||
[Monad m] [MonadAttach m] [LawfulMonad m] [WeaklyLawfulMonadAttach m] [Iterator α Id β] [Iterator α₂ m γ]
|
||||
{f : β → m (IterM (α := α₂) m γ)} {it₁ : Iter (α := α) β} {it₂ : Option (IterM (α := α₂) m γ)} :
|
||||
(it₁.flatMapAfterM f it₂).step = (do
|
||||
match it₂ with
|
||||
| none =>
|
||||
match it₁.step with
|
||||
| .yield it₁' b h =>
|
||||
return .deflate (.skip (it₁'.flatMapAfterM f (some (← f b))) (.outerYield_flatMapM_pure h))
|
||||
let fx ← MonadAttach.attach (f b)
|
||||
return .deflate (.skip (it₁'.flatMapAfterM f (some fx.val)) (.outerYield_flatMapM_pure h fx.property))
|
||||
| .skip it₁' h => return .deflate (.skip (it₁'.flatMapAfterM f none) (.outerSkip_flatMapM_pure h))
|
||||
| .done h => return .deflate (.done (.outerDone_flatMapM_pure h))
|
||||
| some it₂ =>
|
||||
@@ -118,18 +133,22 @@ public theorem Iter.step_flatMapAfterM {α : Type w} {β : Type w} {α₂ : Type
|
||||
return .deflate (.skip (it₁.flatMapAfterM f (some it₂')) (.innerSkip_flatMapM_pure h))
|
||||
| .done h =>
|
||||
return .deflate (.skip (it₁.flatMapAfterM f none) (.innerDone_flatMapM_pure h))) := by
|
||||
simp only [flatMapAfterM, IterM.step_flatMapAfterM, Iter.step_mapM]
|
||||
simp only [flatMapAfterM, IterM.step_flatMapAfterM, Iter.step_mapWithPostcondition,
|
||||
PostconditionT.operation_pure]
|
||||
split
|
||||
· split <;> simp [*]
|
||||
· rfl
|
||||
|
||||
public theorem Iter.step_flatMapM {α : Type w} {β : Type w} {α₂ : Type w}
|
||||
{γ : Type w} {m : Type w → Type w'} [Monad m] [LawfulMonad m] [Iterator α Id β] [Iterator α₂ m γ]
|
||||
{γ : Type w} {m : Type w → Type w'}
|
||||
[Monad m] [MonadAttach m] [LawfulMonad m] [WeaklyLawfulMonadAttach m]
|
||||
[Iterator α Id β] [Iterator α₂ m γ]
|
||||
{f : β → m (IterM (α := α₂) m γ)} {it₁ : Iter (α := α) β} :
|
||||
(it₁.flatMapM f).step = (do
|
||||
match it₁.step with
|
||||
| .yield it₁' b h =>
|
||||
return .deflate (.skip (it₁'.flatMapAfterM f (some (← f b))) (.outerYield_flatMapM_pure h))
|
||||
let fx ← MonadAttach.attach (f b)
|
||||
return .deflate (.skip (it₁'.flatMapAfterM f (some fx.val)) (.outerYield_flatMapM_pure h fx.property))
|
||||
| .skip it₁' h => return .deflate (.skip (it₁'.flatMapAfterM f none) (.outerSkip_flatMapM_pure h))
|
||||
| .done h => return .deflate (.done (.outerDone_flatMapM_pure h))) := by
|
||||
simp [flatMapM, step_flatMapAfterM]
|
||||
@@ -167,10 +186,9 @@ public theorem Iter.step_flatMap {α : Type w} {β : Type w} {α₂ : Type w}
|
||||
| .done h => .done (.outerDone_flatMap_pure h)) := by
|
||||
simp [flatMap, step_flatMapAfter]
|
||||
|
||||
public theorem Iter.toList_flatMapAfterM {α α₂ β γ : Type w} {m : Type w → Type w'} [Monad m]
|
||||
[LawfulMonad m] [Iterator α Id β] [Iterator α₂ m γ] [Finite α Id] [Finite α₂ m]
|
||||
[IteratorCollect α Id m] [IteratorCollect α₂ m m]
|
||||
[LawfulIteratorCollect α Id m] [LawfulIteratorCollect α₂ m m]
|
||||
public theorem Iter.toList_flatMapAfterM {α α₂ β γ : Type w} {m : Type w → Type w'}
|
||||
[Monad m] [MonadAttach m] [LawfulMonad m] [WeaklyLawfulMonadAttach m]
|
||||
[Iterator α Id β] [Iterator α₂ m γ] [Finite α Id] [Finite α₂ m]
|
||||
{f : β → m (IterM (α := α₂) m γ)}
|
||||
{it₁ : Iter (α := α) β} {it₂ : Option (IterM (α := α₂) m γ)} :
|
||||
(it₁.flatMapAfterM f it₂).toList = do
|
||||
@@ -179,17 +197,11 @@ public theorem Iter.toList_flatMapAfterM {α α₂ β γ : Type w} {m : Type w
|
||||
| some it₂ => return (← it₂.toList) ++
|
||||
(← List.flatten <$> (it₁.mapM fun b => do (← f b).toList).toList) := by
|
||||
simp only [flatMapAfterM, IterM.toList_flatMapAfterM]
|
||||
split
|
||||
· simp only [mapM, IterM.toList_mapM_mapM, monadLift_self]
|
||||
congr <;> simp
|
||||
· apply bind_congr; intro step
|
||||
simp only [mapM, IterM.toList_mapM_mapM, monadLift_self, bind_pure_comp, Functor.map_map]
|
||||
congr <;> simp
|
||||
split <;> simp [IterM.toList_mapM_eq_toList_mapWithPostcondition]
|
||||
|
||||
public theorem Iter.toArray_flatMapAfterM {α α₂ β γ : Type w} {m : Type w → Type w'} [Monad m]
|
||||
[LawfulMonad m] [Iterator α Id β] [Iterator α₂ m γ] [Finite α Id] [Finite α₂ m]
|
||||
[IteratorCollect α Id m] [IteratorCollect α₂ m m]
|
||||
[LawfulIteratorCollect α Id m] [LawfulIteratorCollect α₂ m m]
|
||||
public theorem Iter.toArray_flatMapAfterM {α α₂ β γ : Type w} {m : Type w → Type w'}
|
||||
[Monad m] [MonadAttach m] [LawfulMonad m] [WeaklyLawfulMonadAttach m]
|
||||
[Iterator α Id β] [Iterator α₂ m γ] [Finite α Id] [Finite α₂ m]
|
||||
{f : β → m (IterM (α := α₂) m γ)}
|
||||
{it₁ : Iter (α := α) β} {it₂ : Option (IterM (α := α₂) m γ)} :
|
||||
(it₁.flatMapAfterM f it₂).toArray = do
|
||||
@@ -198,58 +210,47 @@ public theorem Iter.toArray_flatMapAfterM {α α₂ β γ : Type w} {m : Type w
|
||||
| some it₂ => return (← it₂.toArray) ++
|
||||
(← Array.flatten <$> (it₁.mapM fun b => do (← f b).toArray).toArray) := by
|
||||
simp only [flatMapAfterM, IterM.toArray_flatMapAfterM]
|
||||
split
|
||||
· simp only [mapM, IterM.toArray_mapM_mapM, monadLift_self]
|
||||
congr <;> simp
|
||||
· apply bind_congr; intro step
|
||||
simp only [mapM, IterM.toArray_mapM_mapM, monadLift_self, bind_pure_comp, Functor.map_map]
|
||||
congr <;> simp
|
||||
split <;> simp [IterM.toArray_mapM_eq_toArray_mapWithPostcondition]
|
||||
|
||||
public theorem Iter.toList_flatMapM {α α₂ β γ : Type w} {m : Type w → Type w'} [Monad m]
|
||||
[LawfulMonad m] [Iterator α Id β] [Iterator α₂ m γ] [Finite α Id] [Finite α₂ m]
|
||||
[IteratorCollect α Id m] [IteratorCollect α₂ m m]
|
||||
[LawfulIteratorCollect α Id m] [LawfulIteratorCollect α₂ m m]
|
||||
public theorem Iter.toList_flatMapM {α α₂ β γ : Type w} {m : Type w → Type w'}
|
||||
[Monad m] [MonadAttach m] [LawfulMonad m] [WeaklyLawfulMonadAttach m]
|
||||
[Iterator α Id β] [Iterator α₂ m γ] [Finite α Id] [Finite α₂ m]
|
||||
{f : β → m (IterM (α := α₂) m γ)}
|
||||
{it₁ : Iter (α := α) β} :
|
||||
(it₁.flatMapM f).toList = List.flatten <$> (it₁.mapM fun b => do (← f b).toList).toList := by
|
||||
simp [flatMapM, toList_flatMapAfterM]
|
||||
|
||||
public theorem Iter.toArray_flatMapM {α α₂ β γ : Type w} {m : Type w → Type w'} [Monad m]
|
||||
[LawfulMonad m] [Iterator α Id β] [Iterator α₂ m γ] [Finite α Id] [Finite α₂ m]
|
||||
[IteratorCollect α Id m] [IteratorCollect α₂ m m]
|
||||
[LawfulIteratorCollect α Id m] [LawfulIteratorCollect α₂ m m]
|
||||
public theorem Iter.toArray_flatMapM {α α₂ β γ : Type w} {m : Type w → Type w'}
|
||||
[Monad m] [MonadAttach m] [LawfulMonad m] [WeaklyLawfulMonadAttach m]
|
||||
[Iterator α Id β] [Iterator α₂ m γ] [Finite α Id] [Finite α₂ m]
|
||||
{f : β → m (IterM (α := α₂) m γ)}
|
||||
{it₁ : Iter (α := α) β} :
|
||||
(it₁.flatMapM f).toArray = Array.flatten <$> (it₁.mapM fun b => do (← f b).toArray).toArray := by
|
||||
simp [flatMapM, toArray_flatMapAfterM]
|
||||
|
||||
public theorem Iter.toList_flatMapAfter {α α₂ β γ : Type w} [Iterator α Id β] [Iterator α₂ Id γ]
|
||||
[Finite α Id] [Finite α₂ Id] [IteratorCollect α Id Id] [IteratorCollect α₂ Id Id]
|
||||
[LawfulIteratorCollect α Id Id] [LawfulIteratorCollect α₂ Id Id]
|
||||
[Finite α Id] [Finite α₂ Id]
|
||||
{f : β → Iter (α := α₂) γ} {it₁ : Iter (α := α) β} {it₂ : Option (Iter (α := α₂) γ)} :
|
||||
(it₁.flatMapAfter f it₂).toList = match it₂ with
|
||||
| none => (it₁.map fun b => (f b).toList).toList.flatten
|
||||
| some it₂ => it₂.toList ++
|
||||
(it₁.map fun b => (f b).toList).toList.flatten := by
|
||||
simp only [flatMapAfter, Iter.toList, toIterM_toIter, IterM.toList_flatMapAfter]
|
||||
cases it₂ <;> simp [map, IterM.toList_map_eq_toList_mapM]
|
||||
cases it₂ <;> simp [map, IterM.toList_map_eq_toList_mapM, - IterM.toList_map]
|
||||
|
||||
public theorem Iter.toArray_flatMapAfter {α α₂ β γ : Type w} [Iterator α Id β] [Iterator α₂ Id γ]
|
||||
[Finite α Id] [Finite α₂ Id] [IteratorCollect α Id Id] [IteratorCollect α₂ Id Id]
|
||||
[LawfulIteratorCollect α Id Id] [LawfulIteratorCollect α₂ Id Id]
|
||||
[Finite α Id] [Finite α₂ Id]
|
||||
{f : β → Iter (α := α₂) γ} {it₁ : Iter (α := α) β} {it₂ : Option (Iter (α := α₂) γ)} :
|
||||
(it₁.flatMapAfter f it₂).toArray = match it₂ with
|
||||
| none => (it₁.map fun b => (f b).toArray).toArray.flatten
|
||||
| some it₂ => it₂.toArray ++
|
||||
(it₁.map fun b => (f b).toArray).toArray.flatten := by
|
||||
simp only [flatMapAfter, Iter.toArray, toIterM_toIter, IterM.toArray_flatMapAfter]
|
||||
cases it₂ <;> simp [map, IterM.toArray_map_eq_toArray_mapM]
|
||||
cases it₂ <;> simp [map, IterM.toArray_map_eq_toArray_mapM, - IterM.toArray_map]
|
||||
|
||||
public theorem Iter.toList_flatMap {α α₂ β γ : Type w} [Iterator α Id β] [Iterator α₂ Id γ]
|
||||
[Finite α Id] [Finite α₂ Id]
|
||||
[Iterator α Id β] [Iterator α₂ Id γ] [Finite α Id] [Finite α₂ Id]
|
||||
[IteratorCollect α Id Id] [IteratorCollect α₂ Id Id]
|
||||
[LawfulIteratorCollect α Id Id] [LawfulIteratorCollect α₂ Id Id]
|
||||
{f : β → Iter (α := α₂) γ} {it₁ : Iter (α := α) β} :
|
||||
(it₁.flatMap f).toList = (it₁.map fun b => (f b).toList).toList.flatten := by
|
||||
simp [flatMap, toList_flatMapAfter]
|
||||
@@ -257,10 +258,8 @@ public theorem Iter.toList_flatMap {α α₂ β γ : Type w} [Iterator α Id β]
|
||||
public theorem Iter.toArray_flatMap {α α₂ β γ : Type w} [Iterator α Id β] [Iterator α₂ Id γ]
|
||||
[Finite α Id] [Finite α₂ Id]
|
||||
[Iterator α Id β] [Iterator α₂ Id γ] [Finite α Id] [Finite α₂ Id]
|
||||
[IteratorCollect α Id Id] [IteratorCollect α₂ Id Id]
|
||||
[LawfulIteratorCollect α Id Id] [LawfulIteratorCollect α₂ Id Id]
|
||||
{f : β → Iter (α := α₂) γ} {it₁ : Iter (α := α) β} :
|
||||
(it₁.flatMap f).toArray = (it₁.map fun b => (f b).toArray).toArray.flatten := by
|
||||
simp [flatMap, toArray_flatMapAfter]
|
||||
|
||||
end Std.Iterators
|
||||
end Std
|
||||
|
||||
@@ -13,20 +13,20 @@ 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]
|
||||
theorem IterM.map_unattach_toList_attachWith [Iterator α m β] [Monad m]
|
||||
{it : IterM (α := α) m β} {hP}
|
||||
[Finite α m] [IteratorCollect α m m]
|
||||
[LawfulMonad m] [LawfulIteratorCollect α m m] :
|
||||
[Finite α m] [LawfulMonad m] :
|
||||
List.unattach <$> (it.attachWith P hP).toList = it.toList := by
|
||||
induction it using IterM.inductSteps with | step it ihy ihs
|
||||
rw [IterM.toList_eq_match_step, IterM.toList_eq_match_step, step_attachWith]
|
||||
@@ -45,8 +45,7 @@ theorem IterM.map_unattach_toList_attachWith [Iterator α m β] [Monad m]
|
||||
@[simp]
|
||||
theorem IterM.map_unattach_toListRev_attachWith [Iterator α m β] [Monad m] [Monad n]
|
||||
{it : IterM (α := α) m β} {hP}
|
||||
[Finite α m] [IteratorCollect α m m]
|
||||
[LawfulMonad m] [LawfulIteratorCollect α m m] :
|
||||
[Finite α m] [LawfulMonad m] :
|
||||
List.unattach <$> (it.attachWith P hP).toListRev = it.toListRev := by
|
||||
rw [toListRev_eq, toListRev_eq, ← map_unattach_toList_attachWith (it := it) (hP := hP)]
|
||||
simp [-map_unattach_toList_attachWith]
|
||||
@@ -54,8 +53,8 @@ theorem IterM.map_unattach_toListRev_attachWith [Iterator α m β] [Monad m] [Mo
|
||||
@[simp]
|
||||
theorem IterM.map_unattach_toArray_attachWith [Iterator α m β] [Monad m] [Monad n]
|
||||
{it : IterM (α := α) m β} {hP}
|
||||
[Finite α m] [IteratorCollect α m m]
|
||||
[LawfulMonad m] [LawfulIteratorCollect α m m] :
|
||||
[Finite α m]
|
||||
[LawfulMonad m] :
|
||||
(·.map Subtype.val) <$> (it.attachWith P hP).toArray = it.toArray := by
|
||||
rw [← toArray_toList, ← toArray_toList, ← map_unattach_toList_attachWith (it := it) (hP := hP)]
|
||||
simp [-map_unattach_toList_attachWith, -IterM.toArray_toList]
|
||||
@@ -65,9 +64,8 @@ theorem IterM.count_attachWith [Iterator α m β] [Monad m] [Monad n]
|
||||
{it : IterM (α := α) m β} {hP}
|
||||
[Finite α m] [IteratorLoop α m m] [LawfulMonad m] [LawfulIteratorLoop α m m] :
|
||||
(it.attachWith P hP).count = it.count := by
|
||||
letI : IteratorCollect α m m := .defaultImplementation
|
||||
rw [← up_length_toList_eq_count, ← up_length_toList_eq_count,
|
||||
← map_unattach_toList_attachWith (it := it) (P := P) (hP := hP)]
|
||||
simp only [Functor.map_map, List.length_unattach]
|
||||
|
||||
end Std.Iterators
|
||||
end Std
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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,46 +32,48 @@ 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 γ]
|
||||
{γ : Type w} {m : Type w → Type w'} [Monad m] [MonadAttach m] [LawfulMonad m] [Iterator α m β] [Iterator α₂ m γ]
|
||||
{f : β → m (IterM (α := α₂) m γ)} {it₁ it₁' : IterM (α := α) m β} {it₂' b}
|
||||
(h : it₁.IsPlausibleStep (.yield it₁' b)) :
|
||||
(h : it₁.IsPlausibleStep (.yield it₁' b)) (h' : MonadAttach.CanReturn (f b) it₂') :
|
||||
(it₁.flatMapAfterM f none).IsPlausibleStep (.skip (it₁'.flatMapAfterM f (some it₂'))) :=
|
||||
.outerYield (.yieldSome h ⟨⟨_, trivial⟩, rfl⟩)
|
||||
.outerYield (.yieldSome h ⟨⟨_, h'⟩, rfl⟩)
|
||||
|
||||
public theorem Flatten.IsPlausibleStep.outerSkip_flatMapM {α : 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₁ it₁' : IterM (α := α) m β}
|
||||
{γ : Type w} {m : Type w → Type w'} [Monad m] [MonadAttach m] [LawfulMonad m] [Iterator α m β]
|
||||
[Iterator α₂ m γ] {f : β → m (IterM (α := α₂) m γ)} {it₁ it₁' : IterM (α := α) m β}
|
||||
(h : it₁.IsPlausibleStep (.skip it₁')) :
|
||||
(it₁.flatMapAfterM f none).IsPlausibleStep (.skip (it₁'.flatMapAfterM f none)) :=
|
||||
.outerSkip (.skip h)
|
||||
|
||||
public theorem Flatten.IsPlausibleStep.outerDone_flatMapM {α : 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 β}
|
||||
{γ : Type w} {m : Type w → Type w'} [Monad m] [MonadAttach m] [LawfulMonad m] [Iterator α m β]
|
||||
[Iterator α₂ m γ] {f : β → m (IterM (α := α₂) m γ)} {it₁ : IterM (α := α) m β}
|
||||
(h : it₁.IsPlausibleStep .done) :
|
||||
(it₁.flatMapAfterM f none).IsPlausibleStep .done :=
|
||||
.outerDone (.done h)
|
||||
|
||||
public theorem Flatten.IsPlausibleStep.innerYield_flatMapM {α : 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₂ it₂' b}
|
||||
{γ : Type w} {m : Type w → Type w'} [Monad m] [MonadAttach m] [LawfulMonad m] [Iterator α m β]
|
||||
[Iterator α₂ m γ] {f : β → m (IterM (α := α₂) m γ)} {it₁ : IterM (α := α) m β} {it₂ it₂' b}
|
||||
(h : it₂.IsPlausibleStep (.yield it₂' b)) :
|
||||
(it₁.flatMapAfterM f (some it₂)).IsPlausibleStep (.yield (it₁.flatMapAfterM f (some it₂')) b) :=
|
||||
.innerYield h
|
||||
|
||||
public theorem Flatten.IsPlausibleStep.innerSkip_flatMapM {α : 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₂ it₂'}
|
||||
{γ : Type w} {m : Type w → Type w'} [Monad m] [MonadAttach m] [LawfulMonad m] [Iterator α m β]
|
||||
[Iterator α₂ m γ] {f : β → m (IterM (α := α₂) m γ)} {it₁ : IterM (α := α) m β} {it₂ it₂'}
|
||||
(h : it₂.IsPlausibleStep (.skip it₂')) :
|
||||
(it₁.flatMapAfterM f (some it₂)).IsPlausibleStep (.skip (it₁.flatMapAfterM f (some it₂'))) :=
|
||||
.innerSkip h
|
||||
|
||||
public theorem Flatten.IsPlausibleStep.innerDone_flatMapM {α : 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₂}
|
||||
{γ : Type w} {m : Type w → Type w'} [Monad m] [MonadAttach m] [LawfulMonad m] [Iterator α m β]
|
||||
[Iterator α₂ m γ] {f : β → m (IterM (α := α₂) m γ)} {it₁ : IterM (α := α) m β} {it₂}
|
||||
(h : it₂.IsPlausibleStep .done) :
|
||||
(it₁.flatMapAfterM f (some it₂)).IsPlausibleStep (.skip (it₁.flatMapAfterM f none)) :=
|
||||
.innerDone h
|
||||
@@ -118,15 +120,19 @@ 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 γ)} :
|
||||
{γ : Type w} {m : Type w → Type w'} [Monad m] [MonadAttach m] [LawfulMonad m] [WeaklyLawfulMonadAttach m]
|
||||
[Iterator α m β] [Iterator α₂ m γ] {f : β → m (IterM (α := α₂) m γ)} {it₁ : IterM (α := α) m β}
|
||||
{it₂ : Option (IterM (α := α₂) m γ)} :
|
||||
(it₁.flatMapAfterM f it₂).step = (do
|
||||
match it₂ with
|
||||
| none =>
|
||||
match (← it₁.step).inflate with
|
||||
| .yield it₁' b h =>
|
||||
return .deflate (.skip (it₁'.flatMapAfterM f (some (← f b))) (.outerYield_flatMapM h))
|
||||
let fx ← MonadAttach.attach (f b)
|
||||
return .deflate (.skip (it₁'.flatMapAfterM f (some fx.val)) (.outerYield_flatMapM h fx.property))
|
||||
| .skip it₁' h => return .deflate (.skip (it₁'.flatMapAfterM f none) (.outerSkip_flatMapM h))
|
||||
| .done h => return .deflate (.done (.outerDone_flatMapM h))
|
||||
| some it₂ =>
|
||||
@@ -138,17 +144,22 @@ public theorem IterM.step_flatMapAfterM {α : Type w} {β : Type w} {α₂ : Typ
|
||||
split
|
||||
· simp only [bind_assoc]
|
||||
apply bind_congr; intro step
|
||||
cases step.inflate using PlausibleIterStep.casesOn <;> simp
|
||||
cases step.inflate using PlausibleIterStep.casesOn
|
||||
· simp only [bind_pure_comp, bind_map_left, Shrink.inflate_deflate]
|
||||
· simp
|
||||
· simp
|
||||
· rfl
|
||||
|
||||
public theorem IterM.step_flatMapM {α : 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 β} :
|
||||
{γ : Type w} {m : Type w → Type w'} [Monad m] [MonadAttach m] [LawfulMonad m]
|
||||
[WeaklyLawfulMonadAttach m] [Iterator α m β] [Iterator α₂ m γ] {f : β → m (IterM (α := α₂) m γ)}
|
||||
{it₁ : IterM (α := α) m β} :
|
||||
(it₁.flatMapM f).step = (do
|
||||
match (← it₁.step).inflate with
|
||||
| .yield it₁' b h =>
|
||||
return .deflate (.skip (it₁'.flatMapAfterM f (some (← f b)))
|
||||
(.outerYield_flatMapM h))
|
||||
let fx ← MonadAttach.attach (f b)
|
||||
return .deflate (.skip (it₁'.flatMapAfterM f (some fx.val))
|
||||
(.outerYield_flatMapM h fx.property))
|
||||
| .skip it₁' h => return .deflate (.skip (it₁'.flatMapAfterM f none) (.outerSkip_flatMapM h))
|
||||
| .done h => return .deflate (.done (.outerDone_flatMapM h))) := by
|
||||
simp [flatMapM, step_flatMapAfterM]
|
||||
@@ -187,10 +198,9 @@ public theorem IterM.step_flatMap {α : Type w} {β : Type w} {α₂ : Type w}
|
||||
| .done h => return .deflate (.done (.outerDone_flatMap h))) := by
|
||||
simp [flatMap, step_flatMapAfter]
|
||||
|
||||
theorem IterM.toList_flattenAfter {α α₂ β : Type w} {m : Type w → Type w'} [Monad m] [LawfulMonad m]
|
||||
theorem IterM.toList_flattenAfter {α α₂ β : Type w} {m : Type w → Type w'}
|
||||
[Monad m] [MonadAttach m] [LawfulMonad m] [WeaklyLawfulMonadAttach m]
|
||||
[Iterator α m (IterM (α := α₂) m β)] [Iterator α₂ m β] [Finite α m] [Finite α₂ m]
|
||||
[IteratorCollect α m m] [IteratorCollect α₂ m m]
|
||||
[LawfulIteratorCollect α m m] [LawfulIteratorCollect α₂ m m]
|
||||
{it₁ : IterM (α := α) m (IterM (α := α₂) m β)} {it₂ : Option (IterM (α := α₂) m β)} :
|
||||
(it₁.flattenAfter it₂).toList = do
|
||||
match it₂ with
|
||||
@@ -203,7 +213,10 @@ theorem IterM.toList_flattenAfter {α α₂ β : Type w} {m : Type w → Type w'
|
||||
simp only [bind_assoc, map_eq_pure_bind]
|
||||
apply bind_congr; intro step
|
||||
cases step.inflate using PlausibleIterStep.casesOn
|
||||
· simp [ihy₁ ‹_›]
|
||||
· simp only [bind_pure_comp, pure_bind, Shrink.inflate_deflate,
|
||||
bind_map_left, Functor.map_map, List.flatten_cons, ihy₁ ‹_›]
|
||||
conv => lhs; rw [← WeaklyLawfulMonadAttach.map_attach (x := IterM.toList _)]
|
||||
simp
|
||||
· simp [ihs₁ ‹_›]
|
||||
· simp
|
||||
cases it₂
|
||||
@@ -219,42 +232,31 @@ theorem IterM.toList_flattenAfter {α α₂ β : Type w} {m : Type w → Type w'
|
||||
· simp [ihs₂ ‹_›]
|
||||
· simp [hn]
|
||||
|
||||
theorem IterM.toArray_flattenAfter {α α₂ β : Type w} {m : Type w → Type w'} [Monad m] [LawfulMonad m]
|
||||
theorem IterM.toArray_flattenAfter {α α₂ β : Type w} {m : Type w → Type w'}
|
||||
[Monad m] [MonadAttach m] [LawfulMonad m] [WeaklyLawfulMonadAttach m]
|
||||
[Iterator α m (IterM (α := α₂) m β)] [Iterator α₂ m β] [Finite α m] [Finite α₂ m]
|
||||
[IteratorCollect α m m] [IteratorCollect α₂ m m]
|
||||
[LawfulIteratorCollect α m m] [LawfulIteratorCollect α₂ m m]
|
||||
{it₁ : IterM (α := α) m (IterM (α := α₂) m β)} {it₂ : Option (IterM (α := α₂) m β)} :
|
||||
(it₁.flattenAfter it₂).toArray = do
|
||||
match it₂ with
|
||||
| none => Array.flatten <$> (it₁.mapM fun it₂ => it₂.toArray).toArray
|
||||
| some it₂ => return (← it₂.toArray) ++ (← Array.flatten <$> (it₁.mapM fun it₂ => it₂.toArray).toArray) := by
|
||||
induction it₁ using IterM.inductSteps generalizing it₂ with | step it₁ ihy₁ ihs₁ =>
|
||||
have hn : (it₁.flattenAfter none).toArray =
|
||||
Array.flatten <$> (it₁.mapM fun it₂ => it₂.toArray).toArray := by
|
||||
rw [toArray_eq_match_step, toArray_eq_match_step, step_flattenAfter, step_mapM]
|
||||
simp only [bind_assoc, map_eq_pure_bind]
|
||||
apply bind_congr; intro step
|
||||
cases step.inflate using PlausibleIterStep.casesOn
|
||||
· simp [ihy₁ ‹_›]
|
||||
· simp [ihs₁ ‹_›]
|
||||
· simp
|
||||
cases it₂
|
||||
· exact hn
|
||||
· rename_i ih₂
|
||||
induction ih₂ using IterM.inductSteps with | step it₂ ihy₂ ihs₂ =>
|
||||
rw [toArray_eq_match_step, step_flattenAfter, bind_assoc]
|
||||
simp only
|
||||
rw [toArray_eq_match_step, bind_assoc]
|
||||
apply bind_congr; intro step
|
||||
cases step.inflate using PlausibleIterStep.casesOn
|
||||
· simp [ihy₂ ‹_›]
|
||||
· simp [ihs₂ ‹_›]
|
||||
· simp [hn]
|
||||
simp only [← IterM.toArray_toList, toList_flattenAfter]
|
||||
split
|
||||
· simp only [Functor.map_map]
|
||||
simp only [← Array.flatten_map_toArray_toArray, ← Functor.map_map]
|
||||
rw [IterM.toArray_toList, IterM.toArray_toList, ← IterM.toArray_map, IterM.toArray_map_mapM]
|
||||
apply congrArg (it₁.mapM · |>.toArray |> Functor.map Array.flatten); ext it₂
|
||||
simp
|
||||
· simp only [bind_pure_comp, Functor.map_map, map_bind, Array.flatten_toArray, bind_map_left,
|
||||
List.append_toArray]
|
||||
apply bind_congr; intro bs
|
||||
simp only [← Functor.map_map, ← IterM.toList_map, IterM.toList_map_mapM]
|
||||
apply congrArg (fun f => List.toArray <$> HAppend.hAppend bs <$> List.flatten <$> (mapM f it₁).toList)
|
||||
simp
|
||||
|
||||
public theorem IterM.toList_flatMapAfterM {α α₂ β γ : Type w} {m : Type w → Type w'} [Monad m]
|
||||
[LawfulMonad m] [Iterator α m β] [Iterator α₂ m γ] [Finite α m] [Finite α₂ m]
|
||||
[IteratorCollect α m m] [IteratorCollect α₂ m m]
|
||||
[LawfulIteratorCollect α m m] [LawfulIteratorCollect α₂ m m]
|
||||
public theorem IterM.toList_flatMapAfterM {α α₂ β γ : Type w} {m : Type w → Type w'}
|
||||
[Monad m] [MonadAttach m] [LawfulMonad m] [WeaklyLawfulMonadAttach m]
|
||||
[Iterator α m β] [Iterator α₂ m γ] [Finite α m] [Finite α₂ m]
|
||||
{f : β → m (IterM (α := α₂) m γ)}
|
||||
{it₁ : IterM (α := α) m β} {it₂ : Option (IterM (α := α₂) m γ)} :
|
||||
(it₁.flatMapAfterM f it₂).toList = do
|
||||
@@ -264,10 +266,9 @@ public theorem IterM.toList_flatMapAfterM {α α₂ β γ : Type w} {m : Type w
|
||||
(← List.flatten <$> (it₁.mapM fun b => do (← f b).toList).toList) := by
|
||||
simp [flatMapAfterM, toList_flattenAfter]; rfl
|
||||
|
||||
public theorem IterM.toArray_flatMapAfterM {α α₂ β γ : Type w} {m : Type w → Type w'} [Monad m]
|
||||
[LawfulMonad m] [Iterator α m β] [Iterator α₂ m γ] [Finite α m] [Finite α₂ m]
|
||||
[IteratorCollect α m m] [IteratorCollect α₂ m m]
|
||||
[LawfulIteratorCollect α m m] [LawfulIteratorCollect α₂ m m]
|
||||
public theorem IterM.toArray_flatMapAfterM {α α₂ β γ : Type w} {m : Type w → Type w'}
|
||||
[Monad m] [MonadAttach m] [LawfulMonad m] [WeaklyLawfulMonadAttach m]
|
||||
[Iterator α m β] [Iterator α₂ m γ] [Finite α m] [Finite α₂ m]
|
||||
{f : β → m (IterM (α := α₂) m γ)}
|
||||
{it₁ : IterM (α := α) m β} {it₂ : Option (IterM (α := α₂) m γ)} :
|
||||
(it₁.flatMapAfterM f it₂).toArray = do
|
||||
@@ -277,28 +278,25 @@ public theorem IterM.toArray_flatMapAfterM {α α₂ β γ : Type w} {m : Type w
|
||||
(← Array.flatten <$> (it₁.mapM fun b => do (← f b).toArray).toArray) := by
|
||||
simp [flatMapAfterM, toArray_flattenAfter]; rfl
|
||||
|
||||
public theorem IterM.toList_flatMapM {α α₂ β γ : Type w} {m : Type w → Type w'} [Monad m]
|
||||
[LawfulMonad m] [Iterator α m β] [Iterator α₂ m γ] [Finite α m] [Finite α₂ m]
|
||||
[IteratorCollect α m m] [IteratorCollect α₂ m m]
|
||||
[LawfulIteratorCollect α m m] [LawfulIteratorCollect α₂ m m]
|
||||
public theorem IterM.toList_flatMapM {α α₂ β γ : Type w} {m : Type w → Type w'}
|
||||
[Monad m] [MonadAttach m] [LawfulMonad m] [WeaklyLawfulMonadAttach m]
|
||||
[Iterator α m β] [Iterator α₂ m γ] [Finite α m] [Finite α₂ m]
|
||||
{f : β → m (IterM (α := α₂) m γ)}
|
||||
{it₁ : IterM (α := α) m β} :
|
||||
(it₁.flatMapM f).toList = List.flatten <$> (it₁.mapM fun b => do (← f b).toList).toList := by
|
||||
simp [flatMapM, toList_flatMapAfterM]
|
||||
|
||||
public theorem IterM.toArray_flatMapM {α α₂ β γ : Type w} {m : Type w → Type w'} [Monad m]
|
||||
[LawfulMonad m] [Iterator α m β] [Iterator α₂ m γ] [Finite α m] [Finite α₂ m]
|
||||
[IteratorCollect α m m] [IteratorCollect α₂ m m]
|
||||
[LawfulIteratorCollect α m m] [LawfulIteratorCollect α₂ m m]
|
||||
public theorem IterM.toArray_flatMapM {α α₂ β γ : Type w} {m : Type w → Type w'}
|
||||
[Monad m] [MonadAttach m] [LawfulMonad m] [WeaklyLawfulMonadAttach m]
|
||||
[Iterator α m β] [Iterator α₂ m γ] [Finite α m] [Finite α₂ m]
|
||||
{f : β → m (IterM (α := α₂) m γ)}
|
||||
{it₁ : IterM (α := α) m β} :
|
||||
(it₁.flatMapM f).toArray = Array.flatten <$> (it₁.mapM fun b => do (← f b).toArray).toArray := by
|
||||
simp [flatMapM, toArray_flatMapAfterM]
|
||||
|
||||
public theorem IterM.toList_flatMapAfter {α α₂ β γ : Type w} {m : Type w → Type w'} [Monad m]
|
||||
[LawfulMonad m] [Iterator α m β] [Iterator α₂ m γ] [Finite α m] [Finite α₂ m]
|
||||
[IteratorCollect α m m] [IteratorCollect α₂ m m]
|
||||
[LawfulIteratorCollect α m m] [LawfulIteratorCollect α₂ m m]
|
||||
public theorem IterM.toList_flatMapAfter {α α₂ β γ : Type w} {m : Type w → Type w'}
|
||||
[Monad m] [MonadAttach m] [LawfulMonad m] [WeaklyLawfulMonadAttach m]
|
||||
[Iterator α m β] [Iterator α₂ m γ] [Finite α m] [Finite α₂ m]
|
||||
{f : β → IterM (α := α₂) m γ}
|
||||
{it₁ : IterM (α := α) m β} {it₂ : Option (IterM (α := α₂) m γ)} :
|
||||
(it₁.flatMapAfter f it₂).toList = do
|
||||
@@ -308,10 +306,9 @@ public theorem IterM.toList_flatMapAfter {α α₂ β γ : Type w} {m : Type w
|
||||
(← List.flatten <$> (it₁.mapM fun b => (f b).toList).toList) := by
|
||||
simp [flatMapAfter, toList_flattenAfter]; rfl
|
||||
|
||||
public theorem IterM.toArray_flatMapAfter {α α₂ β γ : Type w} {m : Type w → Type w'} [Monad m]
|
||||
[LawfulMonad m] [Iterator α m β] [Iterator α₂ m γ] [Finite α m] [Finite α₂ m]
|
||||
[IteratorCollect α m m] [IteratorCollect α₂ m m]
|
||||
[LawfulIteratorCollect α m m] [LawfulIteratorCollect α₂ m m]
|
||||
public theorem IterM.toArray_flatMapAfter {α α₂ β γ : Type w} {m : Type w → Type w'}
|
||||
[Monad m] [MonadAttach m] [LawfulMonad m] [WeaklyLawfulMonadAttach m]
|
||||
[Iterator α m β] [Iterator α₂ m γ] [Finite α m] [Finite α₂ m]
|
||||
{f : β → IterM (α := α₂) m γ}
|
||||
{it₁ : IterM (α := α) m β} {it₂ : Option (IterM (α := α₂) m γ)} :
|
||||
(it₁.flatMapAfter f it₂).toArray = do
|
||||
@@ -321,24 +318,22 @@ public theorem IterM.toArray_flatMapAfter {α α₂ β γ : Type w} {m : Type w
|
||||
(← Array.flatten <$> (it₁.mapM fun b => (f b).toArray).toArray) := by
|
||||
simp [flatMapAfter, toArray_flattenAfter]; rfl
|
||||
|
||||
public theorem IterM.toList_flatMap {α α₂ β γ : Type w} {m : Type w → Type w'} [Monad m]
|
||||
[LawfulMonad m] [Iterator α m β] [Iterator α₂ m γ] [Finite α m] [Finite α₂ m]
|
||||
public theorem IterM.toList_flatMap {α α₂ β γ : Type w} {m : Type w → Type w'}
|
||||
[Monad m] [MonadAttach m] [LawfulMonad m] [WeaklyLawfulMonadAttach m]
|
||||
[Iterator α m β] [Iterator α₂ m γ] [Finite α m] [Finite α₂ m]
|
||||
[Iterator α m β] [Iterator α₂ m γ] [Finite α m] [Finite α₂ m]
|
||||
[IteratorCollect α m m] [IteratorCollect α₂ m m]
|
||||
[LawfulIteratorCollect α m m] [LawfulIteratorCollect α₂ m m]
|
||||
{f : β → IterM (α := α₂) m γ}
|
||||
{it₁ : IterM (α := α) m β} :
|
||||
(it₁.flatMap f).toList = List.flatten <$> (it₁.mapM fun b => (f b).toList).toList := by
|
||||
simp [flatMap, toList_flatMapAfter]
|
||||
|
||||
public theorem IterM.toArray_flatMap {α α₂ β γ : Type w} {m : Type w → Type w'} [Monad m]
|
||||
[LawfulMonad m] [Iterator α m β] [Iterator α₂ m γ] [Finite α m] [Finite α₂ m]
|
||||
public theorem IterM.toArray_flatMap {α α₂ β γ : Type w} {m : Type w → Type w'}
|
||||
[Monad m] [MonadAttach m] [LawfulMonad m] [WeaklyLawfulMonadAttach m]
|
||||
[Iterator α m β] [Iterator α₂ m γ] [Finite α m] [Finite α₂ m]
|
||||
[Iterator α m β] [Iterator α₂ m γ] [Finite α m] [Finite α₂ m]
|
||||
[IteratorCollect α m m] [IteratorCollect α₂ m m]
|
||||
[LawfulIteratorCollect α m m] [LawfulIteratorCollect α₂ m m]
|
||||
{f : β → IterM (α := α₂) m γ}
|
||||
{it₁ : IterM (α := α) m β} :
|
||||
(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
|
||||
@@ -42,7 +47,6 @@ theorem IterM.step_take {α m β} [Monad m] [Iterator α m β] {n : Nat}
|
||||
|
||||
theorem IterM.toList_take_zero {α m β} [Monad m] [LawfulMonad m] [Iterator α m β]
|
||||
[Finite (Take α m) m]
|
||||
[IteratorCollect (Take α m) m m] [LawfulIteratorCollect (Take α m) m m]
|
||||
{it : IterM (α := α) m β} :
|
||||
(it.take 0).toList = pure [] := by
|
||||
rw [toList_eq_match_step]
|
||||
@@ -62,7 +66,6 @@ theorem IterM.step_toTake {α m β} [Monad m] [Iterator α m β] [Finite α m]
|
||||
|
||||
@[simp]
|
||||
theorem IterM.toList_toTake {α m β} [Monad m] [LawfulMonad m] [Iterator α m β] [Finite α m]
|
||||
[IteratorCollect α m m] [LawfulIteratorCollect α m m]
|
||||
{it : IterM (α := α) m β} :
|
||||
it.toTake.toList = it.toList := by
|
||||
induction it using IterM.inductSteps with | step it ihy ihs
|
||||
@@ -74,4 +77,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}
|
||||
@@ -30,8 +31,8 @@ theorem IterM.step_uLift [Iterator α m β] [Monad n] {it : IterM (α := α) m
|
||||
|
||||
@[simp]
|
||||
theorem IterM.toList_uLift [Iterator α m β] [Monad m] [Monad n] {it : IterM (α := α) m β}
|
||||
[MonadLiftT m (ULiftT n)] [Finite α m] [IteratorCollect α m m]
|
||||
[LawfulMonad m] [LawfulMonad n] [LawfulIteratorCollect α m m]
|
||||
[MonadLiftT m (ULiftT n)] [Finite α m]
|
||||
[LawfulMonad m] [LawfulMonad n]
|
||||
[LawfulMonadLiftT m (ULiftT n)] :
|
||||
(it.uLift n).toList =
|
||||
(fun l => l.down.map ULift.up) <$> (monadLift it.toList : ULiftT n _).run := by
|
||||
@@ -46,8 +47,8 @@ theorem IterM.toList_uLift [Iterator α m β] [Monad m] [Monad n] {it : IterM (
|
||||
|
||||
@[simp]
|
||||
theorem IterM.toListRev_uLift [Iterator α m β] [Monad m] [Monad n] {it : IterM (α := α) m β}
|
||||
[MonadLiftT m (ULiftT n)] [Finite α m] [IteratorCollect α m m]
|
||||
[LawfulMonad m] [LawfulMonad n] [LawfulIteratorCollect α m m]
|
||||
[MonadLiftT m (ULiftT n)] [Finite α m]
|
||||
[LawfulMonad m] [LawfulMonad n]
|
||||
[LawfulMonadLiftT m (ULiftT n)] :
|
||||
(it.uLift n).toListRev =
|
||||
(fun l => l.down.map ULift.up) <$> (monadLift it.toListRev : ULiftT n _).run := by
|
||||
@@ -56,8 +57,8 @@ theorem IterM.toListRev_uLift [Iterator α m β] [Monad m] [Monad n] {it : IterM
|
||||
|
||||
@[simp]
|
||||
theorem IterM.toArray_uLift [Iterator α m β] [Monad m] [Monad n] {it : IterM (α := α) m β}
|
||||
[MonadLiftT m (ULiftT n)] [Finite α m] [IteratorCollect α m m]
|
||||
[LawfulMonad m] [LawfulMonad n] [LawfulIteratorCollect α m m]
|
||||
[MonadLiftT m (ULiftT n)] [Finite α m]
|
||||
[LawfulMonad m] [LawfulMonad n]
|
||||
[LawfulMonadLiftT m (ULiftT n)] :
|
||||
(it.uLift n).toArray =
|
||||
(fun l => l.down.map ULift.up) <$> (monadLift it.toArray : ULiftT n _).run := by
|
||||
@@ -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 (α := α) β} :
|
||||
@@ -62,8 +63,7 @@ theorem Iter.atIdxSlow?_take {α β}
|
||||
|
||||
@[simp]
|
||||
theorem Iter.toList_take_of_finite {α β} [Iterator α Id β] {n : Nat}
|
||||
[Finite α Id] [IteratorCollect α Id Id] [LawfulIteratorCollect α Id Id]
|
||||
{it : Iter (α := α) β} :
|
||||
[Finite α Id] {it : Iter (α := α) β} :
|
||||
(it.take n).toList = it.toList.take n := by
|
||||
induction it using Iter.inductSteps generalizing n with | step it ihy ihs
|
||||
rw [Iter.toList_eq_match_step, Iter.toList_eq_match_step, Iter.step_take]
|
||||
@@ -79,23 +79,19 @@ theorem Iter.toList_take_of_finite {α β} [Iterator α Id β] {n : Nat}
|
||||
|
||||
@[simp]
|
||||
theorem Iter.toListRev_take_of_finite {α β} [Iterator α Id β] {n : Nat}
|
||||
[Finite α Id] [IteratorCollect α Id Id] [LawfulIteratorCollect α Id Id]
|
||||
{it : Iter (α := α) β} :
|
||||
[Finite α Id] {it : Iter (α := α) β} :
|
||||
(it.take n).toListRev = it.toListRev.drop (it.toList.length - n) := by
|
||||
rw [toListRev_eq, toList_take_of_finite, List.reverse_take, toListRev_eq]
|
||||
|
||||
@[simp]
|
||||
theorem Iter.toArray_take_of_finite {α β} [Iterator α Id β] {n : Nat}
|
||||
[Finite α Id] [IteratorCollect α Id Id] [LawfulIteratorCollect α Id Id]
|
||||
{it : Iter (α := α) β} :
|
||||
[Finite α Id] {it : Iter (α := α) β} :
|
||||
(it.take n).toArray = it.toArray.take n := by
|
||||
rw [← toArray_toList, ← toArray_toList, List.take_toArray, toList_take_of_finite]
|
||||
|
||||
@[simp]
|
||||
theorem Iter.toList_take_zero {α β} [Iterator α Id β]
|
||||
[Finite (Take α Id) Id]
|
||||
[IteratorCollect (Take α Id) Id Id] [LawfulIteratorCollect (Take α Id) Id Id]
|
||||
{it : Iter (α := α) β} :
|
||||
[Finite (Take α Id) Id] {it : Iter (α := α) β} :
|
||||
(it.take 0).toList = [] := by
|
||||
rw [toList_eq_match_step]
|
||||
simp [step_take]
|
||||
@@ -112,10 +108,8 @@ theorem Iter.step_toTake {α β} [Iterator α Id β] [Finite α Id]
|
||||
cases it.toIterM.step.run.inflate using PlausibleIterStep.casesOn <;> simp
|
||||
|
||||
@[simp]
|
||||
theorem Iter.toList_toTake {α β} [Iterator α Id β] [Finite α Id]
|
||||
[IteratorCollect α Id Id] [LawfulIteratorCollect α Id Id]
|
||||
{it : Iter (α := α) β} :
|
||||
theorem Iter.toList_toTake {α β} [Iterator α Id β] [Finite α Id] {it : Iter (α := α) β} :
|
||||
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}
|
||||
|
||||
@@ -36,8 +37,7 @@ theorem Iter.step_uLift [Iterator α Id β] {it : Iter (α := α) β} :
|
||||
|
||||
@[simp]
|
||||
theorem Iter.toList_uLift [Iterator α Id β] {it : Iter (α := α) β}
|
||||
[Finite α Id] [IteratorCollect α Id Id]
|
||||
[LawfulIteratorCollect α Id Id] :
|
||||
[Finite α Id] :
|
||||
it.uLift.toList = it.toList.map ULift.up := by
|
||||
simp only [monadLift, uLift_eq_toIter_uLift_toIterM, IterM.toList_toIter]
|
||||
rw [IterM.toList_uLift]
|
||||
@@ -45,15 +45,13 @@ theorem Iter.toList_uLift [Iterator α Id β] {it : Iter (α := α) β}
|
||||
|
||||
@[simp]
|
||||
theorem Iter.toListRev_uLift [Iterator α Id β] {it : Iter (α := α) β}
|
||||
[Finite α Id] [IteratorCollect α Id Id]
|
||||
[LawfulIteratorCollect α Id Id] :
|
||||
[Finite α Id] :
|
||||
it.uLift.toListRev = it.toListRev.map ULift.up := by
|
||||
rw [toListRev_eq, toListRev_eq, toList_uLift, List.map_reverse]
|
||||
|
||||
@[simp]
|
||||
theorem Iter.toArray_uLift [Iterator α Id β] {it : Iter (α := α) β}
|
||||
[Finite α Id] [IteratorCollect α Id Id]
|
||||
[LawfulIteratorCollect α Id Id] :
|
||||
[Finite α Id] :
|
||||
it.uLift.toArray = it.toArray.map ULift.up := by
|
||||
rw [← toArray_toList, ← toArray_toList, toList_uLift]
|
||||
simp [-toArray_toList]
|
||||
@@ -66,4 +64,4 @@ theorem Iter.count_uLift [Iterator α Id β] {it : Iter (α := α) β}
|
||||
rw [IterM.count_uLift]
|
||||
simp [monadLift]
|
||||
|
||||
end Std.Iterators
|
||||
end Std
|
||||
|
||||
@@ -9,3 +9,4 @@ prelude
|
||||
public import Init.Data.Iterators.Lemmas.Consumers.Monadic
|
||||
public import Init.Data.Iterators.Lemmas.Consumers.Collect
|
||||
public import Init.Data.Iterators.Lemmas.Consumers.Loop
|
||||
public import Init.Data.Iterators.Lemmas.Consumers.Access
|
||||
|
||||
26
src/Init/Data/Iterators/Lemmas/Consumers/Access.lean
Normal file
26
src/Init/Data/Iterators/Lemmas/Consumers/Access.lean
Normal file
@@ -0,0 +1,26 @@
|
||||
/-
|
||||
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.Consumers.Access
|
||||
|
||||
namespace Std.Iter
|
||||
open Std.Iterators
|
||||
|
||||
public theorem atIdxSlow?_eq_match [Iterator α Id β] [Productive α Id]
|
||||
{n : Nat} {it : Iter (α := α) β} :
|
||||
it.atIdxSlow? n =
|
||||
(match it.step.val with
|
||||
| .yield it' out =>
|
||||
match n with
|
||||
| 0 => some out
|
||||
| n + 1 => it'.atIdxSlow? n
|
||||
| .skip it' => it'.atIdxSlow? n
|
||||
| .done => none) := by
|
||||
fun_induction it.atIdxSlow? n <;> simp_all
|
||||
|
||||
end Std.Iter
|
||||
@@ -16,15 +16,16 @@ 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 (α := α) β} :
|
||||
theorem Iter.toArray_eq_toArray_toIterM {α β} [Iterator α Id β] [Finite α Id]
|
||||
{it : Iter (α := α) β} :
|
||||
it.toArray = it.toIterM.toArray.run :=
|
||||
(rfl)
|
||||
|
||||
theorem Iter.toList_eq_toList_toIterM {α β} [Iterator α Id β] [Finite α Id] [IteratorCollect α Id Id]
|
||||
[LawfulIteratorCollect α Id Id] {it : Iter (α := α) β} :
|
||||
theorem Iter.toList_eq_toList_toIterM {α β} [Iterator α Id β] [Finite α Id]
|
||||
{it : Iter (α := α) β} :
|
||||
it.toList = it.toIterM.toList.run :=
|
||||
(rfl)
|
||||
|
||||
@@ -34,14 +35,14 @@ theorem Iter.toListRev_eq_toListRev_toIterM {α β} [Iterator α Id β] [Finite
|
||||
(rfl)
|
||||
|
||||
@[simp]
|
||||
theorem Iter.toArray_ensureTermination {α β} [Iterator α Id β] [Finite α Id] [IteratorCollect α Id Id]
|
||||
[LawfulIteratorCollect α Id Id] {it : Iter (α := α) β} :
|
||||
theorem Iter.toArray_ensureTermination {α β} [Iterator α Id β] [Finite α 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 (α := α) β} :
|
||||
theorem Iter.toList_ensureTermination {α β} [Iterator α Id β] [Finite α Id]
|
||||
{it : Iter (α := α) β} :
|
||||
it.ensureTermination.toList = it.toList :=
|
||||
(rfl)
|
||||
|
||||
@@ -51,7 +52,7 @@ theorem Iter.toListRev_ensureTermination_eq_toListRev {α β} [Iterator α Id β
|
||||
(rfl)
|
||||
|
||||
@[simp]
|
||||
theorem IterM.toList_toIter {α β} [Iterator α Id β] [Finite α Id] [IteratorCollect α Id Id]
|
||||
theorem IterM.toList_toIter {α β} [Iterator α Id β] [Finite α Id]
|
||||
{it : IterM (α := α) Id β} :
|
||||
it.toIter.toList = it.toList.run :=
|
||||
(rfl)
|
||||
@@ -63,51 +64,50 @@ theorem IterM.toListRev_toIter {α β} [Iterator α Id β] [Finite α Id]
|
||||
(rfl)
|
||||
|
||||
@[simp]
|
||||
theorem Iter.toList_toArray {α β} [Iterator α Id β] [Finite α Id] [IteratorCollect α Id Id]
|
||||
[LawfulIteratorCollect α Id Id] {it : Iter (α := α) β} :
|
||||
theorem Iter.toList_toArray {α β} [Iterator α Id β] [Finite α Id]
|
||||
{it : Iter (α := α) β} :
|
||||
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 : 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 (α := α) β} :
|
||||
theorem Iter.toArray_toList {α β} [Iterator α Id β] [Finite α 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 : Iter (α := α) β} :
|
||||
it.ensureTermination.toList.toArray = it.toArray := by
|
||||
simp
|
||||
|
||||
@[simp]
|
||||
theorem Iter.reverse_toListRev [Iterator α Id β] [Finite α Id]
|
||||
[IteratorCollect α Id Id] [LawfulIteratorCollect α Id Id]
|
||||
{it : Iter (α := α) β} :
|
||||
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 : 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 (α := α) β} :
|
||||
theorem Iter.toListRev_eq {α β} [Iterator α Id β] [Finite α 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 : 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 (α := α) β} :
|
||||
theorem Iter.toArray_eq_match_step {α β} [Iterator α Id β] [Finite α Id]
|
||||
{it : Iter (α := α) β} :
|
||||
it.toArray = match it.step.val with
|
||||
| .yield it' out => #[out] ++ it'.toArray
|
||||
| .skip it' => it'.toArray
|
||||
@@ -117,16 +117,16 @@ 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 (α := α) β} :
|
||||
theorem Iter.toArray_ensureTermination_eq_match_step {α β} [Iterator α Id β] [Finite α 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 (α := α) β} :
|
||||
theorem Iter.toList_eq_match_step {α β} [Iterator α Id β] [Finite α Id]
|
||||
{it : Iter (α := α) β} :
|
||||
it.toList = match it.step.val with
|
||||
| .yield it' out => out :: it'.toList
|
||||
| .skip it' => it'.toList
|
||||
@@ -134,8 +134,8 @@ 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 (α := α) β} :
|
||||
theorem Iter.toList_ensureTermination_eq_match_step {α β} [Iterator α Id β] [Finite α Id]
|
||||
{it : Iter (α := α) β} :
|
||||
it.ensureTermination.toList = match it.step.val with
|
||||
| .yield it' out => out :: it'.toList
|
||||
| .skip it' => it'.toList
|
||||
@@ -159,7 +159,7 @@ theorem Iter.toListRev_ensureTermination_eq_match_step {α β} [Iterator α Id
|
||||
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]
|
||||
[Iterator α Id β] [Finite α Id]
|
||||
{it : Iter (α := α) β} {k : Nat} :
|
||||
it.toList[k]? = it.atIdxSlow? k := by
|
||||
induction it using Iter.inductSteps generalizing k with | step it ihy ihs
|
||||
@@ -171,15 +171,15 @@ theorem Iter.getElem?_toList_eq_atIdxSlow? {α β}
|
||||
· simp
|
||||
|
||||
theorem Iter.toList_eq_of_atIdxSlow?_eq {α₁ α₂ β}
|
||||
[Iterator α₁ Id β] [Finite α₁ Id] [IteratorCollect α₁ Id Id] [LawfulIteratorCollect α₁ Id Id]
|
||||
[Iterator α₂ Id β] [Finite α₂ Id] [IteratorCollect α₂ Id Id] [LawfulIteratorCollect α₂ Id Id]
|
||||
[Iterator α₁ Id β] [Finite α₁ Id]
|
||||
[Iterator α₂ Id β] [Finite α₂ Id]
|
||||
{it₁ : Iter (α := α₁) β} {it₂ : Iter (α := α₂) β}
|
||||
(h : ∀ k, it₁.atIdxSlow? k = it₂.atIdxSlow? k) :
|
||||
it₁.toList = it₂.toList := by
|
||||
ext; simp [getElem?_toList_eq_atIdxSlow?, h]
|
||||
|
||||
theorem Iter.isPlausibleIndirectOutput_of_mem_toList
|
||||
[Iterator α Id β] [Finite α Id] [IteratorCollect α Id Id] [LawfulIteratorCollect α Id Id]
|
||||
[Iterator α Id β] [Finite α Id]
|
||||
{it : Iter (α := α) β} {b : β} :
|
||||
b ∈ it.toList → it.IsPlausibleIndirectOutput b := by
|
||||
induction it using Iter.inductSteps with | step it ihy ihs
|
||||
@@ -202,7 +202,7 @@ theorem Iter.isPlausibleIndirectOutput_of_mem_toList
|
||||
simp
|
||||
|
||||
theorem Iter.isPlausibleIndirectOutput_of_mem_toListRev
|
||||
[Iterator α Id β] [Finite α Id] [IteratorCollect α Id Id] [LawfulIteratorCollect α Id Id]
|
||||
[Iterator α Id β] [Finite α Id]
|
||||
{it : Iter (α := α) β} {b : β} :
|
||||
b ∈ it.toListRev → it.IsPlausibleIndirectOutput b := by
|
||||
intro h
|
||||
@@ -210,7 +210,7 @@ theorem Iter.isPlausibleIndirectOutput_of_mem_toListRev
|
||||
simpa [toListRev_eq] using h
|
||||
|
||||
theorem Iter.isPlausibleIndirectOutput_of_mem_toArray
|
||||
[Iterator α Id β] [Finite α Id] [IteratorCollect α Id Id] [LawfulIteratorCollect α Id Id]
|
||||
[Iterator α Id β] [Finite α Id]
|
||||
{it : Iter (α := α) β} {b : β} :
|
||||
b ∈ it.toArray → it.IsPlausibleIndirectOutput b := by
|
||||
intro h
|
||||
@@ -218,4 +218,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]
|
||||
@@ -149,8 +150,7 @@ private theorem Iter.forIn'_toList.aux {ρ : Type u} {α : Type v} {γ : Type x}
|
||||
cases h; rfl
|
||||
|
||||
theorem Iter.isPlausibleStep_iff_step_eq {α β} [Iterator α Id β]
|
||||
[IteratorCollect α Id Id] [Finite α Id]
|
||||
[LawfulIteratorCollect α Id Id] [LawfulDeterministicIterator α Id]
|
||||
[Finite α Id] [LawfulDeterministicIterator α Id]
|
||||
{it : Iter (α := α) β} {step} :
|
||||
it.IsPlausibleStep step ↔ it.step.val = step := by
|
||||
obtain ⟨step', hs'⟩ := LawfulDeterministicIterator.isPlausibleStep_eq_eq (it := it.toIterM)
|
||||
@@ -169,8 +169,7 @@ theorem Iter.isPlausibleStep_iff_step_eq {α β} [Iterator α Id β]
|
||||
simpa using h
|
||||
|
||||
theorem Iter.mem_toList_iff_isPlausibleIndirectOutput {α β} [Iterator α Id β]
|
||||
[IteratorCollect α Id Id] [Finite α Id]
|
||||
[LawfulIteratorCollect α Id Id] [LawfulDeterministicIterator α Id]
|
||||
[Finite α Id] [LawfulDeterministicIterator α Id]
|
||||
{it : Iter (α := α) β} {out : β} :
|
||||
out ∈ it.toList ↔ it.IsPlausibleIndirectOutput out := by
|
||||
induction it using Iter.inductSteps with | step it ihy ihs
|
||||
@@ -216,8 +215,7 @@ theorem Iter.mem_toList_iff_isPlausibleIndirectOutput {α β} [Iterator α Id β
|
||||
simp [heq, IterStep.successor] at h₁
|
||||
|
||||
theorem Iter.mem_toArray_iff_isPlausibleIndirectOutput {α β} [Iterator α Id β]
|
||||
[IteratorCollect α Id Id] [Finite α Id]
|
||||
[LawfulIteratorCollect α Id Id] [LawfulDeterministicIterator α Id]
|
||||
[Finite α Id] [LawfulDeterministicIterator α Id]
|
||||
{it : Iter (α := α) β} {out : β} :
|
||||
out ∈ it.toArray ↔ it.IsPlausibleIndirectOutput out := by
|
||||
rw [← Iter.toArray_toList, List.mem_toArray, mem_toList_iff_isPlausibleIndirectOutput]
|
||||
@@ -225,7 +223,6 @@ theorem Iter.mem_toArray_iff_isPlausibleIndirectOutput {α β} [Iterator α Id
|
||||
theorem Iter.forIn'_toList {α β : Type w} [Iterator α Id β]
|
||||
[Finite α Id] {m : Type x → Type x'} [Monad m] [LawfulMonad m]
|
||||
[IteratorLoop α Id m] [LawfulIteratorLoop α Id m]
|
||||
[IteratorCollect α Id Id] [LawfulIteratorCollect α Id Id]
|
||||
[LawfulDeterministicIterator α Id]
|
||||
{γ : Type x} {it : Iter (α := α) β} {init : γ}
|
||||
{f : (out : β) → _ → γ → m (ForInStep γ)} :
|
||||
@@ -259,7 +256,6 @@ theorem Iter.forIn'_toList {α β : Type w} [Iterator α Id β]
|
||||
theorem Iter.forIn'_toArray {α β : Type w} [Iterator α Id β]
|
||||
[Finite α Id] {m : Type x → Type x'} [Monad m] [LawfulMonad m]
|
||||
[IteratorLoop α Id m] [LawfulIteratorLoop α Id m]
|
||||
[IteratorCollect α Id Id] [LawfulIteratorCollect α Id Id]
|
||||
[LawfulDeterministicIterator α Id]
|
||||
{γ : Type x} {it : Iter (α := α) β} {init : γ}
|
||||
{f : (out : β) → _ → γ → m (ForInStep γ)} :
|
||||
@@ -270,7 +266,6 @@ theorem Iter.forIn'_toArray {α β : Type w} [Iterator α Id β]
|
||||
theorem Iter.forIn'_eq_forIn'_toList {α β : Type w} [Iterator α Id β]
|
||||
[Finite α Id] {m : Type x → Type x'} [Monad m] [LawfulMonad m]
|
||||
[IteratorLoop α Id m] [LawfulIteratorLoop α Id m]
|
||||
[IteratorCollect α Id Id] [LawfulIteratorCollect α Id Id]
|
||||
[LawfulDeterministicIterator α Id]
|
||||
{γ : Type x} {it : Iter (α := α) β} {init : γ}
|
||||
{f : (out : β) → _ → γ → m (ForInStep γ)} :
|
||||
@@ -282,7 +277,6 @@ theorem Iter.forIn'_eq_forIn'_toList {α β : Type w} [Iterator α Id β]
|
||||
theorem Iter.forIn'_eq_forIn'_toArray {α β : Type w} [Iterator α Id β]
|
||||
[Finite α Id] {m : Type x → Type x'} [Monad m] [LawfulMonad m]
|
||||
[IteratorLoop α Id m] [LawfulIteratorLoop α Id m]
|
||||
[IteratorCollect α Id Id] [LawfulIteratorCollect α Id Id]
|
||||
[LawfulDeterministicIterator α Id]
|
||||
{γ : Type x} {it : Iter (α := α) β} {init : γ}
|
||||
{f : (out : β) → _ → γ → m (ForInStep γ)} :
|
||||
@@ -294,7 +288,6 @@ theorem Iter.forIn'_eq_forIn'_toArray {α β : Type w} [Iterator α Id β]
|
||||
theorem Iter.forIn_toList {α β : Type w} [Iterator α Id β]
|
||||
[Finite α Id] {m : Type x → Type x'} [Monad m] [LawfulMonad m]
|
||||
[IteratorLoop α Id m] [LawfulIteratorLoop α Id m]
|
||||
[IteratorCollect α Id Id] [LawfulIteratorCollect α Id Id]
|
||||
{γ : Type x} {it : Iter (α := α) β} {init : γ}
|
||||
{f : β → γ → m (ForInStep γ)} :
|
||||
ForIn.forIn it.toList init f = ForIn.forIn it init f := by
|
||||
@@ -320,7 +313,6 @@ theorem Iter.forIn_toList {α β : Type w} [Iterator α Id β]
|
||||
theorem Iter.forIn_toArray {α β : Type w} [Iterator α Id β]
|
||||
[Finite α Id] {m : Type x → Type x'} [Monad m] [LawfulMonad m]
|
||||
[IteratorLoop α Id m] [LawfulIteratorLoop α Id m]
|
||||
[IteratorCollect α Id Id] [LawfulIteratorCollect α Id Id]
|
||||
{γ : Type x} {it : Iter (α := α) β} {init : γ}
|
||||
{f : β → γ → m (ForInStep γ)} :
|
||||
ForIn.forIn it.toArray init f = ForIn.forIn it init f := by
|
||||
@@ -361,15 +353,15 @@ theorem Iter.foldM_eq_match_step {α β : Type w} {γ : Type x} [Iterator α Id
|
||||
|
||||
theorem Iter.foldlM_toList {α β : Type w} {γ : Type x} [Iterator α Id β] [Finite α Id]
|
||||
{m : Type x → Type x'} [Monad m] [LawfulMonad m] [IteratorLoop α Id m]
|
||||
[LawfulIteratorLoop α Id m] [IteratorCollect α Id Id] [LawfulIteratorCollect α Id Id]
|
||||
[LawfulIteratorLoop α Id m]
|
||||
{f : γ → β → m γ} {init : γ} {it : Iter (α := α) β} :
|
||||
it.toList.foldlM (init := init) f = it.foldM (init := init) f := by
|
||||
rw [Iter.foldM_eq_forIn, ← Iter.forIn_toList]
|
||||
simp only [List.forIn_yield_eq_foldlM, id_map']
|
||||
it.toList.foldlM (init := init) f = it.foldM (init := init) f:= by
|
||||
rw [foldM_eq_forIn, ← Iter.forIn_toList]
|
||||
simp
|
||||
|
||||
theorem Iter.foldlM_toArray {α β : Type w} {γ : Type x} [Iterator α Id β] [Finite α Id]
|
||||
{m : Type x → Type x'} [Monad m] [LawfulMonad m] [IteratorLoop α Id m]
|
||||
[LawfulIteratorLoop α Id m] [IteratorCollect α Id Id] [LawfulIteratorCollect α Id Id]
|
||||
[LawfulIteratorLoop α Id m]
|
||||
{f : γ → β → m γ} {init : γ} {it : Iter (α := α) β} :
|
||||
it.toArray.foldlM (init := init) f = it.foldM (init := init) f := by
|
||||
rw [Iter.foldM_eq_forIn, ← Iter.forIn_toArray]
|
||||
@@ -378,7 +370,6 @@ theorem Iter.foldlM_toArray {α β : Type w} {γ : Type x} [Iterator α Id β] [
|
||||
theorem IterM.forIn_eq_foldM {α β : Type w} [Iterator α Id β]
|
||||
[Finite α Id] {m : Type x → Type x'} [Monad m] [LawfulMonad m]
|
||||
[IteratorLoop α Id m] [LawfulIteratorLoop α Id m]
|
||||
[IteratorCollect α Id Id] [LawfulIteratorCollect α Id Id]
|
||||
{γ : Type x} {it : Iter (α := α) β} {init : γ}
|
||||
{f : β → γ → m (ForInStep γ)} :
|
||||
forIn it init f = ForInStep.value <$>
|
||||
@@ -443,14 +434,12 @@ theorem Iter.fold_hom {γ₁ : Type x₁} {γ₂ : Type x₂} [Iterator α Id β
|
||||
|
||||
theorem Iter.toList_eq_fold {α β : Type w} [Iterator α Id β]
|
||||
[Finite α Id] [IteratorLoop α Id Id] [LawfulIteratorLoop α Id Id]
|
||||
[IteratorCollect α Id Id] [LawfulIteratorCollect α Id Id]
|
||||
{it : Iter (α := α) β} :
|
||||
it.toList = it.fold (init := []) (fun l out => l ++ [out]) := by
|
||||
rw [Iter.toList_eq_toList_toIterM, IterM.toList_eq_fold, Iter.fold_eq_fold_toIterM]
|
||||
|
||||
theorem Iter.toArray_eq_fold {α β : Type w} [Iterator α Id β]
|
||||
[Finite α Id] [IteratorLoop α Id Id] [LawfulIteratorLoop α Id Id]
|
||||
[IteratorCollect α Id Id] [LawfulIteratorCollect α Id Id]
|
||||
{it : Iter (α := α) β} :
|
||||
it.toArray = it.fold (init := #[]) (fun xs out => xs.push out) := by
|
||||
simp only [← toArray_toList, toList_eq_fold]
|
||||
@@ -460,7 +449,6 @@ theorem Iter.toArray_eq_fold {α β : Type w} [Iterator α Id β]
|
||||
@[simp]
|
||||
theorem Iter.foldl_toList {α β : Type w} {γ : Type x} [Iterator α Id β] [Finite α Id]
|
||||
[IteratorLoop α Id Id] [LawfulIteratorLoop α Id Id]
|
||||
[IteratorCollect α Id Id] [LawfulIteratorCollect α Id Id]
|
||||
{f : γ → β → γ} {init : γ} {it : Iter (α := α) β} :
|
||||
it.toList.foldl (init := init) f = it.fold (init := init) f := by
|
||||
rw [fold_eq_foldM, List.foldl_eq_foldlM, ← Iter.foldlM_toList]
|
||||
@@ -468,7 +456,6 @@ theorem Iter.foldl_toList {α β : Type w} {γ : Type x} [Iterator α Id β] [Fi
|
||||
@[simp]
|
||||
theorem Iter.foldl_toArray {α β : Type w} {γ : Type x} [Iterator α Id β] [Finite α Id]
|
||||
[IteratorLoop α Id Id] [LawfulIteratorLoop α Id Id]
|
||||
[IteratorCollect α Id Id] [LawfulIteratorCollect α Id Id]
|
||||
{f : γ → β → γ} {init : γ} {it : Iter (α := α) β} :
|
||||
it.toArray.foldl (init := init) f = it.fold (init := init) f := by
|
||||
rw [fold_eq_foldM, Array.foldl_eq_foldlM, ← Iter.foldlM_toArray]
|
||||
@@ -508,7 +495,6 @@ theorem Iter.count_eq_match_step {α β : Type w} [Iterator α Id β]
|
||||
|
||||
@[simp]
|
||||
theorem Iter.size_toArray_eq_count {α β : Type w} [Iterator α Id β] [Finite α Id]
|
||||
[IteratorCollect α Id Id] [LawfulIteratorCollect α Id Id]
|
||||
[IteratorLoop α Id Id] [LawfulIteratorLoop α Id Id]
|
||||
{it : Iter (α := α) β} :
|
||||
it.toArray.size = it.count := by
|
||||
@@ -520,7 +506,6 @@ def Iter.size_toArray_eq_size := @size_toArray_eq_count
|
||||
|
||||
@[simp]
|
||||
theorem Iter.length_toList_eq_count {α β : Type w} [Iterator α Id β] [Finite α Id]
|
||||
[IteratorCollect α Id Id] [LawfulIteratorCollect α Id Id]
|
||||
[IteratorLoop α Id Id] [LawfulIteratorLoop α Id Id]
|
||||
{it : Iter (α := α) β} :
|
||||
it.toList.length = it.count := by
|
||||
@@ -531,7 +516,6 @@ def Iter.length_toList_eq_size := @length_toList_eq_count
|
||||
|
||||
@[simp]
|
||||
theorem Iter.length_toListRev_eq_count {α β : Type w} [Iterator α Id β] [Finite α Id]
|
||||
[IteratorCollect α Id Id] [LawfulIteratorCollect α Id Id]
|
||||
[IteratorLoop α Id Id] [LawfulIteratorLoop α Id Id]
|
||||
{it : Iter (α := α) β} :
|
||||
it.toListRev.length = it.count := by
|
||||
@@ -574,7 +558,6 @@ theorem Iter.anyM_eq_match_step {α β : Type w} {m : Type → Type w'} [Iterato
|
||||
|
||||
theorem Iter.anyM_toList {α β : Type w} {m : Type → Type w'} [Iterator α Id β]
|
||||
[Finite α Id] [Monad m] [LawfulMonad m] [IteratorLoop α Id m] [LawfulIteratorLoop α Id m]
|
||||
[IteratorCollect α Id Id] [LawfulIteratorCollect α Id Id]
|
||||
{it : Iter (α := α) β} {p : β → m Bool} :
|
||||
it.toList.anyM p = it.anyM p := by
|
||||
induction it using Iter.inductSteps with | step it ihy ihs =>
|
||||
@@ -586,7 +569,6 @@ theorem Iter.anyM_toList {α β : Type w} {m : Type → Type w'} [Iterator α Id
|
||||
|
||||
theorem Iter.anyM_toArray {α β : Type w} {m : Type → Type w'} [Iterator α Id β]
|
||||
[Finite α Id] [Monad m] [LawfulMonad m] [IteratorLoop α Id m] [LawfulIteratorLoop α Id m]
|
||||
[IteratorCollect α Id Id] [LawfulIteratorCollect α Id Id]
|
||||
{it : Iter (α := α) β} {p : β → m Bool} :
|
||||
it.toArray.anyM p = it.anyM p := by
|
||||
simp only [← Iter.toArray_toList, List.anyM_toArray, anyM_toList]
|
||||
@@ -633,7 +615,6 @@ theorem Iter.any_eq_forIn {α β : Type w} [Iterator α Id β]
|
||||
|
||||
theorem Iter.any_toList {α β : Type w} [Iterator α Id β]
|
||||
[Finite α Id] [IteratorLoop α Id Id] [LawfulIteratorLoop α Id Id]
|
||||
[IteratorCollect α Id Id] [LawfulIteratorCollect α Id Id]
|
||||
{it : Iter (α := α) β} {p : β → Bool} :
|
||||
it.toList.any p = it.any p := by
|
||||
induction it using Iter.inductSteps with | step it ihy ihs =>
|
||||
@@ -646,7 +627,6 @@ theorem Iter.any_toList {α β : Type w} [Iterator α Id β]
|
||||
|
||||
theorem Iter.any_toArray {α β : Type w} [Iterator α Id β]
|
||||
[Finite α Id] [IteratorLoop α Id Id] [LawfulIteratorLoop α Id Id]
|
||||
[IteratorCollect α Id Id] [LawfulIteratorCollect α Id Id]
|
||||
{it : Iter (α := α) β} {p : β → Bool} :
|
||||
it.toArray.any p = it.any p := by
|
||||
simp only [← Iter.toArray_toList, List.any_toArray, any_toList]
|
||||
@@ -725,7 +705,6 @@ theorem Iter.all_eq_forIn {α β : Type w} [Iterator α Id β]
|
||||
|
||||
theorem Iter.all_toList {α β : Type w} [Iterator α Id β]
|
||||
[Finite α Id] [IteratorLoop α Id Id] [LawfulIteratorLoop α Id Id]
|
||||
[IteratorCollect α Id Id] [LawfulIteratorCollect α Id Id]
|
||||
{it : Iter (α := α) β} {p : β → Bool} :
|
||||
it.toList.all p = it.all p := by
|
||||
induction it using Iter.inductSteps with | step it ihy ihs =>
|
||||
@@ -738,7 +717,6 @@ theorem Iter.all_toList {α β : Type w} [Iterator α Id β]
|
||||
|
||||
theorem Iter.all_toArray {α β : Type w} [Iterator α Id β]
|
||||
[Finite α Id] [IteratorLoop α Id Id] [LawfulIteratorLoop α Id Id]
|
||||
[IteratorCollect α Id Id] [LawfulIteratorCollect α Id Id]
|
||||
{it : Iter (α := α) β} {p : β → Bool} :
|
||||
it.toArray.all p = it.all p := by
|
||||
simp only [← Iter.toArray_toList, List.all_toArray, all_toList]
|
||||
@@ -792,8 +770,8 @@ theorem Iter.findSomeM?_eq_match_step {α β : Type w} {γ : Type x} {m : Type x
|
||||
· simp
|
||||
|
||||
theorem Iter.findSomeM?_toList {α β : Type w} {γ : Type x} {m : Type x → Type w'} [Monad m]
|
||||
[Iterator α Id β] [IteratorLoop α Id m] [IteratorCollect α Id Id]
|
||||
[LawfulMonad m] [Finite α Id] [LawfulIteratorLoop α Id m] [LawfulIteratorCollect α Id Id]
|
||||
[Iterator α Id β] [IteratorLoop α Id m]
|
||||
[LawfulMonad m] [Finite α Id] [LawfulIteratorLoop α Id m]
|
||||
{it : Iter (α := α) β} {f : β → m (Option γ)} :
|
||||
it.toList.findSomeM? f = it.findSomeM? f := by
|
||||
induction it using Iter.inductSteps with | step it ihy ihs
|
||||
@@ -835,8 +813,8 @@ theorem Iter.findSome?_eq_match_step {α β : Type w} {γ : Type x}
|
||||
· simp
|
||||
|
||||
theorem Iter.findSome?_toList {α β : Type w} {γ : Type x}
|
||||
[Iterator α Id β] [IteratorLoop α Id Id] [IteratorCollect α Id Id]
|
||||
[Finite α Id] [LawfulIteratorLoop α Id Id] [LawfulIteratorCollect α Id Id]
|
||||
[Iterator α Id β] [IteratorLoop α Id Id]
|
||||
[Finite α Id] [LawfulIteratorLoop α Id Id]
|
||||
{it : Iter (α := α) β} {f : β → Option γ} :
|
||||
it.toList.findSome? f = it.findSome? f := by
|
||||
simp [findSome?_eq_findSomeM?, List.findSome?_eq_findSomeM?, findSomeM?_toList]
|
||||
@@ -846,7 +824,6 @@ theorem Iter.findSomeM?_pure {α β : Type w} {γ : Type x} {m : Type x → Type
|
||||
[LawfulMonad m] [Finite α Id] [LawfulIteratorLoop α Id m] [LawfulIteratorLoop α Id Id]
|
||||
{it : Iter (α := α) β} {f : β → Option γ} :
|
||||
it.findSomeM? (pure <| f ·) = pure (f := m) (it.findSome? f) := by
|
||||
letI : IteratorCollect α Id Id := .defaultImplementation
|
||||
simp [← findSomeM?_toList, ← findSome?_toList, List.findSomeM?_pure]
|
||||
|
||||
theorem Iter.findM?_eq_findSomeM? {α β : Type w} {m : Type w → Type w'} [Monad m]
|
||||
@@ -873,15 +850,15 @@ theorem Iter.findM?_eq_match_step {α β : Type w} {m : Type w → Type w'} [Mon
|
||||
· simp
|
||||
|
||||
theorem Iter.findM?_toList {α β : Type} {m : Type → Type w'} [Monad m]
|
||||
[Iterator α Id β] [IteratorLoop α Id m] [IteratorCollect α Id Id]
|
||||
[LawfulMonad m] [Finite α Id] [LawfulIteratorLoop α Id m] [LawfulIteratorCollect α Id Id]
|
||||
[Iterator α Id β] [IteratorLoop α Id m]
|
||||
[LawfulMonad m] [Finite α Id] [LawfulIteratorLoop α Id m]
|
||||
{it : Iter (α := α) β} {f : β → m Bool} :
|
||||
it.toList.findM? f = it.findM? (.up <$> f ·) := by
|
||||
simp [findM?_eq_findSomeM?, List.findM?_eq_findSomeM?, findSomeM?_toList]
|
||||
|
||||
theorem Iter.findM?_eq_findM?_toList {α β : Type} {m : Type → Type w'} [Monad m]
|
||||
[Iterator α Id β] [IteratorLoop α Id m] [IteratorCollect α Id Id]
|
||||
[LawfulMonad m] [Finite α Id] [LawfulIteratorLoop α Id m] [LawfulIteratorCollect α Id Id]
|
||||
[Iterator α Id β] [IteratorLoop α Id m]
|
||||
[LawfulMonad m] [Finite α Id] [LawfulIteratorLoop α Id m]
|
||||
{it : Iter (α := α) β} {f : β → m (ULift Bool)} :
|
||||
it.findM? f = it.toList.findM? (ULift.down <$> f ·) := by
|
||||
simp [findM?_toList]
|
||||
@@ -917,8 +894,8 @@ theorem Iter.find?_eq_match_step {α β : Type w}
|
||||
· simp
|
||||
|
||||
theorem Iter.find?_toList {α β : Type w}
|
||||
[Iterator α Id β] [IteratorLoop α Id Id] [IteratorCollect α Id Id]
|
||||
[Finite α Id] [LawfulIteratorLoop α Id Id] [LawfulIteratorCollect α Id Id]
|
||||
[Iterator α Id β] [IteratorLoop α Id Id]
|
||||
[Finite α Id] [LawfulIteratorLoop α Id Id]
|
||||
{it : Iter (α := α) β} {f : β → Bool} :
|
||||
it.toList.find? f = it.find? f := by
|
||||
simp [find?_eq_findSome?, List.find?_eq_findSome?_guard, findSome?_toList, Option.guard_def]
|
||||
@@ -938,4 +915,4 @@ theorem Iter.findM?_pure {α β : Type w} {m : Type w → Type w'} [Monad m]
|
||||
· simp [ihs ‹_›]
|
||||
· simp
|
||||
|
||||
end Std.Iterators
|
||||
end Std
|
||||
|
||||
@@ -15,87 +15,68 @@ import all Init.WFExtrinsicFix
|
||||
|
||||
public section
|
||||
|
||||
namespace Std.Iterators
|
||||
open Std.Internal
|
||||
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 β}
|
||||
variable {α β : Type w} {m : Type w → Type w'} {it : IterM (α := α) m β}
|
||||
|
||||
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
|
||||
private theorem IterM.toArray.go_eq [Monad m]
|
||||
[Iterator α m β] [LawfulMonad m] [Finite α m] {acc : Array β} :
|
||||
go 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
|
||||
| .yield it' out => go it' (acc.push out)
|
||||
| .skip it' => go it' acc
|
||||
| .done => return acc) := by
|
||||
letI : MonadLift m n := ⟨lift (δ := _)⟩
|
||||
rw [toArrayMapped.go, WellFounded.extrinsicFix₂_eq_apply]
|
||||
rw [toArray.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
|
||||
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.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
|
||||
private theorem IterM.toArray.go.aux₁ [Monad m] [LawfulMonad m]
|
||||
[Iterator α m β] [Finite α m] {b : β} {bs : Array β} :
|
||||
IterM.toArray.go it (#[b] ++ bs) (m := m) =
|
||||
(#[b] ++ ·) <$> IterM.toArray.go it bs (m := m) := by
|
||||
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]
|
||||
|
||||
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
|
||||
private theorem IterM.toArray.go.aux₂ [Monad m] [LawfulMonad m]
|
||||
[Iterator α m β] [Finite α m] {acc : Array β} :
|
||||
IterM.toArray.go it acc (m := m) =
|
||||
(acc ++ ·) <$> it.toArray := by
|
||||
rw [← Array.toArray_toList (xs := acc)]
|
||||
generalize acc.toList = acc
|
||||
induction acc with
|
||||
| nil => simp [toArrayMapped]
|
||||
| nil => simp [toArray]
|
||||
| cons x xs ih =>
|
||||
rw [List.toArray_cons, IterM.DefaultConsumers.toArrayMapped.go.aux₁, ih]
|
||||
rw [List.toArray_cons, IterM.toArray.go.aux₁, ih]
|
||||
simp only [Functor.map_map, Array.append_assoc]
|
||||
|
||||
theorem IterM.DefaultConsumers.toArrayMapped_eq_match_step [Monad n] [LawfulMonad n]
|
||||
theorem IterM.toArray_eq_match_step [Monad m] [LawfulMonad m]
|
||||
[Iterator α m β] [Finite α m] :
|
||||
IterM.DefaultConsumers.toArrayMapped lift f it (m := m) = letI : MonadLift m n := ⟨lift (δ := _)⟩; (do
|
||||
match (← it.step).inflate.val with
|
||||
| .yield it' out =>
|
||||
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_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
|
||||
IterM.toArray it (m := m) = (do
|
||||
match (← it.step).inflate.val with
|
||||
| .yield it' out => return #[out] ++ (← it'.toArray)
|
||||
| .skip it' => it'.toArray
|
||||
| .done => return #[]) := by
|
||||
simp only [IterM.toArray, LawfulIteratorCollect.toArrayMapped_eq]
|
||||
rw [IterM.DefaultConsumers.toArrayMapped_eq_match_step]
|
||||
simp [bind_pure_comp, pure_bind]
|
||||
rw [IterM.toArray, IterM.toArray.go_eq]
|
||||
apply bind_congr
|
||||
intro step
|
||||
cases step.inflate using PlausibleIterStep.casesOn <;>
|
||||
simp [IterM.toArray.go.aux₂]
|
||||
|
||||
@[simp]
|
||||
theorem IterM.toArray_ensureTermination [Monad m] [Iterator α m β] [Finite α m]
|
||||
{it : IterM (α := α) m β} :
|
||||
it.ensureTermination.toArray = it.toArray :=
|
||||
(rfl)
|
||||
|
||||
theorem IterM.toArray_ensureTermination_eq_match_step [Monad m] [LawfulMonad m] [Iterator α m β]
|
||||
[Finite α m] [IteratorCollect α m m] [LawfulIteratorCollect α m m] :
|
||||
[Finite α m] :
|
||||
it.ensureTermination.toArray = (do
|
||||
match (← it.step).inflate.val with
|
||||
| .yield it' out => return #[out] ++ (← it'.toArray)
|
||||
@@ -105,34 +86,34 @@ theorem IterM.toArray_ensureTermination_eq_match_step [Monad m] [LawfulMonad m]
|
||||
|
||||
@[simp]
|
||||
theorem IterM.toList_ensureTermination [Monad m] [Iterator α m β] [Finite α m]
|
||||
[IteratorCollect α m m] {it : IterM (α := α) m β} :
|
||||
{it : IterM (α := α) m β} :
|
||||
it.ensureTermination.toList = it.toList :=
|
||||
(rfl)
|
||||
|
||||
@[simp]
|
||||
theorem IterM.toList_toArray [Monad m] [Iterator α m β] [Finite α m] [IteratorCollect α m m]
|
||||
theorem IterM.toList_toArray [Monad m] [Iterator α m β] [Finite α 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 β} :
|
||||
{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 β} :
|
||||
{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 β} :
|
||||
{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 : IterM (α := α) m β} :
|
||||
it.toList = (do
|
||||
match (← it.step).inflate.val with
|
||||
| .yield it' out => return out :: (← it'.toList)
|
||||
@@ -145,7 +126,7 @@ theorem IterM.toList_eq_match_step [Monad m] [LawfulMonad m] [Iterator α m β]
|
||||
split <;> simp
|
||||
|
||||
theorem IterM.toList_ensureTermination_eq_match_step [Monad m] [LawfulMonad m] [Iterator α m β]
|
||||
[Finite α m] [IteratorCollect α m m] [LawfulIteratorCollect α m m] {it : IterM (α := α) m β} :
|
||||
[Finite α m] {it : IterM (α := α) m β} :
|
||||
it.ensureTermination.toList = (do
|
||||
match (← it.step).inflate.val with
|
||||
| .yield it' out => return out :: (← it'.toList)
|
||||
@@ -219,7 +200,6 @@ theorem IterM.toListRev_ensureTermination_eq_match_step [Monad m] [LawfulMonad m
|
||||
|
||||
@[simp]
|
||||
theorem IterM.reverse_toListRev [Monad m] [LawfulMonad m] [Iterator α m β] [Finite α m]
|
||||
[IteratorCollect α m m] [LawfulIteratorCollect α m m]
|
||||
{it : IterM (α := α) m β} :
|
||||
List.reverse <$> it.toListRev = it.toList := by
|
||||
apply Eq.symm
|
||||
@@ -232,35 +212,19 @@ theorem IterM.reverse_toListRev [Monad m] [LawfulMonad m] [Iterator α m β] [Fi
|
||||
|
||||
@[simp]
|
||||
theorem IterM.reverse_toListRev_ensureTermination [Monad m] [LawfulMonad m] [Iterator α m β]
|
||||
[Finite α m] [IteratorCollect α m m] [LawfulIteratorCollect α m m]
|
||||
[Finite α 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
|
||||
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 [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]
|
||||
[hl : LawfulIteratorCollect α m m]
|
||||
{it : IterM (α := α) m β} :
|
||||
it.toList = (letI : IteratorCollect α m m := .defaultImplementation; it.toList) := by
|
||||
simp [IterM.toList, toArray_eq, -IterM.toList_toArray]
|
||||
|
||||
end Std.Iterators
|
||||
end Std
|
||||
|
||||
@@ -12,7 +12,8 @@ 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] [LawfulMonad n]
|
||||
@@ -217,6 +218,34 @@ theorem IterM.forIn_eq_match_step {α β : Type w} {m : Type w → Type w'} [Ite
|
||||
simp only [forIn]
|
||||
exact forIn'_eq_match_step
|
||||
|
||||
theorem IterM.forIn_toList {α β : Type w} [Monad m] [LawfulMonad m] [Iterator α Id β]
|
||||
[Finite α Id] [IteratorLoop α Id m] [LawfulIteratorLoop α Id m]
|
||||
{it : IterM (α := α) Id β} {f : β → γ → m (ForInStep γ)} {init : γ} :
|
||||
ForIn.forIn it.toList.run init f = ForIn.forIn it init f := by
|
||||
rw [List.forIn_eq_foldlM]
|
||||
induction it using IterM.inductSteps generalizing init with | step it ihy ihs
|
||||
rw [forIn_eq_match_step, IterM.toList_eq_match_step]
|
||||
simp only [map_eq_pure_bind, Id.run_bind, liftM, monadLift, pure_bind]
|
||||
cases it.step.run.inflate using PlausibleIterStep.casesOn
|
||||
· rename_i it' out h
|
||||
simp only [List.foldlM_cons, bind_pure_comp, map_bind, Id.run_map]
|
||||
apply bind_congr
|
||||
intro forInStep
|
||||
cases forInStep
|
||||
· induction it'.toList.run <;> simp [*]
|
||||
· simp only [ForIn.forIn] at ihy
|
||||
simp [ihy h]
|
||||
· rename_i it' h
|
||||
simp only [bind_pure_comp]
|
||||
rw [ihs h]
|
||||
· simp
|
||||
|
||||
theorem IterM.forIn_toArray {α β : Type w} [Monad m] [LawfulMonad m] [Iterator α Id β]
|
||||
[Finite α Id] [IteratorLoop α Id m] [LawfulIteratorLoop α Id m]
|
||||
{it : IterM (α := α) Id β} {f : β → γ → m (ForInStep γ)} {init : γ} :
|
||||
ForIn.forIn it.toArray.run init f = ForIn.forIn it init f := by
|
||||
simp [← toArray_toList, forIn_toList]
|
||||
|
||||
theorem IterM.forM_eq_forIn {α β : 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]
|
||||
@@ -325,7 +354,6 @@ theorem IterM.fold_hom {m : Type w → Type w'} [Iterator α m β] [Finite α m]
|
||||
|
||||
theorem IterM.toList_eq_fold {α β : Type w} {m : Type w → Type w'} [Iterator α m β]
|
||||
[Finite α m] [Monad m] [LawfulMonad m] [IteratorLoop α m m] [LawfulIteratorLoop α m m]
|
||||
[IteratorCollect α m m] [LawfulIteratorCollect α m m]
|
||||
{it : IterM (α := α) m β} :
|
||||
it.toList = it.fold (init := []) (fun l out => l ++ [out]) := by
|
||||
suffices h : ∀ l' : List β, (l' ++ ·) <$> it.toList =
|
||||
@@ -348,13 +376,43 @@ theorem IterM.toList_eq_fold {α β : Type w} {m : Type w → Type w'} [Iterator
|
||||
|
||||
theorem IterM.toArray_eq_fold {α β : Type w} {m : Type w → Type w'} [Iterator α m β]
|
||||
[Finite α m] [Monad m] [LawfulMonad m] [IteratorLoop α m m] [LawfulIteratorLoop α m m]
|
||||
[IteratorCollect α m m] [LawfulIteratorCollect α m m]
|
||||
{it : IterM (α := α) m β} :
|
||||
it.toArray = it.fold (init := #[]) (fun xs out => xs.push out) := by
|
||||
simp only [← toArray_toList, toList_eq_fold]
|
||||
rw [← fold_hom]
|
||||
simp
|
||||
|
||||
theorem IterM.foldlM_toList {α β : Type w} [Monad m] [LawfulMonad m] [Iterator α Id β]
|
||||
[Finite α Id] [IteratorLoop α Id m] [LawfulIteratorLoop α Id m]
|
||||
{it : IterM (α := α) Id β} {f : γ → β → m γ} {init : γ} :
|
||||
it.toList.run.foldlM f init = it.foldM f init := by
|
||||
simp [foldM_eq_forIn, ← forIn_toList]
|
||||
|
||||
theorem IterM.foldlM_toArray {α β : Type w} [Monad m] [LawfulMonad m] [Iterator α Id β]
|
||||
[Finite α Id] [IteratorLoop α Id m] [LawfulIteratorLoop α Id m]
|
||||
{it : IterM (α := α) Id β} {f : γ → β → m γ} {init : γ} :
|
||||
it.toArray.run.foldlM f init = it.foldM f init := by
|
||||
simp [← toArray_toList, foldlM_toList]
|
||||
|
||||
theorem IterM.foldl_toList {α β : Type w} [Monad m] [LawfulMonad m] [Iterator α m β]
|
||||
[Finite α m] [IteratorLoop α m m] [LawfulIteratorLoop α m m]
|
||||
{it : IterM (α := α) m β} {f : γ → β → γ} {init : γ} :
|
||||
(·.foldl f init) <$> it.toList = it.fold f init := by
|
||||
induction it using IterM.inductSteps generalizing init with | step it ihy ihs
|
||||
rw [toList_eq_match_step, fold_eq_match_step]
|
||||
simp only [bind_pure_comp, map_bind]
|
||||
apply bind_congr; intro step
|
||||
cases step.inflate using PlausibleIterStep.casesOn
|
||||
· simp [ihy ‹_›]
|
||||
· simp [ihs ‹_›]
|
||||
· simp
|
||||
|
||||
theorem IterM.foldl_toArray {α β : Type w} [Monad m] [LawfulMonad m] [Iterator α m β]
|
||||
[Finite α m] [IteratorLoop α m m] [LawfulIteratorLoop α m m]
|
||||
{it : IterM (α := α) m β} {f : γ → β → γ} {init : γ} :
|
||||
(·.foldl f init) <$> it.toArray = it.fold f init := by
|
||||
simp only [← toArray_toList, Functor.map_map, List.foldl_toArray, foldl_toList]
|
||||
|
||||
theorem IterM.drain_eq_fold {α β : Type w} {m : Type w → Type w'} [Iterator α m β] [Finite α m]
|
||||
[Monad m] [IteratorLoop α m m] {it : IterM (α := α) m β} :
|
||||
it.drain = it.fold (init := PUnit.unit) (fun _ _ => .unit) :=
|
||||
@@ -383,7 +441,6 @@ theorem IterM.drain_eq_match_step {α β : Type w} {m : Type w → Type w'} [Ite
|
||||
|
||||
theorem IterM.drain_eq_map_toList {α β : Type w} {m : Type w → Type w'} [Iterator α m β]
|
||||
[Finite α m] [Monad m] [LawfulMonad m] [IteratorLoop α m m] [LawfulIteratorLoop α m m]
|
||||
[IteratorCollect α m m] [LawfulIteratorCollect α m m]
|
||||
{it : IterM (α := α) m β} :
|
||||
it.drain = (fun _ => .unit) <$> it.toList := by
|
||||
induction it using IterM.inductSteps with | step it ihy ihs
|
||||
@@ -400,14 +457,12 @@ theorem IterM.drain_eq_map_toList {α β : Type w} {m : Type w → Type w'} [Ite
|
||||
|
||||
theorem IterM.drain_eq_map_toListRev {α β : Type w} {m : Type w → Type w'} [Iterator α m β]
|
||||
[Finite α m] [Monad m] [LawfulMonad m] [IteratorLoop α m m] [LawfulIteratorLoop α m m]
|
||||
[IteratorCollect α m m] [LawfulIteratorCollect α m m]
|
||||
{it : IterM (α := α) m β} :
|
||||
it.drain = (fun _ => .unit) <$> it.toListRev := by
|
||||
simp [IterM.drain_eq_map_toList, IterM.toListRev_eq]
|
||||
|
||||
theorem IterM.drain_eq_map_toArray {α β : Type w} {m : Type w → Type w'} [Iterator α m β]
|
||||
[Finite α m] [Monad m] [LawfulMonad m] [IteratorLoop α m m] [LawfulIteratorLoop α m m]
|
||||
[IteratorCollect α m m] [LawfulIteratorCollect α m m]
|
||||
{it : IterM (α := α) m β} :
|
||||
it.drain = (fun _ => .unit) <$> it.toList := by
|
||||
simp [IterM.drain_eq_map_toList]
|
||||
@@ -451,7 +506,6 @@ theorem IterM.count_eq_match_step {α β : Type w} {m : Type w → Type w'} [Ite
|
||||
@[simp]
|
||||
theorem IterM.up_size_toArray_eq_count {α β : Type w} [Iterator α m β] [Finite α m]
|
||||
[Monad m] [LawfulMonad m]
|
||||
[IteratorCollect α m m] [LawfulIteratorCollect α m m]
|
||||
[IteratorLoop α m m] [LawfulIteratorLoop α m m]
|
||||
{it : IterM (α := α) m β} :
|
||||
(.up <| ·.size) <$> it.toArray = it.count := by
|
||||
@@ -462,7 +516,6 @@ theorem IterM.up_size_toArray_eq_count {α β : Type w} [Iterator α m β] [Fini
|
||||
@[simp]
|
||||
theorem IterM.up_length_toList_eq_count {α β : Type w} [Iterator α m β] [Finite α m]
|
||||
[Monad m] [LawfulMonad m]
|
||||
[IteratorCollect α m m] [LawfulIteratorCollect α m m]
|
||||
[IteratorLoop α m m] [LawfulIteratorLoop α m m]
|
||||
{it : IterM (α := α) m β} :
|
||||
(.up <| ·.length) <$> it.toList = it.count := by
|
||||
@@ -473,7 +526,6 @@ theorem IterM.up_length_toList_eq_count {α β : Type w} [Iterator α m β] [Fin
|
||||
@[simp]
|
||||
theorem IterM.up_length_toListRev_eq_count {α β : Type w} [Iterator α m β] [Finite α m]
|
||||
[Monad m] [LawfulMonad m]
|
||||
[IteratorCollect α m m] [LawfulIteratorCollect α m m]
|
||||
[IteratorLoop α m m] [LawfulIteratorLoop α m m]
|
||||
{it : IterM (α := α) m β} :
|
||||
(.up <| ·.length) <$> it.toListRev = it.count := by
|
||||
@@ -780,4 +832,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 β} :
|
||||
@[simp, grind =]
|
||||
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 β} :
|
||||
@[simp, grind =]
|
||||
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 β} :
|
||||
@[simp, grind =]
|
||||
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,54 +18,43 @@ 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]
|
||||
{β : 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
|
||||
rw [LawfulIteratorCollect.toArrayMapped_eq]
|
||||
@[simp, grind =]
|
||||
theorem List.toArray_iterM [LawfulMonad m] {β : Type w} {l : List β} :
|
||||
(l.iterM m).toArray = pure l.toArray := by
|
||||
induction l with
|
||||
| nil =>
|
||||
rw [IterM.DefaultConsumers.toArrayMapped_eq_match_step]
|
||||
simp [List.step_iterM_nil, LawfulMonadLiftFunction.lift_pure]
|
||||
rw [IterM.toArray_eq_match_step]
|
||||
simp [List.step_iterM_nil]
|
||||
| cons x xs ih =>
|
||||
rw [IterM.DefaultConsumers.toArrayMapped_eq_match_step]
|
||||
simp [List.step_iterM_cons, List.mapM_cons, pure_bind, ih, LawfulMonadLiftFunction.lift_pure]
|
||||
rw [IterM.toArray_eq_match_step]
|
||||
simp [List.step_iterM_cons, pure_bind, ih]
|
||||
|
||||
@[simp]
|
||||
theorem _root_.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 β} :
|
||||
@[simp, grind =]
|
||||
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 β} :
|
||||
@[simp, grind =]
|
||||
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
|
||||
|
||||
@@ -53,6 +53,11 @@ def PostconditionT.lift {α : Type w} {m : Type w → Type w'} [Functor m] (x :
|
||||
PostconditionT m α :=
|
||||
⟨fun _ => True, (⟨·, .intro⟩) <$> x⟩
|
||||
|
||||
@[always_inline, inline, expose]
|
||||
def PostconditionT.attachLift {α : Type w} {m : Type w → Type w'} [MonadAttach m]
|
||||
(x : m α) : PostconditionT m α :=
|
||||
⟨MonadAttach.CanReturn x, MonadAttach.attach x⟩
|
||||
|
||||
@[always_inline, inline, expose]
|
||||
protected def PostconditionT.pure {m : Type w → Type w'} [Pure m] {α : Type w}
|
||||
(a : α) : PostconditionT m α :=
|
||||
@@ -67,7 +72,7 @@ def PostconditionT.liftWithProperty {α : Type w} {m : Type w → Type w'} {P :
|
||||
⟨P, x⟩
|
||||
|
||||
/--
|
||||
Given a function `f : α → β`, returns a a function `PostconditionT m α → PostconditionT m β`,
|
||||
Given a function `f : α → β`, returns a function `PostconditionT m α → PostconditionT m β`,
|
||||
turning `PostconditionT m` into a functor.
|
||||
|
||||
The postcondition of the `x.map f` states that the return value is the image under `f` of some
|
||||
@@ -80,7 +85,7 @@ protected def PostconditionT.map {m : Type w → Type w'} [Functor m] {α : Type
|
||||
(fun a => ⟨f a.val, _, rfl⟩) <$> x.operation⟩
|
||||
|
||||
/--
|
||||
Given a function `α → PostconditionT m β`, returns a a function
|
||||
Given a function `α → PostconditionT m β`, returns a function
|
||||
`PostconditionT m α → PostconditionT m β`, turning `PostconditionT m` into a monad.
|
||||
-/
|
||||
@[always_inline, inline, expose]
|
||||
@@ -116,6 +121,11 @@ def PostconditionT.run {m : Type w → Type w'} [Monad m] {α : Type w} (x : Pos
|
||||
m α :=
|
||||
(fun a => a.val) <$> x.operation
|
||||
|
||||
theorem PostconditionT.run_eq_map {m : Type w → Type w'} [Monad m] {α : Type w}
|
||||
{x : PostconditionT m α} :
|
||||
x.run = Subtype.val <$> x.operation :=
|
||||
(rfl)
|
||||
|
||||
instance {m : Type w → Type w'} [Functor m] : Functor (PostconditionT m) where
|
||||
map := PostconditionT.map
|
||||
|
||||
@@ -238,6 +248,28 @@ theorem PostconditionT.operation_bind' {m : Type w → Type w'} [Monad m] {α :
|
||||
(fun fa => ⟨fa.1, by exact⟨a.1, a.2, fa.2⟩⟩) <$> (f a.1).operation) := by
|
||||
rfl
|
||||
|
||||
theorem PostconditionT.operation_eq_map_mk_operation {m : Type w → Type w'}
|
||||
[Monad m] [LawfulMonad m] {x : PostconditionT m α} :
|
||||
x.operation = (fun a => ⟨a.val, a.property⟩) <$> x.operation := by
|
||||
simp
|
||||
|
||||
theorem PostconditionT.operation_bind_eq_operation_bind_mk {m : Type w → Type w'}
|
||||
[Monad m] {x : PostconditionT m α} {f : Subtype x.Property → m β} :
|
||||
x.operation >>= f = x.operation >>= (fun a => f ⟨a.val, a.property⟩) := by
|
||||
rfl
|
||||
|
||||
@[simp]
|
||||
theorem PostconditionT.run_bind {m : Type w → Type w'} [Monad m] [LawfulMonad m]
|
||||
{α : Type w} {β : Type w} {x : PostconditionT m α} {f : α → PostconditionT m β} :
|
||||
(x.bind f).run = x.run >>= (f · |>.run) := by
|
||||
simp [run_eq_map]
|
||||
|
||||
@[simp]
|
||||
theorem PostconditionT.run_bind' {m : Type w → Type w'} [Monad m] [LawfulMonad m]
|
||||
{α : Type w} {β : Type w} {x : PostconditionT m α} {f : α → PostconditionT m β} :
|
||||
(x >>= f).run = x.run >>= (f · |>.run) :=
|
||||
run_bind
|
||||
|
||||
@[simp]
|
||||
theorem PostconditionT.property_lift {m : Type w → Type w'} [Functor m] {α : Type w}
|
||||
{x : m α} : (lift x : PostconditionT m α).Property = (fun _ => True) := by
|
||||
@@ -249,6 +281,18 @@ theorem PostconditionT.operation_lift {m : Type w → Type w'} [Functor m] {α :
|
||||
(⟨·, property_lift (m := m) ▸ True.intro⟩) <$> x := by
|
||||
rfl
|
||||
|
||||
@[simp]
|
||||
theorem PostconditionT.run_attachLift {m : Type w → Type w'} [Monad m] [MonadAttach m]
|
||||
[WeaklyLawfulMonadAttach m] {α : Type w}
|
||||
{x : m α} : (attachLift x).run = x := by
|
||||
simp [attachLift, run_eq_map, WeaklyLawfulMonadAttach.map_attach]
|
||||
|
||||
@[simp]
|
||||
theorem PostconditionT.operation_attachLift {m : Type w → Type w'} [Monad m] [MonadAttach m]
|
||||
{α : Type w} {x : m α} : (attachLift x : PostconditionT m α).operation =
|
||||
MonadAttach.attach x := by
|
||||
rfl
|
||||
|
||||
instance {m : Type w → Type w'} {n : Type w → Type w''} [MonadLift m n] :
|
||||
MonadLift (PostconditionT m) (PostconditionT n) where
|
||||
monadLift x := ⟨_, monadLift x.operation⟩
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -7,7 +7,6 @@ module
|
||||
|
||||
prelude
|
||||
public import Init.Data.Iterators.Consumers
|
||||
public import Init.Data.Iterators.Internal.Termination
|
||||
|
||||
@[expose] public section
|
||||
|
||||
@@ -17,9 +16,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 +28,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,38 +48,35 @@ 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)
|
||||
Rel := InvImage WellFoundedRelation.rel (ListIterator.list ∘ IterM.internalState)
|
||||
wf := InvImage.wf _ WellFoundedRelation.wf
|
||||
subrelation {it it'} h := by
|
||||
simp_wf
|
||||
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] :
|
||||
IteratorCollect (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
|
||||
|
||||
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
|
||||
|
||||
@@ -11,7 +11,7 @@ public import Init.Core
|
||||
public section
|
||||
|
||||
/--
|
||||
The `BEq α` and `Hashable α` instances on `α` are compatible. This means that that `a == b` implies
|
||||
The `BEq α` and `Hashable α` instances on `α` are compatible. This means that `a == b` implies
|
||||
`hash a = hash b`.
|
||||
|
||||
This is automatic if the `BEq` instance is lawful.
|
||||
|
||||
@@ -169,10 +169,10 @@ Examples:
|
||||
| a::as, b::bs, eqv => eqv a b && isEqv as bs eqv
|
||||
| _, _, _ => false
|
||||
|
||||
@[simp] theorem isEqv_nil_nil : isEqv ([] : List α) [] eqv = true := rfl
|
||||
@[simp] theorem isEqv_nil_cons : isEqv ([] : List α) (a::as) eqv = false := rfl
|
||||
@[simp] theorem isEqv_cons_nil : isEqv (a::as : List α) [] eqv = false := rfl
|
||||
theorem isEqv_cons₂ : isEqv (a::as) (b::bs) eqv = (eqv a b && isEqv as bs eqv) := rfl
|
||||
@[simp, grind =] theorem isEqv_nil_nil : isEqv ([] : List α) [] eqv = true := rfl
|
||||
@[simp, grind =] theorem isEqv_nil_cons : isEqv ([] : List α) (a::as) eqv = false := rfl
|
||||
@[simp, grind =] theorem isEqv_cons_nil : isEqv (a::as : List α) [] eqv = false := rfl
|
||||
@[grind =] theorem isEqv_cons₂ : isEqv (a::as) (b::bs) eqv = (eqv a b && isEqv as bs eqv) := rfl
|
||||
|
||||
|
||||
/-! ## Lexicographic ordering -/
|
||||
@@ -717,6 +717,7 @@ Examples:
|
||||
* `["red", "green", "blue"].leftpad 3 "blank" = ["red", "green", "blue"]`
|
||||
* `["red", "green", "blue"].leftpad 1 "blank" = ["red", "green", "blue"]`
|
||||
-/
|
||||
@[simp, grind =]
|
||||
def leftpad (n : Nat) (a : α) (l : List α) : List α := replicate (n - length l) a ++ l
|
||||
|
||||
|
||||
@@ -730,6 +731,7 @@ Examples:
|
||||
* `["red", "green", "blue"].rightpad 3 "blank" = ["red", "green", "blue"]`
|
||||
* `["red", "green", "blue"].rightpad 1 "blank" = ["red", "green", "blue"]`
|
||||
-/
|
||||
@[simp, grind =]
|
||||
def rightpad (n : Nat) (a : α) (l : List α) : List α := l ++ replicate (n - length l) a
|
||||
|
||||
/-! ### reduceOption -/
|
||||
|
||||
@@ -50,7 +50,7 @@ Users that want to use `mapM` with `Applicative` should use `mapA` instead.
|
||||
Applies the monadic action `f` to every element in the list, left-to-right, and returns the list of
|
||||
results.
|
||||
|
||||
This implementation is tail recursive. `List.mapM'` is a a non-tail-recursive variant that may be
|
||||
This implementation is tail recursive. `List.mapM'` is a non-tail-recursive variant that may be
|
||||
more convenient to reason about. `List.forM` is the variant that discards the results and
|
||||
`List.mapA` is the variant that works with `Applicative`.
|
||||
-/
|
||||
@@ -107,7 +107,7 @@ Applies the monadic action `f` to the corresponding elements of two lists, left-
|
||||
at the end of the shorter list. `zipWithM f as bs` is equivalent to `mapM id (zipWith f as bs)`
|
||||
for lawful `Monad` instances.
|
||||
|
||||
This implementation is tail recursive. `List.zipWithM'` is a a non-tail-recursive variant that may
|
||||
This implementation is tail recursive. `List.zipWithM'` is a non-tail-recursive variant that may
|
||||
be more convenient to reason about.
|
||||
-/
|
||||
@[inline, expose]
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user