# Substituting Expression for Symbol in Nested Expression

**URL:** <https://discourse.julialang.org/t/substituting-expression-for-symbol-in-nested-expression/36366>\
**Category:** General Usage\
**Tags:** metaprogramming, strings\
**Created:** [March 22, 2020, 9:44pm UTC](https://discourse.julialang.org/t/substituting-expression-for-symbol-in-nested-expression/36366 "2020-03-22T21:44:21Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![r-b0](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/r-b0/32/12927_2.png) [@r-b0](https://discourse.julialang.org/u/r-b0)\
**Post date:** [March 22, 2020, 9:44pm UTC](https://discourse.julialang.org/t/substituting-expression-for-symbol-in-nested-expression/36366/1 "2020-03-22T21:44:21Z")

</div>

Let’s suppose I have a situation which necessitates substituting an expression for a symbol in a nested expression. Let’s further suppose that I am unable to acomplish this by acting on the string before parsing using [string interpolation](https://en.wikibooks.org/wiki/Introducing_Julia/Strings_and_characters#String_interpolation)

To illustrate the end goal, it is desired to substitute the symbol `y` for `10*a`  
such that **expr\_old** becomes that shown in **expr\_new** as follows:

> expr\_old = :(3_x + (5_x +7_y^3)^2 + 4_z)  
> becomes  
> expr\_new = :(3_x + (5_x +7\*(10_a)^3)^2 + 4_z)

---

<div class="post-metadata">

**Author:** ![ffevotte](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ffevotte/32/6587_2.png) [@ffevotte](https://discourse.julialang.org/u/ffevotte)\
**Post date:** [March 22, 2020, 11:23pm UTC](https://discourse.julialang.org/t/substituting-expression-for-symbol-in-nested-expression/36366/2 "2020-03-22T23:23:01Z")

</div>

Maybe something like this?

```julia
# General case: do nothing (identity)
substitute(x, _) = x

# Symbol: substitute if necessary; otherwise, do nothing
function substitute(s::Symbol, pair)
    s == pair.first && return pair.second
    s
end

# Expression: recursively perform the substitution in all
# components of the expression
function substitute(e::Expr, pair)
    Expr(substitute(e.head, pair), substitute.(e.args, Ref(pair))...)
end

```

```julia
julia> expr_old = :(3x + (5x +7y^3)^2 + 4z)
:(3x + (5x + 7 * y ^ 3) ^ 2 + 4z)

julia> expr_new = substitute(expr_old, :y => :(10*a))
:(3x + (5x + 7 * (10a) ^ 3) ^ 2 + 4z)

```

  

* * *
  

**EDIT:** This can be simplified using [MacroTools](https://github.com/MikeInnes/MacroTools.jl):

```julia
using MacroTools

function substitute(e::Expr, pair)
    MacroTools.postwalk(e) do s
        s == pair.first && return pair.second
        s
    end
end

```

---

<div class="post-metadata">

**Author:** ![r-b0](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/r-b0/32/12927_2.png) [@r-b0](https://discourse.julialang.org/u/r-b0)\
**Post date:** [March 23, 2020, 12:39am UTC](https://discourse.julialang.org/t/substituting-expression-for-symbol-in-nested-expression/36366/3 "2020-03-23T00:39:20Z")

</div>

Brilliant. I tried recursive methods akin to your first approach, but was unable to get something that worked.

I appreciate both of these solutions being provided. I have learned something new studying each.

---

<div class="post-metadata">

**Author:** ![1ozturkbe](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/1ozturkbe/32/16461_2.png) [@1ozturkbe](https://discourse.julialang.org/u/1ozturkbe)\
**Post date:** [October 22, 2020, 11:25am UTC](https://discourse.julialang.org/t/substituting-expression-for-symbol-in-nested-expression/36366/4 "2020-10-22T11:25:05Z")

</div>

Thanks for this great thread. I dug it up, and realized really how versatile it is! I wanted to follow on to this with perhaps a more complicated example that is stumping me.

```julia
using MacroTools
function substitute(e::Expr, pair)
    MacroTools.postwalk(e) do s
        s == pair.first && return pair.second
        s
    end
end
ex = :(sum(x[i] for i=1:4) - y[1] * y[2] + z)
substitute(ex, :(x[2]) => 3) # doesn't work
substitute(ex, :(y[2]) => 1) # works
substitute(ex, :(z) => 1) # works
substitute(ex, :x => [1,2,3,4]) # works

```

Since the array substitution works, am I doing something syntactically wrong with the first :(x[2]) substitution? I would appreciate the help!

---

<div class="post-metadata">

**Author:** ![simeonschaub](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/simeonschaub/32/216566_2.png) [@simeonschaub](https://discourse.julialang.org/u/simeonschaub)\
**Post date:** [October 22, 2020, 12:24pm UTC](https://discourse.julialang.org/t/substituting-expression-for-symbol-in-nested-expression/36366/5 "2020-10-22T12:24:44Z")

</div>

What you need to keep in mind, is that expression matching doesn’t know anything about the values of identifiers, so since the literal expression `:(x[2])` never actually occurs in the expression `ex`, only `:(x[i])`, your first example can’t work. It is possible to achieve something like this using IRTools.jl and recursively stepping through the lowered code of functions instead of just walking an expression, but that’s unrelated to this thread. Feel free to open a new one though, if you have some specific problem in mind that you want to solve or have any further questions.

---

<div class="post-metadata">

**Author:** ![1ozturkbe](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/1ozturkbe/32/16461_2.png) [@1ozturkbe](https://discourse.julialang.org/u/1ozturkbe)\
**Post date:** [October 22, 2020, 12:55pm UTC](https://discourse.julialang.org/t/substituting-expression-for-symbol-in-nested-expression/36366/6 "2020-10-22T12:55:54Z")

</div>

Of course, now I feel pretty silly. I guess the workaround is to substitute for the entire array instead and/or to collect the generators in the expressions. Thanks @simeonschaub, and I will definitely create a new thread in the future.
