Skip to content

Commit eb7e443

Browse files
committed
feat: initial commit, adapted from mathlib4
mathlib4 commit: 2e3cdfaaa8ba1639dc092757cee447e77591ad00
1 parent 395c454 commit eb7e443

22 files changed

+1373
-0
lines changed

.github/workflows/build.yml

+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
on:
2+
push:
3+
branches-ignore:
4+
# ignore tmp branches used by bors
5+
- 'staging.tmp*'
6+
- 'trying.tmp*'
7+
- 'staging*.tmp'
8+
pull_request:
9+
10+
name: ci
11+
12+
jobs:
13+
build:
14+
name: Build
15+
runs-on: ubuntu-latest
16+
steps:
17+
- name: install elan
18+
run: |
19+
set -o pipefail
20+
curl -sSfL https://github.com/leanprover/elan/releases/download/v1.3.1/elan-x86_64-unknown-linux-gnu.tar.gz | tar xz
21+
./elan-init -y --default-toolchain none
22+
echo "$HOME/.elan/bin" >> $GITHUB_PATH
23+
24+
- uses: actions/checkout@v2
25+
26+
- name: update Std.lean
27+
run: |
28+
find Std -name "*.lean" | LC_ALL=C sort | sed 's/\.lean//;s,/,.,g;s/^/import /' > Std.lean
29+
30+
- name: build std
31+
run: lake build
32+
33+
- name: test std
34+
run: make test
35+
36+
- name: lint std
37+
run: make lint
38+
39+
- name: check that all files are imported
40+
run: git diff --exit-code

.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
/build
2+
/prelude/build

.vscode/copyright.code-snippets

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
{
2+
"Copyright header for std": {
3+
"scope": "lean4",
4+
"prefix": "copyright",
5+
"body": [
6+
"/-",
7+
"Copyright (c) ${CURRENT_YEAR} $1. All rights reserved.",
8+
"Released under Apache 2.0 license as described in the file LICENSE.",
9+
"Authors: $1",
10+
"-/"
11+
]
12+
}
13+
}

.vscode/settings.json

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"editor.insertSpaces": true,
3+
"editor.tabSize": 2,
4+
"editor.rulers" : [100],
5+
"files.encoding": "utf8",
6+
"files.eol": "\n",
7+
"files.insertFinalNewline": true,
8+
"files.trimFinalNewlines": true,
9+
"files.trimTrailingWhitespace": true,
10+
"search.usePCRE2": true
11+
}

