Julia元编程初探——以简单符号求导为例
Julia语言具有强大的元编程机制,本文用Julia实现《SICP》中文第二版中第 99 页中的实例:符号求导,体验一下Julia元编程。
运行结果如下:
julia> include("deriv.jl") # 加载代码
multiplicand (generic function with 1 method)
julia> deriv(:(x + 3), :x) # 求表达式 x + 3 关于 x 的导数
1
julia> deriv(:(x * y), :x) #对表达式 x * y进行求导
:y
julia> deriv(:((x * y) * (x + 3)), :x) #对表达式 (x * y) * (x + 3)进行求导
:(x * y + y * (x + 3))
代码如下(deriv.jl):
1 function deriv(expr, var)
2 if isa(expr, Number)
3 return 0
4 elseif isa(expr, Symbol)
5 if is_same_variable(expr, var)
6 return 1
7 else
8 return 0
9 end
10 elseif is_sum(expr)
11 make_sum(deriv(addend(expr), var),
12 deriv(augend(expr), var))
13 elseif is_product(expr)
14 make_sum(make_product(multiplier(expr),
15 deriv(multiplicand(expr), var)),
16 make_product(deriv(multiplier(expr), var),
17 multiplicand(expr)))
18 else
19 println("unknown expression type -- DERIV", expr)
20 end
21 end
22
23
24 function is_variable(n)
25 return typeof(n) == Symbol
26 end
27
28 function is_same_variable(v1, v2)
29 return isa(v1, Symbol) && isa(v2, Symbol) && (v1 == v2)
30 end
31
32
33 # function make_sum(a1, a2)
34 # return Expr(:call, :+, a1, a2)
35 # end
36
37 # function make_product(m1, m2)
38 # return Expr(:call, :*, m1, m2)
39 # end
40
41 function make_sum(a1, a2)
42 if is_eq_number(a1, 0)
43 return a2
44 elseif is_eq_number(a2, 0)
45 return a1
46 elseif isa(a1, Number) && isa(a2, Number)
47 return a1 + a2
48 else
49 return Expr(:call, :+, a1, a2)
50 end
51 end
52
53 function make_product(m1, m2)
54 if is_eq_number(m1, 0) || is_eq_number(m2, 0)
55 return 0
56 elseif is_eq_number(m1, 1)
57 return m2
58 elseif is_eq_number(m2, 1)
59 return m1
60 elseif isa(m1, Number) && isa(m2, Number)
61 return m1 * m2
62 else
63 return Expr(:call, :*, m1, m2)
64 end
65 end
66
67 function is_eq_number(expr, num)
68 return isa(expr, Number) && (expr == num)
69 end
70
71 function is_sum(x)
72 return isa(x, Expr) && x.args[1] == :+
73 end
74
75 function addend(s)
76 return s.args[2]
77 end
78
79 function augend(s)
80 return s.args[3]
81 end
82
83 function is_product(x)
84 return isa(x, Expr) && x.args[1] == :*
85 end
86
87 function multiplier(p)
88 return p.args[2]
89 end
90
91 function multiplicand(p)
92 return p.args[3]
93 end