String splicing + parsing completely destroys/ignores any pre-existing
hierarchical structure. If you don't manually get the
precedence/parentheses right, it will completely break. For example:
julia> a, b = "x + y", "x - z";
julia> parse("$a * $b")
:((x + y * x) - z)
julia> a, b = :(x + y), :(x - z);
julia> :($a * $b)
:((x + y) * (x - z))
The more complex the expressions you're working with, the worse this gets.
Similarly If there are problems with how expressions are printed, you're
hosed – you'll stringify some expression, splice it, parse it and get total
nonsense back. If you just splice expression objects, it will just work and
do the right thing, even for expressions which have no possible string
representation.
On Thu, Apr 28, 2016 at 10:21 PM, Yichao Yu <[email protected]> wrote:
> On Thu, Apr 28, 2016 at 6:05 PM, Josh Langsfeld <[email protected]> wrote:
> > That's quite a strong statement to say never use parse. Could you
> explain? I
> > think manipulating strings is typically much easier than Expr objects.
>
> I don't believe that is true. String processing is slow, error prone
> and unsafe. Constructing a AST using splicing is more straightforward
> and more understandable than string splicing. Matching/processing an
> AST is also much easier than pattern matching and replacing in string.
> There's good reason AST processing are not done on strings directly.
>
> As an example, just compare the use of parse in the code provided.
> Note that strings are assumed to be replaced with symbols and
> expressions since that's what should be used for AST processing.
>
> parse("($(reduce((a,b)->"$a,$b",args)))->$f")
> vs
> :(($(args...))->$f)
>
> fun = reduce((a,b)->"$a + $b", dfun)
> parse("($(reduce((a,b)->"$a,$b",args)))->$fun")
> vs
> :(($(args...))->+($(dfun...)))
>
> >
> > On Thursday, April 28, 2016 at 8:38:27 AM UTC-4, Yichao Yu wrote:
> >>
> >>
> >> On Apr 28, 2016 7:15 AM, "Ben Lauwens" <[email protected]> wrote:
> >> >
> >> > Hi
> >> >
> >> > I like to create automatically functions that evaluates the total
> >> > derivative of a function with respect to time, eg.
> >> > given f(t, x1, x2) = t^2+x1*x2, I want to obtain
> >> > df/dt(t,x1,x2,dx1/dt,dx2/dt) = 2t+x1*dx2/dt+x2*dx1/dt,
> >> > d2f/dt2(t,x1,x2,dx1/dt,dx2/dt,d2x1/dt2,d2x2/dt) =
> >> > 2+2dx1/dt*dx2/dt+x1*d2x2/dt2+x2*d2x1/dt2, and so on.
> >> > The initial function is specified as a string as are the arguments.
> >> > The following code using the Calculus package works nicely:
> >> > using Calculus
> >> >
> >> > function total_derivatives_with_respect_to_time(f::AbstractString,
> >> > order::Int, names::AbstractString...)
> >> > derivs = Array(Function, order)
> >> > n = length(names)
> >> > args = AbstractString["t", names...]
> >> > derivs[1] = eval(parse("($(reduce((a,b)->"$a,$b",args)))->$f"))
> >> > if order > 1
> >> > fun = f
> >> > for o = 2:order
> >> > ∇fun = differentiate(fun, args)
> >> > dfun = AbstractString["$(∇fun[1])"]
> >> > for i = 1:n
> >> > push!(args, "d$(o-1)_$(names[i])")
> >> > end
> >> > for j = 2:(o-1)*n+1
> >> > push!(dfun, "($(∇fun[j])) * $(args[j+n])")
> >> > end
> >> > fun = reduce((a,b)->"$a + $b", dfun)
> >> > derivs[o] =
> eval(parse("($(reduce((a,b)->"$a,$b",args)))->$fun"))
> >> > end
> >> > end
> >> > return derivs
> >> > end
> >> >
> >> > derivs = total_derivatives_with_respect_to_time("t^2+x1*x2", 3, "x1",
> >> > "x2")
> >> > println(derivs[1](1.0, 2.0, 3.0))
> >> > println(derivs[2](1.0, 2.0, 3.0, 4.0, 5.0))
> >> > println(derivs[3](1.0, 2.0, 3.0, 4.0, 5.0, -1.0, -2.0))
> >>
> >> For calculating derivatives there may be better ways (forwarddiff and
> >> other packages). In general, generating functions with eval is fine as
> long
> >> as you dont do that in the performance critical part. However, you
> should
> >> never use parse and should construct the AST directly.
> >>
> >> > I have however the feeling that I am abusing the sequence of eval and
> >> > parse to automatically generate anonymous function. Is there a way to
> do
> >> > this more elegantly? Performance wise the code runs fine in Julia
> v0.5.
> >> >
> >> > Ben
>