GNUmakefile

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
TESTS = $(wildcard test/*.lean)
2+
3+
.PHONY: all build test lint
4+
5+
all: build test
6+
7+
build:
8+
lake build
9+
10+
test: $(addsuffix .run, $(TESTS))
11+
12+
test/%.run: build
13+
lake env lean test/$*
14+
15+
lint: build
16+
./build/bin/runLinter

README.md

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# std4
2+
3+
Work in progress standard library for Lean 4. This is a collection of data structures and tactics intended for use by both computer-science applications and mathematics applications of Lean 4.
4+
5+
# Build instructions
6+
7+
* Get the newest version of `elan`. If you already have installed a version of Lean, you can run
8+
```
9+
elan self update
10+
```
11+
If the above command fails, or if you need to install `elan`, run
12+
```
13+
curl https://raw.githubusercontent.com/leanprover/elan/master/elan-init.sh -sSf | sh
14+
```
15+
If this also fails, follow the instructions under `Regular install` [here](https://leanprover-community.github.io/get_started.html).
16+
* To build `std4` run `lake build`. To build and run all tests, run `make`.
17+
* If you added a new file, run the following command to update `Std.lean`
18+
```
19+
find Std -name "*.lean" | env LC_ALL=C sort | sed 's/\.lean//;s,/,.,g;s/^/import /' > Std.lean
20+
```

Std.lean

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import Std.Data.Array.Defs
2+
import Std.Lean.NameMapAttribute
3+
import Std.Tactic.Lint
4+
import Std.Tactic.Lint.Basic
5+
import Std.Tactic.Lint.Frontend
6+
import Std.Tactic.Lint.Misc
7+
import Std.Tactic.Lint.Simp
8+
import Std.Tactic.OpenPrivate
9+
import Std.Util.LibraryNote
10+
import Std.Util.TermUnsafe

Std/Data/Array/Defs.lean

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/-
2+
Copyright (c) 2021 Floris van Doorn. All rights reserved.
3+
Released under Apache 2.0 license as described in the file LICENSE.
4+
Authors: Arthur Paulino, Floris van Doorn
5+
-/
6+
7+
/-!
8+
## Definitions on Arrays
9+
10+
This file contains various definitions on `Array`. It does not contain
11+
proofs about these definitions, those are contained in other files in `Std.Data.Array`.
12+
-/
13+
14+
namespace Array
15+
16+
/-- The array `#[f 0, ..., f n]` -/
17+
def ofFn (n : Nat) (f : Fin n → α) : Array α :=
18+
loop 0 (mkEmpty n)
19+
where
20+
/-- Implementation detail of `Array.ofFn`. -/
21+
loop (i : Nat) (acc : Array α) : Array α :=
22+
if h : i < n then
23+
let acc := acc.push (f ⟨i, h⟩)
24+
loop (i + 1) acc
25+
else
26+
acc
27+
termination_by
28+
loop i acc => n - i
29+
30+
/-- The array `#[0, 1, ..., n - 1]`. -/
31+
def range (n : Nat) : Array Nat :=
32+
n.fold (flip Array.push) #[]
33+
34+
/-- Drop `none`s from a Array, and replace each remaining `some a` with `a`. -/
35+
def reduceOption (l : Array (Option α)) : Array α :=
36+
l.filterMap id
37+
38+
/-- Turns `#[#[a₁, a₂, ⋯], #[b₁, b₂, ⋯], ⋯]` into `#[a₁, a₂, ⋯, b₁, b₂, ⋯]` -/
39+
def flatten (arr : Array (Array α)) : Array α :=
40+
arr.foldl (init := #[]) fun acc a => acc.append a
41+
42+
end Array

Std/Lean/NameMapAttribute.lean

+72
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
/-
2+
Copyright (c) 2022 E.W.Ayers. All rights reserved.
3+
Released under Apache 2.0 license as described in the file LICENSE.
4+
Authors: E.W.Ayers
5+
-/
6+
import Lean
7+
8+
namespace Lean
9+
10+
/-- Maps declaration names to α. -/
11+
def NameMapExtension (α : Type) := SimplePersistentEnvExtension (Name × α) (NameMap α)
12+
13+
instance : Inhabited (NameMapExtension α) :=
14+
inferInstanceAs <| Inhabited (SimplePersistentEnvExtension ..)
15+
16+
def NameMapExtension.find? (ext : NameMapExtension α) (env : Environment) : Name → Option α :=
17+
(SimplePersistentEnvExtension.getState ext env).find?
18+
19+
/-- Add the given k,v pair to the NameMapExtension. -/
20+
def NameMapExtension.add [Monad M] [MonadEnv M] [MonadError M]
21+
(ext : NameMapExtension α) (k : Name) (v : α) : M Unit := do
22+
if let some _ := ext.find? (←getEnv) k then
23+
throwError "Already exists entry for {ext.name} {k}"
24+
else
25+
ext.addEntry (←getEnv) (k, v) |> setEnv
26+
27+
def mkNameMapExtension (α) (name : Name): IO (NameMapExtension α) := do
28+
registerSimplePersistentEnvExtension {
29+
name := name,
30+
addImportedFn := fun ass => ass.foldl (init := ∅) fun
31+
| names, as => as.foldl (init := names) fun
32+
| names, (a,b) => names.insert a b,
33+
addEntryFn := fun s n => s.insert n.1 n.2 ,
34+
toArrayFn := fun es => es.toArray
35+
}
36+
37+
structure NameMapAttributeImpl (α : Type) where
38+
name : Name
39+
descr : String
40+
add : (src : Name) → (stx : Syntax) → AttrM α
41+
deriving Inhabited
42+
43+
/-- Similar to ParametricAttribute except that attributes do not
44+
have to be assigned in the same file as the declaration. -/
45+
structure NameMapAttribute (α) where
46+
impl : NameMapAttributeImpl α
47+
ext : NameMapExtension α
48+
deriving Inhabited
49+
50+
def NameMapAttribute.find? (attr : NameMapAttribute α)
51+
: (env : Environment) → Name → Option α := attr.ext.find?
52+
53+
def NameMapAttribute.add [Monad M] [MonadEnv M] [MonadError M]
54+
(attr : NameMapAttribute α) (k : Name) (v : α) : M Unit :=
55+
attr.ext.add k v
56+
57+
def registerNameMapAttribute (impl : NameMapAttributeImpl α) : IO (NameMapAttribute α) := do
58+
let ext ← mkNameMapExtension α impl.name
59+
registerBuiltinAttribute {
60+
name := impl.name
61+
descr := impl.descr
62+
add := fun src stx _kind => do
63+
let a : α ← impl.add src stx
64+
ext.add src a
65+
}
66+
return {
67+
impl := impl
68+
ext := ext
69+
}
70+
71+
72+
end Lean

Std/Tactic/Lint.lean

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import Std.Tactic.Lint.Misc
2+
import Std.Tactic.Lint.Simp
3+
import Std.Tactic.Lint.Frontend

Std/Tactic/Lint/Basic.lean

+104
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
/-
2+
Copyright (c) 2020 Floris van Doorn. All rights reserved.
3+
Released under Apache 2.0 license as described in the file LICENSE.
4+
Authors: Floris van Doorn, Robert Y. Lewis, Gabriel Ebner
5+
-/
6+
7+
import Lean
8+
import Std.Util.TermUnsafe
9+
import Std.Lean.NameMapAttribute
10+
open Lean Meta
11+
12+
namespace Std.Tactic.Lint
13+
14+
/-!
15+
# Basic linter types and attributes
16+
17+
This file defines the basic types and attributes used by the linting
18+
framework. A linter essentially consists of a function
19+
`(declaration : Name) → MetaM (Option MessageData)`, this function together with some
20+
metadata is stored in the `Linter` structure. We define two attributes:
21+
22+
* `@[stdLinter]` applies to a declaration of type `Linter` and adds it to the default linter set.
23+
24+
* `@[nolint linterName]` omits the tagged declaration from being checked by
25+
the linter with name `linterName`.
26+
-/
27+
28+
syntax (name := nolint) "nolint" (ppSpace ident)+ : attr
29+
30+
-- Defines the user attribute `nolint` for skipping `#lint`
31+
initialize nolintAttr : NameMapAttribute (Array Name) ←
32+
registerNameMapAttribute {
33+
name := `nolint
34+
descr := "Do not report this declaration in any of the tests of `#lint`"
35+
add := fun _decl stx =>
36+
match stx with
37+
-- TODO: validate linter names
38+
| `(attr|nolint $[$ids]*) => pure $ ids.map (·.getId.eraseMacroScopes)
39+
| _ => throwError "unexpected nolint syntax {stx}"
40+
}
41+
42+
/-- Returns true if `decl` should be checked
43+
using `linter`, i.e., if there is no `nolint` attribute. -/
44+
def shouldBeLinted [Monad m] [MonadEnv m] (linter : Name) (decl : Name) : m Bool :=
45+
return !((nolintAttr.find? (← getEnv) decl).getD {}).contains linter
46+
47+
/--
48+
Returns true if `decl` is an automatically generated declaration.
49+
50+
Also returns true if `decl` is an internal name or created during macro
51+
expansion.
52+
-/
53+
def isAutoDecl (decl : Name) : CoreM Bool := do
54+
if decl.hasMacroScopes then return true
55+
if decl.isInternal then return true
56+
if let Name.str n s := decl then
57+
if s.startsWith "proof_" || s.startsWith "match_" then return true
58+
if (← getEnv).isConstructor n && ["injEq", "inj", "sizeOf_spec"].any (· == s) then
59+
return true
60+
if let ConstantInfo.inductInfo _ := (← getEnv).find? n then
61+
if [casesOnSuffix, recOnSuffix, brecOnSuffix, binductionOnSuffix, belowSuffix,
62+
"ndrec", "ndrecOn", "noConfusionType", "noConfusion"].any (· == s) then
63+
return true
64+
pure false
65+
66+
/--
67+
A linting test for the `#lint` command.
68+
69+
`test` defines a test to perform on every declaration. It should never fail. Returning `none`
70+
signifies a passing test. Returning `some msg` reports a failing test with error `msg`.
71+
72+
`noErrorsFound` is the message printed when all tests are negative, and `errorsFound` is printed
73+
when at least one test is positive.
74+
75+
If `isFast` is false, this test will be omitted from `#lint-`.
76+
-/
77+
structure Linter where
78+
test : Name → MetaM (Option MessageData)
79+
noErrorsFound : MessageData
80+
errorsFound : MessageData
81+
isFast := true
82+
83+
structure NamedLinter extends Linter where
84+
declName : Name
85+
86+
def NamedLinter.name (l : NamedLinter) : Name := l.declName.updatePrefix Name.anonymous
87+
88+
def getLinter (declName : Name) : CoreM NamedLinter := unsafe
89+
return { ← evalConstCheck Linter ``Linter declName with declName }
90+
91+
/-- Takes a list of names that resolve to declarations of type `linter`,
92+
and produces a list of linters. -/
93+
def getLinters (l : List Name) : CoreM (List NamedLinter) :=
94+
l.mapM getLinter
95+
96+
-- Defines the user attribute `stdLinter` for adding a linter to the default set.
97+
initialize stdLinterAttr : TagAttribute ←
98+
registerTagAttribute
99+
(name := `stdLinter)
100+
(descr := "Use this declaration as a linting test in #lint")
101+
(validate := fun name => do
102+
let constInfo ← getConstInfo name
103+
unless ← (isDefEq constInfo.type (mkConst ``Linter)).run' do
104+
throwError "must have type Linter, got {constInfo.type}")

0 commit comments

Comments
 (0)