In [1]:
expr = :(x + 1)


Out[1]:
:(x + 1)

In [2]:
typeof(expr)


Out[2]:
Expr

In [3]:
expr |> dump


Expr 
  head: Symbol call
  args: Array(Any,(3,))
    1: Symbol +
    2: Symbol x
    3: Int64 1
  typ: Any

In [4]:
@doc Expr


Out[4]:

No documentation found.

Summary:

type Expr <: Any

Fields:

head :: Symbol
args :: Array{Any,1}
typ  :: Any

In [5]:
expr2 = Expr(:call, :+, 1, 1)


Out[5]:
:(1 + 1)

In [6]:
expr2 |> eval


Out[6]:
2

In [7]:
# Constant
differentiate(x::Number, target::Symbol) = 0


Out[7]:
differentiate (generic function with 1 method)

In [8]:
differentiate(5, :x)


Out[8]:
0

In [9]:
# Just one symbol
function differentiate(s::Symbol, target::Symbol)
    if s == target
        return 1
    else
        return 0
    end
end


Out[9]:
differentiate (generic function with 2 methods)

In [10]:
differentiate(:x, :x)


Out[10]:
1

In [11]:
differentiate(:y, :x)


Out[11]:
0

In [12]:
# Sum
function differentiate_sum(ex::Expr, target::Symbol)
    #@printf "diff[+]: %s\n" ex
    n = length(ex.args)
    new_args = Array(Any, n)
    new_args[1] = :+
    for i in 2:n
        # @printf "diff: %s\n" ex.args[i]
        new_args[i] = differentiate(ex.args[i], target)
    end
    return Expr(:call, new_args...)
end


Out[12]:
differentiate_sum (generic function with 1 method)

In [13]:
differentiate_sum(:(x + y), :x)


Out[13]:
:(1 + 0)

In [14]:
function differentiate_subtraction(ex::Expr, target::Symbol)
    #@printf "diff[-]: %s\n" ex
    n = length(ex.args)
    new_args = Array(Any, n)
    new_args[1] = :-
    for i in 2:n
        new_args[i] = differentiate(ex.args[i], target)
    end
    return Expr(:call, new_args...)
end


Out[14]:
differentiate_subtraction (generic function with 1 method)

In [15]:
differentiate_subtraction(:(x - y), :x)


Out[15]:
:(1 - 0)

In [16]:
function differentiate_product(ex::Expr, target::Symbol)
    #@printf "diff[*]: %s\n" ex
    n = length(ex.args)
    res_args = Array(Any, n)
    res_args[1] = :+
    for i in 2:n
       new_args = Array(Any, n)
       new_args[1] = :*
       for j in 2:n
           if j == i
               new_args[j] = differentiate(ex.args[j], target)
           else
               new_args[j] = ex.args[j]
           end
       end
    # @printf "*: %s" new_args
       res_args[i] = Expr(:call, new_args...)
    end
    return Expr(:call, res_args...)
end


Out[16]:
differentiate_product (generic function with 1 method)

In [17]:
differentiate_product(:(x * x), :x)


Out[17]:
:(1x + x * 1)

In [18]:
function differentiate_quotient(ex::Expr, target::Symbol)
    #@printf "diff[/]: %s\n" ex
    return Expr(:call,
                :/,
                Expr(:call,
                    :-,
                    Expr(:call,
                        :*,
                        differentiate(ex.args[2], target),
                        ex.args[3]
                    ),
                    Expr(:call,
                        :*,
                        ex.args[2],
                        differentiate(ex.args[3], target)
                    )
                ),
                Expr(:call,
                    :^,
                    ex.args[3],
                    2
                )
            )
end


Out[18]:
differentiate_quotient (generic function with 1 method)

In [19]:
differentiate_quotient(:(x / y), :y)


Out[19]:
:((0y - x * 1) / y ^ 2)

In [20]:
differentiate_lookup = Dict(
  :+ => differentiate_sum,
  :- => differentiate_subtraction,
  :* => differentiate_product,
  :/ => differentiate_quotient
)


Out[20]:
Dict{Symbol,Function} with 4 entries:
  :/ => differentiate_quotient
  :+ => differentiate_sum
  :* => differentiate_product
  :- => differentiate_subtraction

In [21]:
function differentiate(ex::Expr, target::Symbol)
    # @printf "differentiate(%s):\n" ex
    # dump(ex)
    if ex.head == :call
        if haskey(differentiate_lookup, ex.args[1])
            f = differentiate_lookup[ex.args[1]]
            @printf "%s(%s, %s)\n" f ex target
            ret = f(ex, target)
            @printf "=> %s\n" ret
            return ret
        else
            error("Don't know how to differentiate $(ex.args[1])")
        end
    else
        error("ex.head != :call")
        # return differentiate(ex.head)
    end
end


Out[21]:
differentiate (generic function with 3 methods)

In [22]:
differentiate(:(x * x), :x)


