|
| 1 | +/- |
| 2 | +Copyright (c) 2019 Robert Y. Lewis. All rights reserved. |
| 3 | +Released under Apache 2.0 license as described in the file LICENSE. |
| 4 | +Authors: Mario Carneiro, Simon Hudon, Scott Morrison, Keeley Hoek, Robert Y. Lewis, Floris van Doorn, E.W.Ayers |
| 5 | +-/ |
| 6 | +import Lean |
| 7 | +import Lean.Meta |
| 8 | +import Mathlib.Util.TermUnsafe |
| 9 | +import Mathlib.Lean.Expr.Traverse |
| 10 | +import Mathlib.Util.MemoFix |
| 11 | +namespace Lean.Expr |
| 12 | +/-! |
| 13 | +# ReplaceRec |
| 14 | +
|
| 15 | +We define a more flexible version of `Expr.replace` where we can use recursive calls even when |
| 16 | +replacing a subexpression. We completely mimic the implementation of `Expr.replace`. -/ |
| 17 | + |
| 18 | +/-- A version of `Expr.replace` where the replacement function is available to the function `f?`. |
| 19 | +
|
| 20 | +`replaceRec f? e` will call `f? r e` where `r = replaceRec f?`. |
| 21 | +If `f? r e = none` then `r` will be called on each immediate subexpression of `e` and reassembled. |
| 22 | +If it is `some x`, traversal terminates and `x` is returned. |
| 23 | +If you wish to recursively replace things in the implementation of `f?`, you can apply `r`. |
| 24 | +
|
| 25 | +The function is also memoised, which means that if the |
| 26 | +same expression (by reference) is encountered the cached replacement is used. -/ |
| 27 | +def replaceRec (f? : (Expr → Expr) → Expr → Option Expr) : Expr → Expr := |
| 28 | + memoFix fun r e => |
| 29 | + match f? r e with |
| 30 | + | some x => x |
| 31 | + | none => traverseChildren (M := Id) r e |
| 32 | + |
| 33 | +/-- A version of `Expr.replace` where we can use recursive calls even if we replace a subexpression. |
| 34 | + When reaching a subexpression `e` we call `traversal e` to see if we want to do anything with this |
| 35 | + expression. If `traversal e = none` we proceed to the children of `e`. If |
| 36 | + `traversal e = some (#[e₁, ..., eₙ], g)`, we first recursively apply this function to |
| 37 | + `#[e₁, ..., eₙ]` to get new expressions `#[f₁, ..., fₙ]`. |
| 38 | + Then we replace `e` by `g [f₁, ..., fₙ]`. |
| 39 | +
|
| 40 | + Important: In order for this function to terminate, the `[e₁, ..., eₙ]` must all be smaller than |
| 41 | + `e` according to some measure (and this measure must also be strictly decreasing on the w.r.t. |
| 42 | + the structural subterm relation). |
| 43 | + -/ |
| 44 | +def replaceRecTraversal (traversal : Expr → Option (Array Expr × (Array Expr → Expr))) : Expr → Expr := |
| 45 | + replaceRec fun r e => |
| 46 | + match traversal e with |
| 47 | + | none => none |
| 48 | + | some (get, set) => some <| set <| .map r <| get |
| 49 | + |
| 50 | +end Lean.Expr |
0 commit comments