/- Copyright (c) 2020 Microsoft Corporation. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Authors: Leonardo de Moura -/ import Lean.Expr import Lean.Util.MonadCache namespace Lean /- Remark: we cannot use the caching trick used at `FindExpr` and `ReplaceExpr` because they may visit the same expression multiple times if they are stored in different memory addresses. Note that the following code is parametric in a monad `m`. -/ variables {ω : Type} {m : Type → Type} [STWorld ω m] [MonadLiftT (ST ω) m] [Monad m] namespace ForEachExpr @[specialize] partial def visit (g : Expr → m Bool) (e : Expr) : MonadCacheT Expr Unit m Unit := checkCache e fun _ => do if (← g e) then match e with | Expr.forallE _ d b _ => do visit g d; visit g b | Expr.lam _ d b _ => do visit g d; visit g b | Expr.letE _ t v b _ => do visit g t; visit g v; visit g b | Expr.app f a _ => do visit g f; visit g a | Expr.mdata _ b _ => visit g b | Expr.proj _ _ b _ => visit g b | _ => pure () end ForEachExpr /-- Apply `f` to each sub-expression of `e`. If `f t` return true, then t's children are not visited. -/ @[inline] def Expr.forEach' (e : Expr) (f : Expr → m Bool) : m Unit := (ForEachExpr.visit f e).run @[inline] def Expr.forEach (e : Expr) (f : Expr → m Unit) : m Unit := e.forEach' fun e => do f e; pure true end Lean