Substitute symbols in expression

Is there any straight way or a function to substitute symbols in an expression?
For example:

ex = :(x + x^2 + x^3)
substitute(ex, :x => :y)   # yields :(y + y^2 + y^3)
substitute(ex, :x => 1.5)  # yields :(1.5 + 1.5^2 + 1.5^3)
1 Like
julia> function rep!(e, old, new)
           for (i,a) in enumerate(e.args)
               if a==old
                   e.args[i] = new
               elseif a isa Expr
                   rep!(a, old, new)
               end
               ## otherwise do nothing
           end
           e
       end
rep! (generic function with 1 method)

julia> rep!(:(x + x^2 + x^3), :x, :y)
:(y + y ^ 2 + y ^ 3)

julia> rep!(:(x + x^2 + x^3), :x, 1.5)
:(1.5 + 1.5 ^ 2 + 1.5 ^ 3)
1 Like

With the MacroTools package you can do

using MacroTools
ex = :(x + x^2 + x^3)
MacroTools.postwalk(ex -> ex == :x ? :y : ex, ex)
MacroTools.postwalk(ex -> ex == :x ? 1.5 : ex, ex)
4 Likes

This is how you could do it with my Reduce.jl package

julia> using Reduce
Reduce (Free CSL version, revision 4590), 11-May-18 ...

julia> ex = :(x+x^2+x^3)
:(x + x ^ 2 + x ^ 3)

julia> rcall(:(x=y)); rcall(ex)
:((y ^ 2 + y + 1) * y)

julia> rcall(:(x=1.5)); rcall(ex)
:(57 / 8)
1 Like

Alternatively, you can also use the Reduce.Algebra.sub method,

julia> using Reduce
Reduce (Free CSL version, revision 4590), 11-May-18 ...

julia> ex = :(x+x^2+x^3)
:(x + x ^ 2 + x ^ 3)

julia> Algebra.sub(:x=>:y,ex)
:((y ^ 2 + y + 1) * y)

julia> Algebra.sub(:x=>1.5,ex)
:(57 / 8)

which is closer to your original proposal and is probably better than my original example

2 Likes

Thanks all for the nice suggestions. I also found a native function:

Base.Cartesian.lreplace(:(x + x^2 + x^3), :x, 1)

but it does not work with float numbers.