differentiate_product(x * x, x)
=> 1x + x * 1
Out[22]:
:(1x + x * 1)

In [23]:
differentiate(:((x + x) * x), :x)


differentiate_product((x + x) * x, x)
differentiate_sum(x + x, x)
=> 1 + 1
=> 13090930648x + (x + x) * 1
Out[23]:
:(13090930648x + (x + x) * 1)

In [24]:
differentiate(:(1 + x + x * x), :x)


differentiate_sum(1 + x + x * x, x)
differentiate_product(x * x, x)
=> 1x + x * 1
=> 0 + 1 + 13090930648
Out[24]:
:(0 + 1 + 13090930648)

In [25]:
differentiate(:(1 + z + x * z + x * z * z), :z)


differentiate_sum(1 + z + x * z + x * z * z, z)
differentiate_product(x * z, z)
=> 0z + x * 1
differentiate_product(x * z * z, z)
=> 0 * z * z + x * 1 * z + x * z * 1
=> 0 + 1 + 13090930648 + 13090930648
Out[25]:
:(0 + 1 + 13090930648 + 13090930648)

In [26]:
differentiate(:(1 + x + 1 / x + x * x), :x)


differentiate_sum(1 + x + 1 / x + x * x, x)
differentiate_quotient(1 / x, x)
=> (0x - 1 * 1) / x ^ 2
differentiate_product(x * x, x)
=> 1x + x * 1
=> 0 + 1 + 13090930648 + 13090930648
Out[26]:
:(0 + 1 + 13090930648 + 13090930648)

In [27]:
# Pkg.add("Calculus")

In [28]:
# import Calculus

In [29]:
repeat("_", 5)


Out[29]:
"_____"

In [36]:
ex = Expr(:call)


Out[36]:
:($(Expr(:call)))

In [37]:
ex.args = [:+, 1, 1]


Out[37]:
3-element Array{Any,1}:
  :+
 1  
 1  

In [38]:
ex.typ = Any


Out[38]:
Any

In [39]:
ex |> dump


Expr 
  head: Symbol call
  args: Array(Any,(3,))
    1: Symbol +
    2: Int64 1
    3: Int64 1
  typ: Any

In [51]:
arr1 = [:+, differentiate(:(x + x), :x)]
arr2 = [:+, differentiate(:(x - x), :x)]
arr3 = [:+, differentiate(:(x * x), :x)]
arr4 = [:+, differentiate(:(x / x), :x)]
ex5 = Expr(:call, arr1..., Expr(:call, arr2..., Expr(:call, arr3..., Expr(:call, arr4..., 5))))


differentiate_sum(x + x, x)
=> 1 + 1
differentiate_subtraction(x - x, x)
=> 1 - 1
differentiate_product(x * x, x)
=> 1x + x * 1
differentiate_quotient(x / x, x)
=> (1x - x * 1) / x ^ 2
Out[51]:
:((1 + 1) + ((1 - 1) + ((1x + x * 1) + ((1x - x * 1) / x ^ 2 + 5))))

In [52]:
differentiate(ex5, :x)


differentiate_sum((1 + 1) + ((1 - 1) + ((1x + x * 1) + ((1x - x * 1) / x ^ 2 + 5))), x)
differentiate_sum(1 + 1, x)
=> 0 + 0
differentiate_sum((1 - 1) + ((1x + x * 1) + ((1x - x * 1) / x ^ 2 + 5)), x)
differentiate_subtraction(1 - 1, x)
=> 0 - 0
differentiate_sum((1x + x * 1) + ((1x - x * 1) / x ^ 2 + 5), x)
differentiate_sum(1x + x * 1, x)
differentiate_product(1x, x)
=> 0x + 1 * 1
differentiate_product(x * 1, x)
=> 1 * 1 + x * 0
=> 13090930648 + 13090930648
differentiate_sum((1x - x * 1) / x ^ 2 + 5, x)
differentiate_quotient((1x - x * 1) / x ^ 2, x)
differentiate_subtraction(1x - x * 1, x)
differentiate_product(1x, x)
=> 0x + 1 * 1
differentiate_product(x * 1, x)
=> 1 * 1 + x * 0
=> 13090930648 - 13090930648
LoadError: Don't know how to differentiate ^
while loading In[52], in expression starting on line 1

 in error at /opt/homebrew-cask/Caskroom/julia/0.4.5/Julia-0.4.5.app/Contents/Resources/julia/lib/julia/sys.dylib
 in differentiate at In[21]:12
 in differentiate_quotient at In[18]:3
 in differentiate at In[21]:8
 in differentiate_sum at In[12]:9
 in differentiate at In[21]:8
 in differentiate_sum at In[12]:9
 in differentiate at In[21]:8
 in differentiate_sum at In[12]:9
 in differentiate at In[21]:8
 in differentiate_sum at In[12]:9
 in differentiate at In[21]:8

In [ ]: