lean4-htt/src/Lean/Meta/WHNF.lean
2020-07-31 14:34:51 -07:00

179 lines
6.2 KiB
Text
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/-
Copyright (c) 2019 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Leonardo de Moura
-/
import Lean.AuxRecursor
import Lean.Util.WHNF
import Lean.Meta.Basic
import Lean.Meta.LevelDefEq
namespace Lean
namespace Meta
def isAuxDef? (constName : Name) : MetaM Bool := do
env ← getEnv; pure (isAuxRecursor env constName || isNoConfusion env constName)
def unfoldDefinition? (e : Expr) : MetaM (Option Expr) :=
Lean.WHNF.unfoldDefinitionAux getConstNoEx isAuxDef? whnf inferType isExprDefEq synthPending getLocalDecl getExprMVarAssignment? e
def whnfCore (e : Expr) : MetaM Expr :=
Lean.WHNF.whnfCore getConstNoEx isAuxDef? whnf inferType isExprDefEqAux getLocalDecl getExprMVarAssignment? e
unsafe def reduceNativeConst (α : Type) (typeName : Name) (constName : Name) : MetaM α := do
env ← getEnv;
match env.evalConstCheck α typeName constName with
| Except.error ex => throwOther ex
| Except.ok v => pure v
unsafe def reduceBoolNativeUnsafe (constName : Name) : MetaM Bool := reduceNativeConst Bool `Bool constName
unsafe def reduceNatNativeUnsafe (constName : Name) : MetaM Nat := reduceNativeConst Nat `Nat constName
@[implementedBy reduceBoolNativeUnsafe] constant reduceBoolNative (constName : Name) : MetaM Bool := arbitrary _
@[implementedBy reduceNatNativeUnsafe] constant reduceNatNative (constName : Name) : MetaM Nat := arbitrary _
def reduceNative? (e : Expr) : MetaM (Option Expr) :=
match e with
| Expr.app (Expr.const fName _ _) (Expr.const argName _ _) _ =>
if fName == `Lean.reduceBool then do
b ← reduceBoolNative argName;
pure $ toExpr b
else if fName == `Lean.reduceNat then do
n ← reduceNatNative argName;
pure $ toExpr n
else
pure none
| _ => pure none
@[inline] def withNatValue {α} (a : Expr) (k : Nat → MetaM (Option α)) : MetaM (Option α) := do
a ← whnf a;
match a with
| Expr.const `Nat.zero _ _ => k 0
| Expr.lit (Literal.natVal v) _ => k v
| _ => pure none
def reduceUnaryNatOp (f : Nat → Nat) (a : Expr) : MetaM (Option Expr) :=
withNatValue a $ fun a =>
pure $ mkNatLit $ f a
def reduceBinNatOp (f : Nat → Nat → Nat) (a b : Expr) : MetaM (Option Expr) :=
withNatValue a $ fun a =>
withNatValue b $ fun b => do
trace `Meta.isDefEq.whnf.reduceBinOp $ fun _ => toString a ++ " op " ++ toString b;
pure $ mkNatLit $ f a b
def reduceBinNatPred (f : Nat → Nat → Bool) (a b : Expr) : MetaM (Option Expr) := do
withNatValue a $ fun a =>
withNatValue b $ fun b =>
pure $ toExpr $ f a b
def reduceNat? (e : Expr) : MetaM (Option Expr) :=
if e.hasFVar || e.hasMVar then
pure none
else match e with
| Expr.app (Expr.const fn _ _) a _ =>
if fn == `Nat.succ then reduceUnaryNatOp Nat.succ a
else pure none
| Expr.app (Expr.app (Expr.const fn _ _) a1 _) a2 _ =>
if fn == `Nat.add then reduceBinNatOp Nat.add a1 a2
else if fn == `Nat.sub then reduceBinNatOp Nat.sub a1 a2
else if fn == `Nat.mul then reduceBinNatOp Nat.mul a1 a2
else if fn == `Nat.div then reduceBinNatOp Nat.div a1 a2
else if fn == `Nat.mod then reduceBinNatOp Nat.mod a1 a2
else if fn == `Nat.beq then reduceBinNatPred Nat.beq a1 a2
else if fn == `Nat.ble then reduceBinNatPred Nat.ble a1 a2
else pure none
| _ => pure none
@[inline] private def useWHNFCache (e : Expr) : MetaM Bool := do
-- We cache only closed terms
if e.hasFVar then pure false
else do
ctx ← read;
pure $ ctx.config.transparency != TransparencyMode.reducible
@[inline] private def cached? (useCache : Bool) (e : Expr) : MetaM (Option Expr) := do
if useCache then do
ctx ← read;
s ← get;
match ctx.config.transparency with
| TransparencyMode.default => pure $ s.cache.whnfDefault.find? e
| TransparencyMode.all => pure $ s.cache.whnfAll.find? e
| _ => unreachable!
else
pure none
private def cache (useCache : Bool) (e r : Expr) : MetaM Expr := do
ctx ← read;
when useCache $
match ctx.config.transparency with
| TransparencyMode.default => modify $ fun s => { s with cache := { s.cache with whnfDefault := s.cache.whnfDefault.insert e r } }
| TransparencyMode.all => modify $ fun s => { s with cache := { s.cache with whnfAll := s.cache.whnfAll.insert e r } }
| _ => unreachable!;
pure r
partial def whnfImpl : Expr → MetaM Expr
| e => Lean.WHNF.whnfEasyCases getLocalDecl getExprMVarAssignment? e $ fun e => do
useCache ← useWHNFCache e;
e? ← cached? useCache e;
match e? with
| some e' => pure e'
| none => do
e' ← whnfCore e;
v? ← reduceNat? e';
match v? with
| some v => cache useCache e v
| none => do
v? ← reduceNative? e';
match v? with
| some v => cache useCache e v
| none => do
e? ← unfoldDefinition? e';
match e? with
| some e => whnfImpl e
| none => cache useCache e e'
@[init] def setWHNFRef : IO Unit :=
whnfRef.set whnfImpl
/- Given an expression `e`, compute its WHNF and if the result is a constructor, return field #i. -/
def reduceProj? (e : Expr) (i : Nat) : MetaM (Option Expr) := do
env ← getEnv;
e ← whnf e;
match e.getAppFn with
| Expr.const name _ _ =>
match env.find? name with
| some (ConstantInfo.ctorInfo ctorVal) =>
let numArgs := e.getAppNumArgs;
let idx := ctorVal.nparams + i;
if idx < numArgs then
pure (some (e.getArg! idx))
else
pure none
| _ => pure none
| _ => pure none
@[specialize] private partial def whnfHeadPredAux (pred : Expr → MetaM Bool) : Expr → MetaM Expr
| e => Lean.WHNF.whnfEasyCases getLocalDecl getExprMVarAssignment? e $ fun e => do
e ← whnfCore e;
condM (pred e)
(do
e? ← unfoldDefinition? e;
match e? with
| some e => whnfHeadPredAux e
| none => pure e)
(pure e)
def whnfHeadPred (e : Expr) (pred : Expr → MetaM Bool) : MetaM Expr :=
whnfHeadPredAux pred e
def whnfUntil (e : Expr) (declName : Name) : MetaM (Option Expr) := do
e ← whnfHeadPredAux (fun e => pure $ !e.isAppOf declName) e;
if e.isAppOf declName then pure e
else pure none
def getStuckMVar? (e : Expr) : MetaM (Option MVarId) :=
WHNF.getStuckMVar? getConst whnf e
end Meta
end Lean