lean4-htt/src/Lean/HeadIndex.lean
JovanGerb c7c50a8bec
chore: fix linter errors (#4502)
The linters in Batteries can be used to spot mistakes in Lean. See the
message on
[Zulip](https://leanprover.zulipchat.com/#narrow/stream/270676-lean4/topic/Go-to-def.20on.20typeclass.20fields.20and.20type-dependent.20notation/near/442613564).
These are the different linters with errors:

- unusedArguments:
There are many unused instance arguments, especially a redundant `[Monad
m]` is very common
- checkUnivs:
There was a problem with universes in a definition in
`Init.Control.StateCps`. I fixed it by adding a `variable` statement for
the implicit arguments in the file.
- defLemma:
many proofs are written as `def` instead of `theorem`, most notably
`rfl`. Because `rfl` is used as a match pattern, it must be a def. Is
this desirable?
The keyword `abbrev` is sometimes used for an alias of a theorem, which
also results in a def. I would want to replace it with the `alias`
keyword to fix this, but it isn't available.
- dupNamespace:
I fixed some of these, but left `Tactic.Tactic` and `Parser.Parser` as
they are as these seem intended.
- unusedHaveSuffices:
  I cleaned up a few proofs with unused `have` or `suffices`
- explicitVarsOfIff:
  I didn't fix any of these, because that would be a breaking change.
- simpNF:
I didn't fix any of these, because I think that requires knowing the
intended simplification order.
2024-06-19 18:24:08 +00:00

111 lines
3.7 KiB
Text

/-
Copyright (c) 2020 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Author: Leonardo de Moura
-/
prelude
import Lean.Expr
namespace Lean
/--
Datastructure for representing the "head symbol" of an expression.
It is the key of `KExprMap`.
Examples:
- The head of `f a` is `.const f`
- The head of `let x := 1; f x` is `.const f`
- The head of `fun x => fun` is `.lam`
`HeadIndex` is a very simple index, and is used in situations where
we want to find definitionally equal terms, but we want to minimize
the search by checking only pairs of terms that have the same
`HeadIndex`.
-/
inductive HeadIndex where
| fvar (fvarId : FVarId)
| mvar (mvarId : MVarId)
| const (constName : Name)
| proj (structName : Name) (idx : Nat)
| lit (litVal : Literal)
| sort
| lam
| forallE
deriving Inhabited, BEq, Repr
/-- Hash code for a `HeadIndex` value. -/
protected def HeadIndex.hash : HeadIndex → UInt64
| fvar fvarId => mixHash 11 <| hash fvarId
| mvar mvarId => mixHash 13 <| hash mvarId
| const constName => mixHash 17 <| hash constName
| proj structName idx => mixHash 19 <| mixHash (hash structName) (hash idx)
| lit litVal => mixHash 23 <| hash litVal
| sort => 29
| lam => 31
| forallE => 37
instance : Hashable HeadIndex := ⟨HeadIndex.hash⟩
namespace Expr
/-- Return the number of arguments in the given expression with respect to its `HeadIndex` -/
def headNumArgs (e : Expr) : Nat :=
go e 0
where
go : Expr → Nat → Nat
| app f _, n => go f (n + 1)
| letE _ _ _ b _, n => go b n
| mdata _ e, n => go e n
| _, n => n
/--
Quick version that may fail if it "hits" a loose bound variable.
This can happen, for example, if the input expression is of the form.
```
let f := fun x => x + 1;
f 0
```
-/
private def toHeadIndexQuick? : Expr → Option HeadIndex
| mvar mvarId => HeadIndex.mvar mvarId
| fvar fvarId => HeadIndex.fvar fvarId
| const constName _ => HeadIndex.const constName
| proj structName idx _ => HeadIndex.proj structName idx
| sort _ => HeadIndex.sort
| lam .. => HeadIndex.lam
| forallE .. => HeadIndex.forallE
| lit v => HeadIndex.lit v
| app f _ => toHeadIndexQuick? f
| letE _ _ _ b _ => toHeadIndexQuick? b
| mdata _ e => toHeadIndexQuick? e
| _ => none
/--
Slower version of `toHeadIndexQuick?` that "expands" let-declarations to make
sure we never hit a loose bound variable.
The performance of the `letE` alternative can be improved, but this function should not be in the hotpath
since `toHeadIndexQuick?` succeeds most of the time.
-/
private partial def toHeadIndexSlow : Expr → HeadIndex
| mvar mvarId => HeadIndex.mvar mvarId
| fvar fvarId => HeadIndex.fvar fvarId
| const constName _ => HeadIndex.const constName
| proj structName idx _ => HeadIndex.proj structName idx
| sort _ => HeadIndex.sort
| lam .. => HeadIndex.lam
| forallE .. => HeadIndex.forallE
| lit v => HeadIndex.lit v
| app f _ => toHeadIndexSlow f
| letE _ _ v b _ => toHeadIndexSlow (b.instantiate1 v)
| mdata _ e => toHeadIndexSlow e
| _ => panic! "unexpected expression kind"
/--
Convert the given expression into a `HeadIndex`.
-/
def toHeadIndex (e : Expr) : HeadIndex :=
match toHeadIndexQuick? e with
| some i => i
| none => toHeadIndexSlow e
end Expr
end Lean